diff --git a/.erb/configs/webpack.config.main.prod.ts b/.erb/configs/webpack.config.main.prod.ts
index d8ab5cd..214ccf9 100644
--- a/.erb/configs/webpack.config.main.prod.ts
+++ b/.erb/configs/webpack.config.main.prod.ts
@@ -56,7 +56,6 @@ const configuration: webpack.Configuration = {
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
- DEBUG_PROD: false,
START_MINIMIZED: false,
}),
diff --git a/.eslintrc.js b/.eslintrc.js
index f694bf2..f1a5ad7 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -28,6 +28,7 @@ module.exports = {
leadingUnderscore: 'allow',
},
],
+ 'prettier/prettier': 'off',
},
parserOptions: {
ecmaVersion: 2020,
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 05e3961..1b9e7bd 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -20,6 +20,8 @@ jobs:
node-version: 14
- name: Install Packages
run: npm install
+ - name: Add Rollbar
+ run: echo export default "'${{ secrets.rollbar_token }}'" > ./src/renderer/lib/rollbarAccessToken.ts
- name: Build and Test
run: npm run build && npm test
- name: Lint
diff --git a/assets/icon.icns b/assets/icon.icns
index 7a5b4f8..0ec58da 100644
Binary files a/assets/icon.icns and b/assets/icon.icns differ
diff --git a/package-lock.json b/package-lock.json
index e7c6102..253ebee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5 +1,5 @@
{
- "version": "0.0.5",
+ "version": "0.0.12",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1113,9 +1113,9 @@
}
},
"@codiga/components": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@codiga/components/-/components-1.1.0.tgz",
- "integrity": "sha512-KkzhYI4cBaaiMgK8vkaoa+OQCCYruBGwVTOV9R2ilzMp6bIGr8JR4aWUXcuOJOFFv+FRIrplLW6e9NRlH1dGAQ=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@codiga/components/-/components-1.3.0.tgz",
+ "integrity": "sha512-/qTPXcUVWkY30gSIw+wM8RLOTz8Bsyk+2B1CKJKXMAQtUAq4VOYgKkbZIdnlQOqnDIAV/mkSyFocK/UopeLtIw=="
},
"@cspotcode/source-map-support": {
"version": "0.8.1",
@@ -2081,6 +2081,14 @@
"tslib": "^2.1.0"
}
},
+ "@rollbar/react": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/@rollbar/react/-/react-0.11.1.tgz",
+ "integrity": "sha512-QwI8wPjX1xc/AuX39TSJx/tEtjmf8macRqYgX+R/uRh7Y3+4ilZX9OMwLg/4Je8+NN+9y7PFNKkQa9adn58d/g==",
+ "requires": {
+ "tiny-invariant": "^1.1.0"
+ }
+ },
"@sinclair/typebox": {
"version": "0.24.28",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz",
@@ -3658,8 +3666,7 @@
"async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
- "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
- "dev": true
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
"async-exit-hook": {
"version": "2.0.1",
@@ -3929,11 +3936,6 @@
"dev": true,
"optional": true
},
- "bootstrap": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
- "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q=="
- },
"boxen": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
@@ -4368,11 +4370,6 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
"dev": true
},
- "classnames": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
- "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
- },
"clean-css": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz",
@@ -4726,6 +4723,11 @@
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"dev": true
},
+ "console-polyfill": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/console-polyfill/-/console-polyfill-0.3.0.tgz",
+ "integrity": "sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ=="
+ },
"content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -5159,6 +5161,15 @@
"ms": "2.1.2"
}
},
+ "decache": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/decache/-/decache-3.1.0.tgz",
+ "integrity": "sha512-p7D6wJ5EJFFq1CcF2lu1XeqKFLBob8jRQGNAvFLTsV3CbSKBl3VtliAVlUIGz2i9H6kEFnI2Amaft5ZopIG2Fw==",
+ "optional": true,
+ "requires": {
+ "find": "^0.2.4"
+ }
+ },
"decimal.js": {
"version": "10.3.1",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
@@ -5195,7 +5206,8 @@
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true
},
"default-gateway": {
"version": "6.0.3",
@@ -5464,15 +5476,6 @@
"utila": "~0.4"
}
},
- "dom-helpers": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
- "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- }
- },
"dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
@@ -6234,7 +6237,6 @@
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz",
"integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==",
- "dev": true,
"requires": {
"stackframe": "^1.1.1"
}
@@ -7466,6 +7468,15 @@
}
}
},
+ "find": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/find/-/find-0.2.9.tgz",
+ "integrity": "sha512-7a4/LCiInB9xYMnAUEjLilL9FKclwbwK7VlXw+h5jMvT2TDFeYFCHM24O1XdnC/on/hx8mxVO3FTQkyHZnOghQ==",
+ "optional": true,
+ "requires": {
+ "traverse-chain": "~0.1.0"
+ }
+ },
"find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@@ -7528,15 +7539,6 @@
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"dev": true
},
- "frameless-titlebar": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/frameless-titlebar/-/frameless-titlebar-2.1.4.tgz",
- "integrity": "sha512-Wz7ZPOLpZNIQg5YxxI2lP6JVrGAolxKN/X85lTOFNpSEe5iJWAKMpYUviuFtc24/Ei8/rBRGkItgdhIFwer7lQ==",
- "requires": {
- "classnames": "^2.2.6",
- "deepmerge": "^4.2.2"
- }
- },
"framer-motion": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz",
@@ -8644,6 +8646,11 @@
"integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
"dev": true
},
+ "is_js": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz",
+ "integrity": "sha512-8Y5EHSH+TonfUHX2g3pMJljdbGavg55q4jmHzghJCdqYDbdNROC8uw/YFQwIRCRqRJT1EY3pJefz+kglw+o7sg=="
+ },
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -9591,9 +9598,7 @@
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json5": {
"version": "2.2.1",
@@ -11801,15 +11806,6 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
- "react-popper": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
- "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
- "requires": {
- "react-fast-compare": "^3.0.1",
- "warning": "^4.0.2"
- }
- },
"react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@@ -11900,30 +11896,6 @@
}
}
},
- "react-transition-group": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
- "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
- "requires": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
- }
- },
- "reactstrap": {
- "version": "9.1.3",
- "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.1.3.tgz",
- "integrity": "sha512-1bYd6JxdnSn5nvvGaimFIAm1EZx79fCJp490/07Mh9B/lwG3/U3hAVOeRKYtYhtaZPgnAIkwxX9sc6G5J9OKuA==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@popperjs/core": "^2.6.0",
- "classnames": "^2.2.3",
- "prop-types": "^15.5.8",
- "react-popper": "^2.2.4",
- "react-transition-group": "^4.4.2"
- }
- },
"read-config-file": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.2.0.tgz",
@@ -12121,6 +12093,14 @@
"strip-ansi": "^6.0.1"
}
},
+ "request-ip": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-2.0.2.tgz",
+ "integrity": "sha512-Y6LxqTmxLKKDk2I5tU2sxoCSKAnWJ42jmGqixNrH+oYoAyncpal7fFF5gqJ2bbgkRmb9qYNxdD6KFHfLS4dKBA==",
+ "requires": {
+ "is_js": "^0.9.0"
+ }
+ },
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -12243,6 +12223,33 @@
"sprintf-js": "^1.1.2"
}
},
+ "rollbar": {
+ "version": "2.25.1",
+ "resolved": "https://registry.npmjs.org/rollbar/-/rollbar-2.25.1.tgz",
+ "integrity": "sha512-xDUZqktjtnI/Vv530C5lQKPR8SR8tdlAs0/OeiyBNdfqnL/ngpTHmmrYhgFn4rpEXcs+OzYp3jLquaozBlaCgg==",
+ "requires": {
+ "async": "~3.2.3",
+ "console-polyfill": "0.3.0",
+ "decache": "^3.0.5",
+ "error-stack-parser": "^2.0.4",
+ "json-stringify-safe": "~5.0.0",
+ "lru-cache": "~2.2.1",
+ "request-ip": "~2.0.1",
+ "source-map": "^0.5.7"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
+ "integrity": "sha512-Q5pAgXs+WEAfoEdw2qKQhNFFhMoFMTYqRVKKUMnzuiR7oKFHS7fWo848cPcTKw+4j/IdN17NyzdhVKgabFV0EA=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
+ }
+ }
+ },
"run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -12829,8 +12836,7 @@
"stackframe": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz",
- "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==",
- "dev": true
+ "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg=="
},
"stat-mode": {
"version": "1.0.0",
@@ -13304,6 +13310,12 @@
"punycode": "^2.1.1"
}
},
+ "traverse-chain": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
+ "integrity": "sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg==",
+ "optional": true
+ },
"tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
diff --git a/package.json b/package.json
index 8526fd0..1e3d2a6 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"coding-assistant",
"codiga"
],
- "version": "0.0.5",
+ "version": "0.0.12",
"homepage": "https://www.codiga.io/",
"bugs": {
"url": "https://github.com/codiga/code-snippets-manager/issues"
@@ -100,19 +100,18 @@
"@apollo/client": "^3.6.9",
"@chakra-ui/icons": "^1.1.7",
"@chakra-ui/react": "^1.8.8",
- "@codiga/components": "^1.1.0",
+ "@codiga/components": "^1.3.0",
"@electron/remote": "^2.0.8",
"@emotion/react": "^11.10.0",
"@emotion/styled": "^11.10.0",
+ "@rollbar/react": "^0.11.1",
"apollo-link-debounce": "^3.0.0",
- "bootstrap": "^5.1.3",
"buffer": "^6.0.3",
"cross-fetch": "^3.1.5",
"electron-debug": "^3.2.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^5.2.1",
- "frameless-titlebar": "^2.1.4",
"framer-motion": "^6.5.1",
"graphql": "^16.6.0",
"path-browserify": "^1.0.1",
@@ -121,7 +120,7 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.34.2",
"react-router-dom": "^6.3.0",
- "reactstrap": "^9.1.3",
+ "rollbar": "^2.25.1",
"url": "^0.11.0"
},
"devDependencies": {
@@ -234,12 +233,7 @@
},
"win": {
"target": [
- {
- "target": "nsis"
- },
- {
- "target": "msi"
- }
+ "nsis"
],
"publisherName": "Xcoding Labs Inc.",
"signAndEditExecutable": true,
diff --git a/release/app/package-lock.json b/release/app/package-lock.json
index a21b76d..7a89f37 100644
--- a/release/app/package-lock.json
+++ b/release/app/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "codiga",
- "version": "0.0.5",
+ "version": "0.0.12",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/release/app/package.json b/release/app/package.json
index 76b7cc8..72fa9a8 100644
--- a/release/app/package.json
+++ b/release/app/package.json
@@ -1,6 +1,6 @@
{
"name": "codiga",
- "version": "0.0.5",
+ "version": "0.0.12",
"description": "Codiga Code Snippets Manager",
"license": "MIT",
"author": {
diff --git a/src/main/main.ts b/src/main/main.ts
index 95b6345..ba28e33 100644
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -31,6 +31,10 @@ ipcMain.on('ipc-example', async (event, arg) => {
event.reply('ipc-example', msgTemplate('pong'));
});
+ipcMain.on('app-version', async (event) => {
+ event.reply('app-version', app.getVersion());
+});
+
if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();
@@ -75,8 +79,8 @@ const createWindow = async () => {
frame: false,
width: 1024,
height: 728,
- minWidth: 600,
- minHeight: 300,
+ minWidth: 900,
+ minHeight: 600,
icon: getAssetPath('icon.png'),
webPreferences: {
sandbox: false,
@@ -123,6 +127,9 @@ const createWindow = async () => {
* Add event listeners...
*/
+// used for win32 desktop notifications - replaces `electron.app.${APP_NAME}` with Codiga.
+app.setAppUserModelId('Codiga');
+
app.on('window-all-closed', () => {
// Respect the OSX convention of having the application in memory even
// after all windows have been closed
diff --git a/src/main/preload.ts b/src/main/preload.ts
index ccdddf6..6c4609e 100644
--- a/src/main/preload.ts
+++ b/src/main/preload.ts
@@ -2,6 +2,7 @@ import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
export type Channels =
| 'ipc-example'
+ | 'app-version'
| 'minimizeApp'
| 'maximizeApp'
| 'closeApp';
diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index 19bf9a5..e947a55 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -1,7 +1,8 @@
import { ApolloProvider } from '@apollo/client';
-import { ChakraProvider } from '@chakra-ui/react';
+import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
import { theme } from '@codiga/components';
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
+import { Provider as RollbarProvider, ErrorBoundary } from '@rollbar/react';
// PAGES
import Home from './pages/Home';
@@ -11,6 +12,8 @@ import MyCookbooks from './pages/MyCookbooks';
import MySnippets from './pages/MySnippets';
import TeamCookbooks from './pages/TeamCookbooks';
import TeamSnippets from './pages/TeamSnippets';
+import ViewSnippet from './pages/ViewSnippet';
+import ViewCookbookSnippets from './pages/ViewCookbookSnippets';
// STYLES
import './styles/reboot.css';
@@ -19,58 +22,68 @@ import './styles/app.css';
// OTHER
import client from './graphql/client';
+import { rollbarConfig } from './lib/rollbar';
import Layout from './components/Layout';
import Filters from './components/Filters/Filters';
import { UserProvider } from './components/UserContext';
import { ThemeProvider } from './components/ThemeContext';
import { FiltersProvider } from './components/FiltersContext';
-import ViewSnippet from './pages/ViewSnippet';
-import ViewCookbookSnippets from './pages/ViewCookbookSnippets';
export default function App() {
return (
-
-
-
-
-
-
-
-
- }>
- } />
- } />
- }
- />
- } />
- }
- />
- } />
- }
- />
-
+
+
+
+
+
+
+
+
+
+
+
+ }>
+ } />
+ } />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+
- }
- />
- }
- />
-
-
-
-
-
-
-
-
+ }
+ />
+ }
+ />
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/renderer/components/AboutApp/AboutApp.tsx b/src/renderer/components/AboutApp/AboutApp.tsx
new file mode 100644
index 0000000..9cca87e
--- /dev/null
+++ b/src/renderer/components/AboutApp/AboutApp.tsx
@@ -0,0 +1,101 @@
+import { useEffect, useState } from 'react';
+import {
+ Modal,
+ ModalOverlay,
+ ModalContent,
+ ModalHeader,
+ ModalCloseButton,
+ ModalBody,
+ Text,
+ Link,
+ IconButton,
+ useDisclosure,
+ Image,
+} from '@chakra-ui/react';
+import { QuestionMarkCircleIcon } from '@codiga/components';
+import CodigaLogo from '../Layout/CodigaIcon.png';
+
+export default function AboutApp() {
+ const { isOpen, onOpen, onClose } = useDisclosure();
+ const [appVersion, setAppVersion] = useState('0.0.0');
+
+ useEffect(() => {
+ // eslint-disable-next-line no-alert
+ window.electron?.ipcRenderer.once('app-version', (arg) => {
+ setAppVersion(arg as string);
+ });
+ window.electron?.ipcRenderer.sendMessage('app-version', ['']);
+ }, []);
+
+ return (
+ <>
+ }
+ _focus={{
+ boxShadow: 'none',
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Codiga Code Snippets Manager
+
+
+
+
+
+ Version {appVersion}
+
+
+
+ Copyright © 2022 Codiga
+
+
+
+ >
+ );
+}
diff --git a/src/renderer/components/AboutApp/index.tsx b/src/renderer/components/AboutApp/index.tsx
new file mode 100644
index 0000000..5e7503e
--- /dev/null
+++ b/src/renderer/components/AboutApp/index.tsx
@@ -0,0 +1 @@
+export { default } from './AboutApp';
diff --git a/src/renderer/components/Code/Code.tsx b/src/renderer/components/Code/Code.tsx
index b045008..2c1f96e 100644
--- a/src/renderer/components/Code/Code.tsx
+++ b/src/renderer/components/Code/Code.tsx
@@ -9,7 +9,6 @@ import {
Tooltip,
Text,
Link,
- Box,
Menu,
MenuButton,
Portal,
@@ -67,169 +66,158 @@ export default function Code({ recipe }: CodeProps) {
const minWidth = lineMaxDigits < 3 ? '2.7em' : `${lineMaxDigits}.25em`;
return (
-
-
+
- setCodeView(value as CodeViewsType),
}}
- >
- span:first-child > .linenumber:first-child':
- {
- paddingTop: '0.5em !important',
- },
- 'code[class*="language-"] .linenumber': {
- border: '0 !important',
- background: 'transparent !important',
- fontStyle: 'normal !important',
- },
- }}
- >
-
- setCodeView(value as CodeViewsType),
- }}
- />
+ />
+
+
+ }
+ onClick={onCopy}
+ aria-label="Copy Snippet"
+ />
+
-
- }
- onClick={onCopy}
- aria-label="Copy Snippet"
- />
-
+
+
+
+
+ {commentsCount}
+
+
+ }
+ aria-label="Comment on Snippet"
+ />
+
-
-
+
+ •••
+
+
+
+
- }
- aria-label="Comment on Snippet"
- />
-
-
- {userId && recipe.owner && userId === recipe.owner.id && (
-
- )}
-
+ Edit Snippet
+
+
+
+
+
+ )}
+
-
- {code}
-
-
-
-
+
+ span:first-child > .linenumber:first-child':
+ {
+ paddingTop: '0.5em !important',
+ },
+ 'code[class*="language-"] .linenumber': {
+ border: '0 !important',
+ background: 'transparent !important',
+ fontStyle: 'normal !important',
+ },
+ }}
+ >
+
+ {code}
+
+
+
);
}
diff --git a/src/renderer/components/Favorite/FavoriteCookbook.tsx b/src/renderer/components/Favorite/FavoriteCookbook.tsx
index 81165a9..5a17f0d 100644
--- a/src/renderer/components/Favorite/FavoriteCookbook.tsx
+++ b/src/renderer/components/Favorite/FavoriteCookbook.tsx
@@ -1,5 +1,8 @@
import { useMutation } from '@apollo/client';
import { useToast } from '@codiga/components';
+import { useRollbar } from '@rollbar/react';
+import { LogArgument } from 'rollbar';
+
import useQueryVariables from '../../hooks/useQueryVariables';
import {
SUBSCRIBE_TO_COOKBOOK,
@@ -11,6 +14,7 @@ import {
GET_USER_SUBSCRIBED_COOKBOOKS,
} from '../../graphql/queries';
import Favorite, { FavoriteProps } from './Favorite';
+import { useUser } from '../UserContext';
type FavoriteCookbookProps = Pick & {
cookbookId: number;
@@ -21,6 +25,8 @@ export default function FavoriteCookbook({
cookbookId,
}: FavoriteCookbookProps) {
const toast = useToast();
+ const rollbar = useRollbar();
+ const { id: userId } = useUser();
const [favoriteCookbook] = useMutation(SUBSCRIBE_TO_COOKBOOK);
const [unfavoriteCookbook] = useMutation(UNSUBSCRIBE_TO_COOKBOOK);
@@ -56,6 +62,11 @@ export default function FavoriteCookbook({
refetchQueries,
});
} catch (err) {
+ rollbar.error('Error favoriting cookbook', err as LogArgument, {
+ cookbookId,
+ isSubscribed,
+ userId,
+ });
toast({
status: 'error',
description: 'An error occurred. Please try again.',
@@ -72,6 +83,11 @@ export default function FavoriteCookbook({
refetchQueries,
});
} catch (err) {
+ rollbar.error('Error unfavoriting cookbook', err as LogArgument, {
+ cookbookId,
+ isSubscribed,
+ userId,
+ });
toast({
status: 'error',
description: 'An error occurred. Please try again.',
diff --git a/src/renderer/components/Favorite/FavoriteSnippet.tsx b/src/renderer/components/Favorite/FavoriteSnippet.tsx
index 4f24ea4..cd8fbe2 100644
--- a/src/renderer/components/Favorite/FavoriteSnippet.tsx
+++ b/src/renderer/components/Favorite/FavoriteSnippet.tsx
@@ -1,5 +1,8 @@
import { useMutation } from '@apollo/client';
import { useToast } from '@codiga/components';
+import { useRollbar } from '@rollbar/react';
+import { LogArgument } from 'rollbar';
+
import useQueryVariables from '../../hooks/useQueryVariables';
import {
SUBSCRIBE_TO_RECIPE,
@@ -12,6 +15,7 @@ import {
GET_USER_SUBSCRIBED_RECIPES,
} from '../../graphql/queries';
import Favorite, { FavoriteProps } from './Favorite';
+import { useUser } from '../UserContext';
type FavoriteRecipeProps = Pick & {
recipeId: number;
@@ -22,6 +26,8 @@ export default function FavoriteSnippet({
recipeId,
}: FavoriteRecipeProps) {
const toast = useToast();
+ const rollbar = useRollbar();
+ const { id: userId } = useUser();
const [favoriteRecipe] = useMutation(SUBSCRIBE_TO_RECIPE);
const [unfavoriteRecipe] = useMutation(UNSUBSCRIBE_TO_RECIPE);
@@ -63,6 +69,11 @@ export default function FavoriteSnippet({
refetchQueries,
});
} catch (err) {
+ rollbar.error('Error favoriting snippet', err as LogArgument, {
+ recipeId,
+ isSubscribed,
+ userId,
+ });
toast({
status: 'error',
description: 'An error occurred. Please try again.',
@@ -79,6 +90,11 @@ export default function FavoriteSnippet({
refetchQueries,
});
} catch (err) {
+ rollbar.error('Error unfavoriting snippet', err as LogArgument, {
+ recipeId,
+ isSubscribed,
+ userId,
+ });
toast({
status: 'error',
description: 'An error occurred. Please try again.',
diff --git a/src/renderer/components/Layout/Titlebar.tsx b/src/renderer/components/Layout/Titlebar.tsx
index e9c683a..5507765 100644
--- a/src/renderer/components/Layout/Titlebar.tsx
+++ b/src/renderer/components/Layout/Titlebar.tsx
@@ -10,6 +10,7 @@ import { getAvatarUrl } from '../../utils/userUtils';
import TitlebarButtonsMac from './TitlebarButtonsMac';
import TitlebarButtonsWin from './TitlebarButtonsWin';
+import AboutApp from '../AboutApp';
type TitlebarProps = {
openLoginModal: () => void;
@@ -38,6 +39,8 @@ export default function Titlebar({ openLoginModal, isOnline }: TitlebarProps) {
{/* we show windows buttons, connecting text or CTA/Avatar here */}
+
+
{isOnline ? (
<>
;
@@ -14,24 +29,65 @@ export default function TitlebarActionsMac() {
ml="space_16"
sx={{ '-webkit-app-region': 'no-drag' }}
>
-
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
);
diff --git a/src/renderer/components/Login/Login.tsx b/src/renderer/components/Login/Login.tsx
index e6d00de..fb165c5 100644
--- a/src/renderer/components/Login/Login.tsx
+++ b/src/renderer/components/Login/Login.tsx
@@ -14,6 +14,8 @@ import {
import { TextField, useToast } from '@codiga/components';
import { useLazyQuery } from '@apollo/client';
import { useForm } from 'react-hook-form';
+import { useRollbar } from '@rollbar/react';
+import { LogArgument } from 'rollbar';
import { APP_URL, TOKEN } from '../../lib/config';
import { CHECK_USER } from '../../graphql/queries';
@@ -26,6 +28,7 @@ type LoginProps = {
export default function Login({ isOpen, closeModal }: LoginProps) {
const toast = useToast();
+ const rollbar = useRollbar();
const { setUser } = useUser();
const {
@@ -62,6 +65,7 @@ export default function Login({ isOpen, closeModal }: LoginProps) {
});
}
} catch (err) {
+ rollbar.error('Error logging in', err as LogArgument);
// network errors while fetching are placed here
toast({
status: 'error',
diff --git a/src/renderer/components/SnippetResults/SnippetResults.tsx b/src/renderer/components/SnippetResults/SnippetResults.tsx
index 69f5ed1..40eeb71 100644
--- a/src/renderer/components/SnippetResults/SnippetResults.tsx
+++ b/src/renderer/components/SnippetResults/SnippetResults.tsx
@@ -13,9 +13,15 @@ export default function SnippetResults({ results }: SnippetResultsProps) {
const query = useUrlQuery();
const currentSnippetId = query.get('currentSnippetId');
- const currentSnippet = currentSnippetId
+ // if we have a snippet id in the url, search for that first
+ let currentSnippet = currentSnippetId
? results.find((recipe) => String(recipe.id) === currentSnippetId)
- : results[0] || {};
+ : undefined;
+
+ // if we can't find the snippet from the url or it wasn't given, use the first result
+ if (!currentSnippet) {
+ currentSnippet = results[0] || {};
+ }
return (
diff --git a/src/renderer/components/ThemeContext/ThemeContext.tsx b/src/renderer/components/ThemeContext/ThemeContext.tsx
index 4085609..02a851f 100644
--- a/src/renderer/components/ThemeContext/ThemeContext.tsx
+++ b/src/renderer/components/ThemeContext/ThemeContext.tsx
@@ -1,22 +1,7 @@
import { useContext, createContext, ReactNode, useEffect } from 'react';
-import { useMutation, useQuery } from '@apollo/client';
import { useColorMode } from '@chakra-ui/react';
-import { useToast } from '@codiga/components';
-
-import { useUser } from '../UserContext';
-import { User } from '../../types/userTypes';
-import { GET_USER_PREFERENCES } from '../../graphql/queries';
-import {
- RemoveUserPreferenceData,
- RemoveUserPreferenceVariables,
- REMOVE_USER_PREFERENCE,
- UpdateUserPreferenceData,
- UpdateUserPreferenceVariables,
- UPDATE_USER_PREFERENCE,
-} from '../../graphql/mutations';
import useLocalStorage from '../../hooks/useLocalStorage';
import { CODIGA_THEME } from '../../lib/config';
-import { UserPreferenceKey } from '../../lib/constants';
enum Theme {
THEME_DARK = 'theme-dark',
@@ -29,16 +14,13 @@ type ThemeType = Theme.THEME_DARK | Theme.THEME_LIGHT;
type CacheStorageThemeType = (theme: ThemeType) => void;
type ThemeContextType = {
- changeToDarkTheme: () => Promise;
- changeToLightTheme: () => Promise;
+ changeToDarkTheme: () => void;
+ changeToLightTheme: () => void;
};
const ThemeContext = createContext({} as ThemeContextType);
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
- const toast = useToast();
- const { id: userId } = useUser();
-
// CHAKRA'S THEME
const { setColorMode } = useColorMode();
// USER'S LOCAL THEME PREFERENCE
@@ -47,25 +29,6 @@ export const ThemeProvider = ({ children }: { children: ReactNode }) => {
Theme.THEME_LIGHT
) as [ThemeType, CacheStorageThemeType, () => string];
- /**
- * If the user is logged in, we check if they have a saved theme preference.
- * If they do, we'll update Chakra and the local version
- */
- useQuery<{ user: Partial }>(GET_USER_PREFERENCES, {
- skip: !!userId,
- onCompleted: (respData) => {
- if (respData?.user?.preferences) {
- const savedTheme = respData.user.preferences
- .map((preference) => preference.key)
- .includes(UserPreferenceKey.Theme)
- ? Theme.THEME_DARK
- : Theme.THEME_LIGHT;
- cacheStorageTheme(savedTheme);
- setColorMode(savedTheme === Theme.THEME_DARK ? 'dark' : 'light');
- }
- },
- });
-
/**
* Because a user can access the app while not authenticated,
* we need to update the theme based on locally stored settings
@@ -76,57 +39,14 @@ export const ThemeProvider = ({ children }: { children: ReactNode }) => {
setColorMode(storedTheme === Theme.THEME_DARK ? 'dark' : 'light');
}, [cacheStorageTheme, hydrateValue, setColorMode]);
- // used to set a DARK theme
- const [removeUserPreference] = useMutation<
- RemoveUserPreferenceData,
- RemoveUserPreferenceVariables
- >(REMOVE_USER_PREFERENCE);
-
- // used to set a LIGHT theme
- const [updateUserPreference] = useMutation<
- UpdateUserPreferenceData,
- UpdateUserPreferenceVariables
- >(UPDATE_USER_PREFERENCE);
-
- const changeToDarkTheme = async () => {
+ const changeToDarkTheme = () => {
cacheStorageTheme(Theme.THEME_DARK);
setColorMode('dark');
- if (!userId) return;
- try {
- await updateUserPreference({
- variables: {
- key: UserPreferenceKey.Theme,
- value: Theme.THEME_DARK,
- },
- refetchQueries: [{ query: GET_USER_PREFERENCES }],
- });
- } catch (err) {
- toast({
- status: 'error',
- description:
- 'An error occurred while updating your theme. Please try again.',
- });
- }
};
- const changeToLightTheme = async () => {
+ const changeToLightTheme = () => {
cacheStorageTheme(Theme.THEME_LIGHT);
setColorMode('light');
- if (!userId) return;
- try {
- await removeUserPreference({
- variables: {
- key: UserPreferenceKey.Theme,
- },
- refetchQueries: [{ query: GET_USER_PREFERENCES }],
- });
- } catch (err) {
- toast({
- status: 'error',
- description:
- 'An error occurred while updating your theme. Please try again.',
- });
- }
};
const themeContext = {
diff --git a/src/renderer/components/Votes/Votes.tsx b/src/renderer/components/Votes/Votes.tsx
index 3e35fa7..277218e 100644
--- a/src/renderer/components/Votes/Votes.tsx
+++ b/src/renderer/components/Votes/Votes.tsx
@@ -3,6 +3,8 @@ import { useInView } from 'framer-motion';
import { useMutation, useQuery } from '@apollo/client';
import { Flex, FlexProps, IconButton, Text, Tooltip } from '@chakra-ui/react';
import { DownVoteIcon, UpVoteIcon, useToast } from '@codiga/components';
+import { LogArgument } from 'rollbar';
+import { useRollbar } from '@rollbar/react';
import { useUser } from '../UserContext';
import {
@@ -29,6 +31,7 @@ export default function Votes({
...props
}: VotesProps) {
const toast = useToast();
+ const rollbar = useRollbar();
const { id: userId } = useUser();
const ref = useRef(null);
@@ -65,6 +68,11 @@ export default function Votes({
description: 'Snippet upvoted',
});
} catch (err) {
+ rollbar.error('Error upvoting', err as LogArgument, {
+ userId,
+ entityId,
+ entityType,
+ });
toast({
status: 'error',
description: 'An error occured while upvoting. Please refresh.',
@@ -85,6 +93,11 @@ export default function Votes({
description: 'Snippet downvoted.',
});
} catch (err) {
+ rollbar.error('Error downvoting', err as LogArgument, {
+ userId,
+ entityId,
+ entityType,
+ });
toast({
status: 'error',
description: 'An error occured while downvoting. Please refresh.',
diff --git a/src/renderer/lib/constants.ts b/src/renderer/lib/constants.ts
index 2792938..c484474 100644
--- a/src/renderer/lib/constants.ts
+++ b/src/renderer/lib/constants.ts
@@ -8,11 +8,14 @@ export enum Language {
LANGUAGE_JSON = 'Json',
LANGUAGE_YAML = 'Yaml',
LANGUAGE_TYPESCRIPT = 'Typescript',
+ LANGUAGE_TWIG = 'Twig',
LANGUAGE_SWIFT = 'Swift',
LANGUAGE_SOLIDITY = 'Solidity',
LANGUAGE_SQL = 'Sql',
LANGUAGE_SHELL = 'Shell',
LANGUAGE_SCALA = 'Scala',
+ LANGUAGE_SCSS = 'Scss',
+ LANGUAGE_SASS = 'Sass',
LANGUAGE_REACT = 'React',
LANGUAGE_PASCAL = 'Pascal',
LANGUAGE_RUST = 'Rust',
@@ -20,6 +23,7 @@ export enum Language {
LANGUAGE_PHP = 'Php',
LANGUAGE_PYTHON = 'Python',
LANGUAGE_PERL = 'Perl',
+ LANGUAGE_MARKDOWN = 'Markdown',
LANGUAGE_KOTLIN = 'Kotlin',
LANGUAGE_JAVASCRIPT = 'Javascript',
LANGUAGE_JAVA = 'Java',
diff --git a/src/renderer/lib/rollbar.ts b/src/renderer/lib/rollbar.ts
new file mode 100644
index 0000000..ac7e219
--- /dev/null
+++ b/src/renderer/lib/rollbar.ts
@@ -0,0 +1,20 @@
+import rollbarAccessToken from './rollbarAccessToken';
+
+export const rollbarConfig = {
+ accessToken: rollbarAccessToken,
+ captureUncaught: true,
+ captureUnhandledRejections: true,
+ payload: { environment: process.env.NODE_ENV || 'development' },
+ autoInstrument: {
+ network: true,
+ networkResponseHeaders: true,
+ // networkResponseBody: true,
+ networkRequestBody: true,
+ log: true,
+ dom: true,
+ navigation: true,
+ connectivity: true,
+ contentSecurityPolicy: true,
+ errorOnContentSecurityPolicy: true,
+ },
+};
diff --git a/src/renderer/lib/rollbarAccessToken.ts b/src/renderer/lib/rollbarAccessToken.ts
new file mode 100644
index 0000000..f546b82
--- /dev/null
+++ b/src/renderer/lib/rollbarAccessToken.ts
@@ -0,0 +1 @@
+export default 'ROLLBAR_TOKEN';