From b677ab642960a5ba08aba996613eb28785b46ad6 Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Sun, 4 Dec 2022 22:03:07 -0500 Subject: [PATCH 1/9] feat: add react TS types --- frontend/package-lock.json | 107 ++++++++++--------------------------- frontend/package.json | 1 + 2 files changed, 28 insertions(+), 80 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7a560ad3f..7a8ed6702 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -50,13 +50,13 @@ "devDependencies": { "@tailwindcss/typography": "^0.5.4", "@types/node": "18.11.9", + "@types/react": "^18.0.26", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "autoprefixer": "^10.4.7", "eslint": "^8.29.0", "eslint-config-next": "^13.0.5", "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-simple-import-sort": "^8.0.0", "postcss": "^8.4.14", "prettier": "2.7.1", @@ -1143,9 +1143,9 @@ "optional": true }, "node_modules/@types/react": { - "version": "18.0.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", - "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", + "version": "18.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", + "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2901,27 +2901,6 @@ "semver": "bin/semver.js" } }, - "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-plugin-react": { "version": "7.31.11", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", @@ -3289,12 +3268,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -5624,18 +5597,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -7666,7 +7627,8 @@ "@headlessui/react": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz", - "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==" + "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==", + "requires": {} }, "@humanwhocodes/config-array": { "version": "0.11.7", @@ -8007,9 +7969,9 @@ "optional": true }, "@types/react": { - "version": "18.0.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", - "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", + "version": "18.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", + "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -8247,7 +8209,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-node": { "version": "1.8.2", @@ -8450,7 +8413,8 @@ "axios-auth-refresh": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz", - "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==" + "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==", + "requires": {} }, "axobject-query": { "version": "2.2.0", @@ -9400,15 +9364,6 @@ } } }, - "eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, "eslint-plugin-react": { "version": "7.31.11", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", @@ -9464,13 +9419,15 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true + "dev": true, + "requires": {} }, "eslint-plugin-simple-import-sort": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz", "integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==", - "dev": true + "dev": true, + "requires": {} }, "eslint-scope": { "version": "7.1.1", @@ -9583,12 +9540,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -11161,15 +11112,6 @@ "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -11441,7 +11383,8 @@ "react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", - "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==" + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", + "requires": {} }, "read-cache": { "version": "1.0.0", @@ -11482,7 +11425,8 @@ "redux-thunk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==" + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "requires": {} }, "regenerator-runtime": { "version": "0.13.11", @@ -11834,7 +11778,8 @@ "styled-jsx": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", - "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==" + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", + "requires": {} }, "stylis": { "version": "4.0.13", @@ -12197,12 +12142,14 @@ "use-memo-one": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", - "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==" + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "requires": {} }, "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} }, "util-deprecate": { "version": "1.0.2", diff --git a/frontend/package.json b/frontend/package.json index ebfdbfe3c..ab71c81bf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,6 +53,7 @@ "devDependencies": { "@tailwindcss/typography": "^0.5.4", "@types/node": "18.11.9", + "@types/react": "^18.0.26", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "autoprefixer": "^10.4.7", From 6ed5b9e706c7701423f2ea44758c919c1c31f8fa Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Tue, 6 Dec 2022 12:25:55 -0500 Subject: [PATCH 2/9] feat: create initial NotificationProvider component --- .../context/NotificationProvider.tsx | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 frontend/components/context/NotificationProvider.tsx diff --git a/frontend/components/context/NotificationProvider.tsx b/frontend/components/context/NotificationProvider.tsx new file mode 100644 index 000000000..98e24f5ab --- /dev/null +++ b/frontend/components/context/NotificationProvider.tsx @@ -0,0 +1,113 @@ +import { createContext, ReactNode, useContext, useState } from "react"; +import { faXmarkCircle } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import classnames from "classnames"; + +type NotificationType = "success" | "error"; +type Notification = { + text: string; + type: NotificationType; +}; + +type NotificationContextState = { + createNotification: (text: string, type?: NotificationType) => void; +}; +const NotificationContext = createContext({ + createNotification: () => console.log("createNotification not set!"), +}); + +export const useNotificationContext = () => useContext(NotificationContext); + +interface NotificationProviderProps { + children: ReactNode; +} + +interface NoticationsProps { + notifications: Notification[]; + clearNotification: (text?: string) => void; +} + +const Notifications = ({ + notifications, + clearNotification, +}: NoticationsProps) => { + return ( +
+
+ {notifications.map((notif) => ( +
+

{notif.text}

+ +
+ ))} +
+
+ ); +}; + +const NotificationProvider = ({ children }: NotificationProviderProps) => { + const [notifications, setNotifications] = useState([ + { + text: "Your secrets weren't saved, please fix the conflicts first.", + type: "error", + }, + { + text: "Testing", + type: "success", + }, + ]); + + const clearNotification = (text?: string) => { + if (text) { + return setNotifications((state) => + state.filter((notif) => notif.text !== text) + ); + } + + return setNotifications([]); + }; + + const createNotification = ( + text: string, + type: NotificationType = "success" + ) => { + const doesNotifExist = notifications.some((notif) => notif.text === text); + + if (doesNotifExist) { + return; + } + + return setNotifications((state) => [...state, { text, type }]); + }; + + return ( + + + {children} + + ); +}; + +export default NotificationProvider; From 389bf0b41f413ce5979fa9a7dbaca90a29a38b81 Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Tue, 6 Dec 2022 12:26:19 -0500 Subject: [PATCH 3/9] feat: add NotificationProvider to _app.tsx --- frontend/pages/_app.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/pages/_app.js b/frontend/pages/_app.js index 6ed9af013..8de838026 100644 --- a/frontend/pages/_app.js +++ b/frontend/pages/_app.js @@ -4,6 +4,7 @@ import { config } from "@fortawesome/fontawesome-svg-core"; import { initPostHog } from "~/components/analytics/posthog"; import Layout from "~/components/basic/layout"; +import NotificationProvider from "~/components/context/NotificationProvider"; import RouteGuard from "~/components/RouteGuard"; import { publicPaths } from "~/const"; import { ENV } from "~/utilities/config"; @@ -46,9 +47,11 @@ const App = ({ Component, pageProps, ...appProps }) => { return ( - - - + + + + + ); }; From 9499aa1097afad876f91548e345d285d9b68325e Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Tue, 6 Dec 2022 12:49:44 -0500 Subject: [PATCH 4/9] feat: move NotificationProvider into Notifications folder --- .../context/NotificationProvider.tsx | 113 ------------------ .../Notifications/NotificationProvider.tsx | 64 ++++++++++ 2 files changed, 64 insertions(+), 113 deletions(-) delete mode 100644 frontend/components/context/NotificationProvider.tsx create mode 100644 frontend/components/context/Notifications/NotificationProvider.tsx diff --git a/frontend/components/context/NotificationProvider.tsx b/frontend/components/context/NotificationProvider.tsx deleted file mode 100644 index 98e24f5ab..000000000 --- a/frontend/components/context/NotificationProvider.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { createContext, ReactNode, useContext, useState } from "react"; -import { faXmarkCircle } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import classnames from "classnames"; - -type NotificationType = "success" | "error"; -type Notification = { - text: string; - type: NotificationType; -}; - -type NotificationContextState = { - createNotification: (text: string, type?: NotificationType) => void; -}; -const NotificationContext = createContext({ - createNotification: () => console.log("createNotification not set!"), -}); - -export const useNotificationContext = () => useContext(NotificationContext); - -interface NotificationProviderProps { - children: ReactNode; -} - -interface NoticationsProps { - notifications: Notification[]; - clearNotification: (text?: string) => void; -} - -const Notifications = ({ - notifications, - clearNotification, -}: NoticationsProps) => { - return ( -
-
- {notifications.map((notif) => ( -
-

{notif.text}

- -
- ))} -
-
- ); -}; - -const NotificationProvider = ({ children }: NotificationProviderProps) => { - const [notifications, setNotifications] = useState([ - { - text: "Your secrets weren't saved, please fix the conflicts first.", - type: "error", - }, - { - text: "Testing", - type: "success", - }, - ]); - - const clearNotification = (text?: string) => { - if (text) { - return setNotifications((state) => - state.filter((notif) => notif.text !== text) - ); - } - - return setNotifications([]); - }; - - const createNotification = ( - text: string, - type: NotificationType = "success" - ) => { - const doesNotifExist = notifications.some((notif) => notif.text === text); - - if (doesNotifExist) { - return; - } - - return setNotifications((state) => [...state, { text, type }]); - }; - - return ( - - - {children} - - ); -}; - -export default NotificationProvider; diff --git a/frontend/components/context/Notifications/NotificationProvider.tsx b/frontend/components/context/Notifications/NotificationProvider.tsx new file mode 100644 index 000000000..723319615 --- /dev/null +++ b/frontend/components/context/Notifications/NotificationProvider.tsx @@ -0,0 +1,64 @@ +import { createContext, ReactNode, useContext, useState } from "react"; + +import Notifications from "./Notifications"; + +type NotificationType = "success" | "error"; + +export type Notification = { + text: string; + type: NotificationType; +}; + +type NotificationContextState = { + createNotification: ({ text, type }: Notification) => void; +}; + +const NotificationContext = createContext({ + createNotification: () => console.log("createNotification not set!"), +}); + +export const useNotificationContext = () => useContext(NotificationContext); + +interface NotificationProviderProps { + children: ReactNode; +} + +const NotificationProvider = ({ children }: NotificationProviderProps) => { + const [notifications, setNotifications] = useState([]); + + const clearNotification = (text?: string) => { + if (text) { + return setNotifications((state) => + state.filter((notif) => notif.text !== text) + ); + } + + return setNotifications([]); + }; + + const createNotification = ({ text, type = "success" }: Notification) => { + const doesNotifExist = notifications.some((notif) => notif.text === text); + + if (doesNotifExist) { + return; + } + + return setNotifications((state) => [...state, { text, type }]); + }; + + return ( + + + {children} + + ); +}; + +export default NotificationProvider; From 9071fafd06aee22e3b9056824f8728e50b718450 Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Tue, 6 Dec 2022 12:50:09 -0500 Subject: [PATCH 5/9] feat: fix import paths --- frontend/pages/_app.js | 2 +- frontend/pages/dashboard/[id].js | 106 ++++++++++++++++++++----------- 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/frontend/pages/_app.js b/frontend/pages/_app.js index 8de838026..907bbc941 100644 --- a/frontend/pages/_app.js +++ b/frontend/pages/_app.js @@ -4,7 +4,7 @@ import { config } from "@fortawesome/fontawesome-svg-core"; import { initPostHog } from "~/components/analytics/posthog"; import Layout from "~/components/basic/layout"; -import NotificationProvider from "~/components/context/NotificationProvider"; +import NotificationProvider from "~/components/context/Notifications/NotificationProvider"; import RouteGuard from "~/components/RouteGuard"; import { publicPaths } from "~/const"; import { ENV } from "~/utilities/config"; diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js index 42abf24db..b936f6e50 100644 --- a/frontend/pages/dashboard/[id].js +++ b/frontend/pages/dashboard/[id].js @@ -26,6 +26,7 @@ import { Menu, Transition } from "@headlessui/react"; import Button from "~/components/basic/buttons/Button"; import ListBox from "~/components/basic/Listbox"; import BottonRightPopup from "~/components/basic/popups/BottomRightPopup"; +import { useNotificationContext } from "~/components/context/Notifications/NotificationProvider"; import DashboardInputField from "~/components/dashboard/DashboardInputField"; import DropZone from "~/components/dashboard/DropZone"; import NavHeader from "~/components/navigation/NavHeader"; @@ -60,7 +61,7 @@ const KeyPair = ({ modifyValue, modifyVisibility, isBlurred, - duplicates + duplicates, }) => { const [randomStringLength, setRandomStringLength] = useState(32); @@ -227,6 +228,8 @@ export default function Dashboard() { const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false); const [hasUserEverPushed, setHasUserEverPushed] = useState(false); + const { createNotification } = useNotificationContext(); + // #TODO: fix save message for changing reroutes // const beforeRouteHandler = (url) => { // const warningText = @@ -370,46 +373,61 @@ export default function Dashboard() { ); // Checking if any of the secret keys start with a number - if so, don't do anything - const nameErrors = !Object.keys(obj).map(key => !isNaN(key.charAt(0))).every(v => v === false); - const duplicatesExist = data?.map(item => item[2]).filter((item, index) => index !== data?.map(item => item[2]).indexOf(item)).length > 0; + const nameErrors = !Object.keys(obj) + .map((key) => !isNaN(key.charAt(0))) + .every((v) => v === false); + const duplicatesExist = + data + ?.map((item) => item[2]) + .filter( + (item, index) => index !== data?.map((item) => item[2]).indexOf(item) + ).length > 0; if (nameErrors) { - console.log("Solve all name errors first!"); - } else if (duplicatesExist) { - console.log("Remove the duplicated entries first!"); - } else { - // Once "Save changed is clicked", disable that button - setButtonReady(false); - pushKeys(obj, router.query.id, env); - - /** - * Check which integrations are active for this project and environment - * If there are any, update environment variables for those integrations - */ - let integrations = await getWorkspaceIntegrations({ - workspaceId: router.query.id, - }); - integrations.map(async (integration) => { - if ( - envMapping[env] == integration.environment && - integration.isActive == true - ) { - let objIntegration = Object.assign( - {}, - ...data.map((row) => ({ [row[2]]: row[3] })) - ); - await pushKeysIntegration({ - obj: objIntegration, - integrationId: integration._id, - }); - } + return createNotification({ + text: "Solve all name errors first!", + type: "error", }); + } - // If this user has never saved environment variables before, show them a prompt to read docs - if (!hasUserEverPushed) { - setCheckDocsPopUpVisible(true); - await registerUserAction({ action: "first_time_secrets_pushed" }); + if (duplicatesExist) { + return createNotification({ + text: "Your secrets weren't saved; please fix the conflicts first.", + type: "error", + }); + } + + // Once "Save changed is clicked", disable that button + setButtonReady(false); + pushKeys(obj, router.query.id, env); + + /** + * Check which integrations are active for this project and environment + * If there are any, update environment variables for those integrations + */ + let integrations = await getWorkspaceIntegrations({ + workspaceId: router.query.id, + }); + integrations.map(async (integration) => { + if ( + envMapping[env] == integration.environment && + integration.isActive == true + ) { + let objIntegration = Object.assign( + {}, + ...data.map((row) => ({ [row[2]]: row[3] })) + ); + await pushKeysIntegration({ + obj: objIntegration, + integrationId: integration._id, + }); } + }); + + // If this user has never saved environment variables before, show them a prompt to read docs + if (!hasUserEverPushed) { + setCheckDocsPopUpVisible(true); + await registerUserAction({ action: "first_time_secrets_pushed" }); } }; @@ -649,7 +667,13 @@ export default function Dashboard() { modifyKey={listenChangeKey} modifyVisibility={listenChangeVisibility} isBlurred={blurred} - duplicates={data?.map(item => item[2]).filter((item, index) => index !== data?.map(item => item[2]).indexOf(item))} + duplicates={data + ?.map((item) => item[2]) + .filter( + (item, index) => + index !== + data?.map((item) => item[2]).indexOf(item) + )} /> ))} @@ -697,7 +721,13 @@ export default function Dashboard() { modifyKey={listenChangeKey} modifyVisibility={listenChangeVisibility} isBlurred={blurred} - duplicates={data?.map(item => item[2]).filter((item, index) => index !== data?.map(item => item[2]).indexOf(item))} + duplicates={data + ?.map((item) => item[2]) + .filter( + (item, index) => + index !== + data?.map((item) => item[2]).indexOf(item) + )} /> ))} From f60e0cf7ee32e9a8c7a6598df48a5065224de131 Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Tue, 6 Dec 2022 12:50:49 -0500 Subject: [PATCH 6/9] feat: separate components from Notification Provider --- .../context/Notifications/Notification.tsx | 38 +++++++++++++++++++ .../context/Notifications/Notifications.tsx | 28 ++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 frontend/components/context/Notifications/Notification.tsx create mode 100644 frontend/components/context/Notifications/Notifications.tsx diff --git a/frontend/components/context/Notifications/Notification.tsx b/frontend/components/context/Notifications/Notification.tsx new file mode 100644 index 000000000..974843cf6 --- /dev/null +++ b/frontend/components/context/Notifications/Notification.tsx @@ -0,0 +1,38 @@ +import { faXmarkCircle } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import classnames from "classnames"; + +import { Notification as NotificationType } from "./NotificationProvider"; + +interface NotificationProps { + notification: NotificationType; + clearNotification: (text?: string) => void; +} + +const Notification = ({ + notification, + clearNotification, +}: NotificationProps) => { + return ( +
+

{notification.text}

+ +
+ ); +}; + +export default Notification; diff --git a/frontend/components/context/Notifications/Notifications.tsx b/frontend/components/context/Notifications/Notifications.tsx new file mode 100644 index 000000000..856331e24 --- /dev/null +++ b/frontend/components/context/Notifications/Notifications.tsx @@ -0,0 +1,28 @@ +import Notification from "./Notification"; +import { Notification as NotificationType } from "./NotificationProvider"; + +interface NoticationsProps { + notifications: NotificationType[]; + clearNotification: (text?: string) => void; +} + +const Notifications = ({ + notifications, + clearNotification, +}: NoticationsProps) => { + return ( +
+
+ {notifications.map((notif) => ( + + ))} +
+
+ ); +}; + +export default Notifications; From 991b10cc1793137c1d32f2c1b0d3997ecb95b59e Mon Sep 17 00:00:00 2001 From: seunghyunOh Date: Wed, 7 Dec 2022 04:58:27 +0900 Subject: [PATCH 7/9] Convert JS to TS --- frontend/components/utilities/attemptLogin.js | 79 ++++++------------- .../utilities/saveTokenToLocalStorage.ts | 29 +++++++ frontend/pages/api/auth/Login1.js | 20 ----- frontend/pages/api/auth/Login1.ts | 32 ++++++++ frontend/pages/api/auth/Login2.js | 28 ------- frontend/pages/api/auth/Login2.ts | 36 +++++++++ 6 files changed, 123 insertions(+), 101 deletions(-) create mode 100644 frontend/components/utilities/saveTokenToLocalStorage.ts delete mode 100644 frontend/pages/api/auth/Login1.js create mode 100644 frontend/pages/api/auth/Login1.ts delete mode 100644 frontend/pages/api/auth/Login2.js create mode 100644 frontend/pages/api/auth/Login2.ts diff --git a/frontend/components/utilities/attemptLogin.js b/frontend/components/utilities/attemptLogin.js index 45cee1f94..7a8cbf96f 100644 --- a/frontend/components/utilities/attemptLogin.js +++ b/frontend/components/utilities/attemptLogin.js @@ -7,6 +7,7 @@ import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProj import { initPostHog } from "../analytics/posthog"; import pushKeys from "./secrets/pushKeys"; import { ENV } from "./config"; +import { saveTokenToLocalStorage } from "./saveTokenToLocalStorage"; import SecurityClient from "./SecurityClient"; const nacl = require("tweetnacl"); @@ -40,66 +41,38 @@ const attemptLogin = async ( async () => { const clientPublicKey = client.getPublicKey(); - let serverPublicKey, salt; - try { - let res = await login1(email, clientPublicKey); - res = await res.json(); - serverPublicKey = res.serverPublicKey; - salt = res.salt; - } catch (err) { - setErrorLogin(true); - console.log("Wrong password", err); - } + const { serverPublicKey, salt } = await login1(email, clientPublicKey); - let response; try { client.setSalt(salt); client.setServerPublicKey(serverPublicKey); const clientProof = client.getProof(); // called M1 - response = await login2(email, clientProof); - } catch (err) { - setErrorLogin(true); - console.log("Password verification failed"); - } - // if everything works, go the main dashboard page. - try { - if (response.status == "200") { - response = await response.json(); - SecurityClient.setToken(response["token"]); - const publicKey = response["publicKey"]; - const encryptedPrivateKey = response["encryptedPrivateKey"]; - const iv = response["iv"]; - const tag = response["tag"]; + // if everything works, go the main dashboard page. + const { token, publicKey, encryptedPrivateKey, iv, tag } = + await login2(email, clientProof); + SecurityClient.setToken(token); - const PRIVATE_KEY = Aes256Gcm.decrypt( - encryptedPrivateKey, - iv, - tag, - password - .slice(0, 32) - .padStart( - 32 + - (password.slice(0, 32).length - new Blob([password]).size), - "0" - ) - ); + const privateKey = Aes256Gcm.decrypt( + encryptedPrivateKey, + iv, + tag, + password + .slice(0, 32) + .padStart( + 32 + (password.slice(0, 32).length - new Blob([password]).size), + "0" + ) + ); - try { - localStorage.setItem("publicKey", publicKey); - localStorage.setItem("encryptedPrivateKey", encryptedPrivateKey); - localStorage.setItem("iv", iv); - localStorage.setItem("tag", tag); - localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY); - } catch (err) { - setErrorLogin(true); - console.error( - "Unable to send the tokens in local storage:" + err.message - ); - } - } else { - setErrorLogin(true); - } + saveTokenToLocalStorage({ + token, + publicKey, + encryptedPrivateKey, + iv, + tag, + privateKey, + }); const userOrgs = await getOrganizations(); const userOrgsData = userOrgs.map((org) => org._id); @@ -149,7 +122,7 @@ const attemptLogin = async ( STRIPE_SECRET_KEY: ["sk_test_7348oyho4hfq398HIUOH78", "shared"], }, workspaceId: projectToLogin, - env: "Development" + env: "Development", }); } try { diff --git a/frontend/components/utilities/saveTokenToLocalStorage.ts b/frontend/components/utilities/saveTokenToLocalStorage.ts new file mode 100644 index 000000000..13e50b2c4 --- /dev/null +++ b/frontend/components/utilities/saveTokenToLocalStorage.ts @@ -0,0 +1,29 @@ +interface Props { + publicKey: string; + encryptedPrivateKey: string; + iv: string; + tag: string; + privateTag: string; +} + +export const saveTokenToLocalStorage = ({ + publicKey, + encryptedPrivateKey, + iv, + tag, + privateTag, +}: Props) => { + try { + localStorage.setItem("publicKey", publicKey); + localStorage.setItem("encryptedPrivateKey", encryptedPrivateKey); + localStorage.setItem("iv", iv); + localStorage.setItem("tag", tag); + localStorage.setItem("PRIVATE_KEY", privateTag); + } catch (err) { + if (err instanceof Error) { + throw new Error( + "Unable to send the tokens in local storage:" + err.message + ); + } + } +}; diff --git a/frontend/pages/api/auth/Login1.js b/frontend/pages/api/auth/Login1.js deleted file mode 100644 index 3f3493f77..000000000 --- a/frontend/pages/api/auth/Login1.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This is the first step of the login process (pake) - * @param {*} email - * @param {*} clientPublicKey - * @returns - */ -const login1 = (email, clientPublicKey) => { - return fetch("/api/v1/auth/login1", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - clientPublicKey, - }), - }); -}; - -export default login1; diff --git a/frontend/pages/api/auth/Login1.ts b/frontend/pages/api/auth/Login1.ts new file mode 100644 index 000000000..818a2d157 --- /dev/null +++ b/frontend/pages/api/auth/Login1.ts @@ -0,0 +1,32 @@ +interface Login1 { + serverPublicKey: string; + salt: string; +} + +/** + * This is the first step of the login process (pake) + * @param {*} email + * @param {*} clientPublicKey + * @returns + */ +const login1 = async (email: string, clientPublicKey: string) => { + const response = await fetch("/api/v1/auth/login1", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: email, + clientPublicKey, + }), + }); + // need precise error handling about the status code + if (response?.status === 200) { + const data = (await response.json()) as unknown as Login1; + return data; + } + + throw new Error("Wrong password"); +}; + +export default login1; diff --git a/frontend/pages/api/auth/Login2.js b/frontend/pages/api/auth/Login2.js deleted file mode 100644 index 923e261df..000000000 --- a/frontend/pages/api/auth/Login2.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This is the second step of the login process - * @param {*} email - * @param {*} clientPublicKey - * @returns - */ -const login2 = (email, clientProof) => { - return fetch("/api/v1/auth/login2", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: email, - clientProof, - }), - credentials: "include", - }).then((res) => { - if (res.status == 200) { - console.log("User logged in", res); - return res; - } else { - console.log("Failed to log in"); - } - }); -}; - -export default login2; diff --git a/frontend/pages/api/auth/Login2.ts b/frontend/pages/api/auth/Login2.ts new file mode 100644 index 000000000..3adcb695f --- /dev/null +++ b/frontend/pages/api/auth/Login2.ts @@ -0,0 +1,36 @@ +interface Login2Response { + encryptedPrivateKey: string; + iv: string; + publicKey: string; + tag: string; + token: string; +} + +/** + * This is the second step of the login process + * @param {*} email + * @param {*} clientPublicKey + * @returns + */ +const login2 = async (email: string, clientProof: string) => { + const response = await fetch("/api/v1/auth/login2", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: email, + clientProof, + }), + credentials: "include", + }); + // need precise error handling about the status code + if (response.status == 200) { + const data = (await response.json()) as unknown as Login2Response; + return data; + } + + throw new Error("Password verification failed"); +}; + +export default login2; From d46bf54a8d1cf67bcaa3949438ddd004b2f2391d Mon Sep 17 00:00:00 2001 From: asharonbaltazar Date: Tue, 6 Dec 2022 21:07:40 -0500 Subject: [PATCH 8/9] fix: wrap pushKeys args in obj --- frontend/pages/dashboard/[id].js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js index b936f6e50..bec6849ad 100644 --- a/frontend/pages/dashboard/[id].js +++ b/frontend/pages/dashboard/[id].js @@ -399,7 +399,7 @@ export default function Dashboard() { // Once "Save changed is clicked", disable that button setButtonReady(false); - pushKeys(obj, router.query.id, env); + pushKeys({ obj, workspaceId: router.query.id, env }); /** * Check which integrations are active for this project and environment From 1310b176a9adbd7ac103d423ff526c47f81dd573 Mon Sep 17 00:00:00 2001 From: mv-turtle <78047717+mv-turtle@users.noreply.github.com> Date: Tue, 6 Dec 2022 21:23:28 -0500 Subject: [PATCH 9/9] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4215a9fa8..1b2d43c5f 100644 --- a/README.md +++ b/README.md @@ -48,11 +48,11 @@ And more. -## Get started +## 🚀 Get started To quickly get started, visit our [get started guide](https://infisical.com/docs/getting-started/introduction). -## What's cool about this? +## 🔥 What's cool about this? Infisical makes secret management simple and end-to-end encrypted by default. We're on a mission to make it more accessible to all developers, not just security teams. @@ -62,20 +62,20 @@ If you care about efficiency and security, then Infisical is right for you. We are currently working hard to make Infisical more extensive. Need any integrations or want a new feature? Feel free to [create an issue](https://github.com/Infisical/infisical/issues) or [contribute](https://infisical.com/docs/contributing/overview) directly to the repository. -## Contributing +## 🌱 Contributing Whether it's big or small, we love contributions ❤️ Check out our guide to see how to [get started](https://infisical.com/docs/contributing/overview). Not sure where to get started? [Book a free, non-pressure pairing sessions with one of our teammates](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)! -## Community & Support +## 💚 Community & Support - [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (For live discussion with the community and the Infisical team) - [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (For help with building and deeper conversations about features) - [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (For any bugs and errors you encounter using Infisical) - [Twitter](https://twitter.com/infisical) (Get news fast) -## Status +## 🐥 Status - [x] Public Alpha: Anyone can sign up over at [infisical.com](https://infisical.com) but go easy on us, there are kinks and we're just getting started. - [ ] Public Beta: Stable enough for most non-enterprise use-cases. @@ -83,13 +83,13 @@ Not sure where to get started? [Book a free, non-pressure pairing sessions with We're currently in Public Alpha. -## Stay Up-to-Date +## 🚨 Stay Up-to-Date Infisical officially launched as v.1.0 on November 21st, 2022. However, a lot of new features are coming very quickly. Watch **releases** of this repository to be notified about future updates: ![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) -## Integrations +## 🔌 Integrations We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :) @@ -261,15 +261,15 @@ We're currently setting the foundation and building [integrations](https://infis -## Open-source vs. paid +## 🏘 Open-source vs. paid This repo is entirely MIT licensed, with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license in the future. We're currently focused on developing non-enterprise offerings first that should suit most use-cases. -## Security +## 🛡 Security Looking to report a security vulnerability? Please don't post about it in GitHub issue. Instead, refer to our [SECURITY.md](./SECURITY.md) file. -## Contributors 🦸 +## 🦸 Contributors [//]: contributor-faces @@ -277,4 +277,4 @@ Looking to report a security vulnerability? Please don't post about it in GitHub - +