diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 1b80aa784..770fa7e83 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -6,6 +6,8 @@ jobs: docker: runs-on: ubuntu-latest steps: + - name: Checkout + uses: actions/checkout@v2 - name: Set up QEMU uses: docker/setup-qemu-action@v2 @@ -23,12 +25,13 @@ jobs: uses: docker/build-push-action@v3 with: push: true - context: /backend - tags: infisical/backend:latest + context: backend + tags: infisical/backend:test - name: Build and push frontend uses: docker/build-push-action@v3 with: push: true - context: /frontend - tags: infisical/frontend:latest + file: frontend/Dockerfile.dev + context: frontend + tags: infisical/frontend:test diff --git a/.github/workflows/helm-chart-release.yaml b/.github/workflows/helm-chart-release.yaml new file mode 100644 index 000000000..e3a3e32bc --- /dev/null +++ b/.github/workflows/helm-chart-release.yaml @@ -0,0 +1,33 @@ +name: Release Charts + +on: [workflow_dispatch] + +jobs: + release: + # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions + # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: v3.10.0 + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.4.1 + with: + charts_dir: helm-charts + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/README.md b/README.md index 6b1fc9436..4215a9fa8 100644 --- a/README.md +++ b/README.md @@ -54,15 +54,13 @@ To quickly get started, visit our [get started guide](https://infisical.com/docs ## What's cool about this? -Infisical is simple, E2EE, and (soon to be) complete. +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. According to a [report](https://www.ekransystem.com/en/blog/secrets-management) in 2019, only 10% of organizations use secret management solutions despite all using digital secrets to some extent. -We're on a mission to make secret management more accessible to everyone β€” that means building for developers, not just security teams. - If you care about efficiency and security, then Infisical is right for you. -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. +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 @@ -124,7 +122,7 @@ We're currently setting the foundation and building [integrations](https://infis - πŸ”œ Vercel + πŸ”œ Vercel (https://github.com/Infisical/infisical/issues/60) πŸ”œ GitLab CI/CD @@ -279,4 +277,4 @@ Looking to report a security vulnerability? Please don't post about it in GitHub - + diff --git a/cli/packages/cmd/root.go b/cli/packages/cmd/root.go index 826ccb4df..42d85e5b2 100644 --- a/cli/packages/cmd/root.go +++ b/cli/packages/cmd/root.go @@ -15,7 +15,7 @@ var rootCmd = &cobra.Command{ Short: "Infisical CLI is used to inject environment variables into any process", Long: `Infisical is a simple, end-to-end encrypted service that enables teams to sync and manage their environment variables across their development life cycle.`, CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, - Version: "0.1.5", + Version: "0.1.6", } // Execute adds all child commands to the root command and sets flags appropriately. diff --git a/docs/contributing/FAQ.mdx b/docs/contributing/FAQ.mdx new file mode 100644 index 000000000..be65f5ca7 --- /dev/null +++ b/docs/contributing/FAQ.mdx @@ -0,0 +1,16 @@ +--- +title: "Frequently Asked Questions" +description: "Have any questions? [Join our Slack community](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g)." +--- + +## Problem with SMTP + +You can normally populate `SMTP_USERNAME` and `SMTP_PASSWORD` with your usual login and password (you could also create a 'burner' email). Sometimes, there still are problems. + +You can go to your Gmail account settings > security and enable β€œless secure apps”. This would allow Infisical to use your Gmail to send emails. + +If it still doesn't work, [this](https://stackoverflow.com/questions/72547853/unable-to-send-email-in-c-sharp-less-secure-app-access-not-longer-available/72553362#72553362) should help. + +## `MONGO_URL` issues + +Your `MONGO_URL` should be something like `mongodb://root:example@mongo:27017/?authSource=admin`. If you want to change it (not recommended), you should make sure that you keep this URL in line with `MONGO_USERNAME=root` and `MONGO_PASSWORD=example`. \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json index 7d0317f0e..4ff49b5b9 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -162,7 +162,8 @@ "pages": [ "contributing/overview", "contributing/code-of-conduct", - "contributing/developing" + "contributing/developing", + "contributing/FAQ" ] } ], diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc similarity index 65% rename from frontend/.eslintrc.json rename to frontend/.eslintrc index 0c5504b90..b562aaa1f 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc @@ -1,10 +1,21 @@ { - "extends": "next/core-web-vitals", - "plugins": [ - "simple-import-sort" + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "next", + "next/core-web-vitals" ], + "parser": "@typescript-eslint/parser", + "plugins": ["simple-import-sort", "@typescript-eslint"], "rules": { "react-hooks/exhaustive-deps": "off", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "simple-import-sort/exports": "warn", "simple-import-sort/imports": [ "warn", @@ -18,15 +29,9 @@ "^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)" ], // Packages `react` related packages - [ - "^react", - "^next", - "^@?\\w" - ], + ["^react", "^next", "^@?\\w"], // Internal packages. - [ - "^~(/.*|$)" - ], + ["^~(/.*|$)"], // Relative imports [ "^\\.\\.(?!/?$)", @@ -36,11 +41,9 @@ "^\\./?$" ], // Style imports. - [ - "^.+\\.?(css|scss)$" - ] + ["^.+\\.?(css|scss)$"] ] } ] } -} \ No newline at end of file +} diff --git a/frontend/README.md b/frontend/README.md index b33ff4335..d97bb4bef 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,20 +1,22 @@ This is the client repository for Infisical. -## Before you get started with development locally +## Before you get started with development locally + Please ensure you have Docker and Docker Compose installed for your OS. -### Steps to start server +### Steps to start server + - `CD` into the repo - run command `docker-compose -f docker-compose.dev.yml up --build --force-recreate` -- Vist localhost:3000 and the website should be live +- Visit localhost:3000 and the website should be live + +### Steps to shutdown this Docker compose -### Steps to shutdown this Docker compose - `CD` into this repo -- run command `docker-compose -f docker-compose-dev.yml down` +- run command `docker-compose -f docker-compose.dev.yml down` ### Notes -Any changes made to local files in the `/components`, `/pages`, `styles` will be hot reloaded. If would like like to watch for other files or folders live, please add them to the docker volume. + +Any changes made to local files in the `/components`, `/pages`, `/styles` will be hot reloaded. If would like like to watch for other files or folders live, please add them to the docker volume. You will also need to ensure that a .env.local file exists with all required environment variables - - diff --git a/frontend/components/basic/buttons/Button.tsx b/frontend/components/basic/buttons/Button.tsx index 40251be93..5fe2db803 100644 --- a/frontend/components/basic/buttons/Button.tsx +++ b/frontend/components/basic/buttons/Button.tsx @@ -1,25 +1,28 @@ import React from "react"; import Image from "next/image"; import { IconProp } from "@fortawesome/fontawesome-svg-core"; -import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome"; +import { + FontAwesomeIcon, + FontAwesomeIconProps, +} from "@fortawesome/react-fontawesome"; -var classNames = require("classnames"); +const classNames = require("classnames"); type ButtonProps = { text: string; onButtonPressed: () => void; - loading: boolean; + loading?: boolean; color: string; size: string; - icon: IconProp; - active: boolean; - iconDisabled: string; - textDisabled: string; -} + icon?: IconProp; + active?: boolean; + iconDisabled?: string; + textDisabled?: string; +}; /** * This is the main butto component in the app. - * @param {object} props + * @param {object} props * @param {string} props.text - text inside the button * @param {function} props.onButtonPressed - the action that happens when the button is clicked * @param {boolean} props.loading - if a button is currently in the laoding state @@ -29,21 +32,28 @@ type ButtonProps = { * @param {boolean} props.active - if the button is active or disabled * @param {FontAwesomeIconProps} props.text - the icon inside the button when it is disabled * @param {string} props.textDisable - text inside the button when it is disabled - * @returns + * @returns */ -export default function Button (props: ButtonProps): JSX.Element { +export default function Button(props: ButtonProps): JSX.Element { // Check if the button show always be 'active' - then true; // or if it should switch between 'active' and 'disabled' - then give the status - const activityStatus = props.active || (props.text != "" && props.textDisabled == undefined) - - let styleButton = classNames( + const activityStatus = + props.active || (props.text != "" && props.textDisabled == undefined); + + const styleButton = classNames( "group m-auto md:m-0 inline-block rounded-md duration-200", // Setting background colors and hover modes - props.color == "mineshaft" && activityStatus && "bg-mineshaft-700 hover:bg-primary", + props.color == "mineshaft" && + activityStatus && + "bg-mineshaft-700 hover:bg-primary", props.color == "mineshaft" && !activityStatus && "bg-mineshaft", - (props.color == "primary" || !props.color) && activityStatus && "bg-primary hover:opacity-80", - (props.color == "primary" || !props.color) && !activityStatus && "bg-primary", + (props.color == "primary" || !props.color) && + activityStatus && + "bg-primary hover:opacity-80", + (props.color == "primary" || !props.color) && + !activityStatus && + "bg-primary", props.color == "red" && "bg-red", // Changing the opacity when active vs when not @@ -57,7 +67,7 @@ export default function Button (props: ButtonProps): JSX.Element { props.size == "icon-sm" && "h-9 w-9 flex items-center justify-center" ); - let styleMainDiv = classNames( + const styleMainDiv = classNames( "relative font-medium flex items-center", // Setting the text color for the text and icon @@ -69,11 +79,11 @@ export default function Button (props: ButtonProps): JSX.Element { props.size == "icon" && "flex items-center justify-center" ); - let textStyle = classNames( + const textStyle = classNames( "relative duration-200", // Show the loading sign if the loading indicator is on - props.loading == true ? "opacity-0" : "opacity-100", + props.loading ? "opacity-0" : "opacity-100", props.size == "md" && "text-sm", props.size == "lg" && "text-lg" ); @@ -100,7 +110,7 @@ export default function Button (props: ButtonProps): JSX.Element { {props.icon && ( )} {(props.text || props.textDisabled) && ( -

{activityStatus ? props.text : props.textDisabled}

+

+ {activityStatus ? props.text : props.textDisabled} +

)} diff --git a/frontend/components/basic/dialog/AddServiceTokenDialog.js b/frontend/components/basic/dialog/AddServiceTokenDialog.js index 8147253b5..7ff1789b8 100644 --- a/frontend/components/basic/dialog/AddServiceTokenDialog.js +++ b/frontend/components/basic/dialog/AddServiceTokenDialog.js @@ -37,7 +37,7 @@ const AddServiceTokenDialog = ({ const [serviceTokenCopied, setServiceTokenCopied] = useState(false); const generateServiceToken = async () => { - const latestFileKey = await getLatestFileKey(workspaceId); + const latestFileKey = await getLatestFileKey({ workspaceId }); const key = decryptAssymmetric({ ciphertext: latestFileKey.latestKey.encryptedKey, diff --git a/frontend/components/basic/layout.js b/frontend/components/basic/layout.js index 0a8cb3ebd..effe38942 100644 --- a/frontend/components/basic/layout.js +++ b/frontend/components/basic/layout.js @@ -3,8 +3,9 @@ import { useEffect, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { + faBookOpen, faGear, - faHouse, + faKey, faMobile, faPlug, faUser, @@ -18,6 +19,7 @@ import getOrganizationUsers from "~/pages/api/organization/GetOrgUsers"; import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace"; import createWorkspace from "~/pages/api/workspace/createWorkspace"; import getWorkspaces from "~/pages/api/workspace/getWorkspaces"; +import uploadKeys from "~/pages/api/workspace/uploadKeys"; import NavBarDashboard from "../navigation/NavBarDashboard"; import { @@ -54,10 +56,10 @@ export default function Layout({ children }) { const workspaces = await getWorkspaces(); const currentWorkspaces = workspaces.map((workspace) => workspace.name); if (!currentWorkspaces.includes(workspaceName)) { - const newWorkspace = await createWorkspace( + const newWorkspace = await createWorkspace({ workspaceName, - localStorage.getItem("orgData.id") - ); + organizationId: localStorage.getItem("orgData.id") + }); let newWorkspaceId; try { newWorkspaceId = newWorkspace._id; @@ -114,7 +116,7 @@ export default function Layout({ children }) { href: "/dashboard/" + workspaceMapping[workspaceSelected] + "?Development", title: "Secrets", - emoji: , + emoji: , }, { href: "/users/" + workspaceMapping[workspaceSelected], @@ -155,9 +157,7 @@ export default function Layout({ children }) { router.push("/noprojects"); } else if (router.asPath != "/noprojects") { const intendedWorkspaceId = router.asPath - .split("/") - [router.asPath.split("/").length - 1].split("?")[0]; - + .split("/")[router.asPath.split("/").length - 1].split("?")[0]; // If a user is not a member of a workspace they are trying to access, just push them to one of theirs if ( intendedWorkspaceId != "heroku" && @@ -178,9 +178,7 @@ export default function Layout({ children }) { userWorkspaces.map((workspace) => [workspace._id, workspace.name]) )[ router.asPath - .split("/") - [router.asPath.split("/").length - 1].split("?")[0] - ] + .split("/")[router.asPath.split("/").length - 1].split("?")[0]] ); } } @@ -192,12 +190,9 @@ export default function Layout({ children }) { workspaceMapping[workspaceSelected] && workspaceMapping[workspaceSelected] !== router.asPath - .split("/") - [router.asPath.split("/").length - 1].split("?")[0] + .split("/")[router.asPath.split("/").length - 1].split("?")[0] ) { - router.push( - "/dashboard/" + workspaceMapping[workspaceSelected] + "?Development" - ); + router.push("/dashboard/" + workspaceMapping[workspaceSelected] + "?Development"); localStorage.setItem( "projectData.id", workspaceMapping[workspaceSelected] @@ -214,66 +209,88 @@ export default function Layout({ children }) {
{ - let result = await getLatestFileKey(router.query.id); + let result = await getLatestFileKey({workspaceId: router.query.id}); const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); diff --git a/frontend/components/billing/Plan.js b/frontend/components/billing/Plan.js index f156cf76d..427469635 100644 --- a/frontend/components/billing/Plan.js +++ b/frontend/components/billing/Plan.js @@ -61,7 +61,7 @@ export default function Plan({ plan }) {
)} - +
{plan.buttonTextSecondary}
diff --git a/frontend/components/dashboard/DashboardInputField.js b/frontend/components/dashboard/DashboardInputField.tsx similarity index 58% rename from frontend/components/dashboard/DashboardInputField.js rename to frontend/components/dashboard/DashboardInputField.tsx index 634591c07..7a5b4a048 100644 --- a/frontend/components/dashboard/DashboardInputField.js +++ b/frontend/components/dashboard/DashboardInputField.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from "react"; +import React, { SyntheticEvent, useRef } from "react"; import { faCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,6 +6,15 @@ import guidGenerator from "../utilities/randomId"; const REGEX = /([$]{.*?})/g; +interface DashboardInputFieldProps { + index: number; + onChangeHandler: (value: string, index: number) => void; + value: string; + type: "varName" | "value"; + blurred: boolean; + duplicates: string[]; +} + /** * This component renders the input fields on the dashboard * @param {object} obj - the order number of a keyPair @@ -14,51 +23,60 @@ const REGEX = /([$]{.*?})/g; * @param {string} obj.type - whether the input field is for a Key Name or for a Key Value * @param {string} obj.value - value of the InputField * @param {boolean} obj.blurred - whether the input field should be blurred (behind the gray dots) or not; this can be turned on/off in the dashboard - * @param {string[]} obj.duplicates - list of all the suplicated key names on the dashboard + * @param {string[]} obj.duplicates - list of all the duplicated key names on the dashboard * @returns */ + const DashboardInputField = ({ index, onChangeHandler, type, value, blurred, - duplicates -}) => { - const ref = useRef(null); - const syncScroll = (e) => { - ref.current.scrollTop = e.target.scrollTop; - ref.current.scrollLeft = e.target.scrollLeft; + duplicates, +}: DashboardInputFieldProps) => { + const ref = useRef(null); + const syncScroll = (e: SyntheticEvent) => { + if (ref.current == null) return; + + ref.current.scrollTop = e.currentTarget.scrollTop; + ref.current.scrollLeft = e.currentTarget.scrollLeft; }; - + if (type === "varName") { - const startsWithNumber = !isNaN(value.charAt(0)) && value != ""; + const startsWithNumber = !isNaN(Number(value.charAt(0))) && value != ""; const hasDuplicates = duplicates?.includes(value); const error = startsWithNumber || hasDuplicates; return (
onChangeHandler(e.target.value.toUpperCase(), index)} + onChange={(e) => + onChangeHandler(e.target.value.toUpperCase(), index) + } type={type} value={value} - className={`asolute z-10 peer font-mono ph-no-capture bg-bunker-800 rounded-md caret-white text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 ${error ? "focus:ring-red/50" : "focus:ring-primary/50"} duration-200`} + className={`z-10 peer font-mono ph-no-capture bg-bunker-800 rounded-md caret-white text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 ${ + error ? "focus:ring-red/50" : "focus:ring-primary/50" + } duration-200`} spellCheck="false" />
- {startsWithNumber && + {startsWithNumber && (

Should not start with a number

- } - {hasDuplicates && !startsWithNumber && + )} + {hasDuplicates && !startsWithNumber && (

Secret names should be unique

- } + )}
); } else if (type === "value") { @@ -78,61 +96,61 @@ const DashboardInputField = ({ } z-10 peer font-mono ph-no-capture bg-transparent rounded-md caret-white text-transparent text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-200 no-scrollbar no-scrollbar::-webkit-scrollbar`} spellCheck="false" /> -
- { - value - .split(REGEX) - .map((word, id) => { - if (word.match(REGEX) !== null) { - return ( - - {word.slice(0, 2)} - - {word.slice(2, word.length - 1)} - - {word.slice(word.length - 1, word.length) == "}" ? ( - - {word.slice(word.length - 1, word.length)} - - ) : ( - - {word.slice(word.length - 1, word.length)} - - )} + {value.split(REGEX).map((word, id) => { + if (word.match(REGEX) !== null) { + return ( + + {word.slice(0, 2)} + + {word.slice(2, word.length - 1)} - ); - } else { - return {word}; - } - }) - } + {word.slice(word.length - 1, word.length) == "}" ? ( + + {word.slice(word.length - 1, word.length)} + + ) : ( + + {word.slice(word.length - 1, word.length)} + + )} + + ); + } else { + return ( + + {word} + + ); + } + })}
{blurred && (
- {value - .split("") - .map(() => ( - - ))} + {value.split("").map(() => ( + + ))}
- )} + )} ); } + + return <>Something Wrong; }; export default React.memo(DashboardInputField); diff --git a/frontend/components/dashboard/DropZone.js b/frontend/components/dashboard/DropZone.tsx similarity index 69% rename from frontend/components/dashboard/DropZone.js rename to frontend/components/dashboard/DropZone.tsx index 6171e682f..7519bca10 100644 --- a/frontend/components/dashboard/DropZone.js +++ b/frontend/components/dashboard/DropZone.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { type ChangeEvent, type DragEvent, useState } from "react"; import Image from "next/image"; import { faUpload } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -8,27 +8,37 @@ import Error from "../basic/Error"; import parse from "../utilities/file"; import guidGenerator from "../utilities/randomId"; +interface DropZoneProps { + // TODO: change Data type from any + setData: (data: any) => void; + setErrorDragAndDrop: (hasError: boolean) => void; + createNewFile: () => void; + errorDragAndDrop: boolean; + setButtonReady: (isReady: boolean) => void; + keysExist: boolean; + numCurrentRows: number; +} + const DropZone = ({ setData, setErrorDragAndDrop, createNewFile, errorDragAndDrop, - addPresetRow, setButtonReady, keysExist, numCurrentRows, -}) => { - const handleDragEnter = (e) => { +}: DropZoneProps) => { + const handleDragEnter = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); }; - const handleDragLeave = (e) => { + const handleDragLeave = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); }; - const handleDragOver = (e) => { + const handleDragOver = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -39,22 +49,25 @@ const DropZone = ({ const [loading, setLoading] = useState(false); // This function function immediately parses the file after it is dropped - const handleDrop = async (e) => { + const handleDrop = async (e: DragEvent) => { setLoading(true); setTimeout(() => setLoading(false), 5000); e.preventDefault(); e.stopPropagation(); e.dataTransfer.dropEffect = "copy"; - var file = e.dataTransfer.files[0], - reader = new FileReader(); - reader.onload = function (event) { - const keyPairs = parse(event.target.result); + const file = e.dataTransfer.files[0]; + const reader = new FileReader(); + + reader.onload = (event) => { + if (event.target === null || event.target.result === null) return; + // parse function's argument looks like to be ArrayBuffer + const keyPairs = parse(event.target.result as Buffer); const newData = Object.keys(keyPairs).map((key, index) => [ guidGenerator(), numCurrentRows + index, key, - keyPairs[key], + keyPairs[key as keyof typeof keyPairs], "shared", ]); setData(newData); @@ -72,23 +85,28 @@ const DropZone = ({ }; // This function is used when the user manually selects a file from the in-browser dircetory (not drag and drop) - const handleFileSelect = (e) => { + const handleFileSelect = (e: ChangeEvent) => { setLoading(true); setTimeout(() => setLoading(false), 5000); - var file = e.target.files[0], - reader = new FileReader(); - reader.onload = function (event) { - const newData = event.target.result - .split("\n") - .map((line, index) => [ - guidGenerator(), - numCurrentRows + index, - line.split("=")[0], - line.split("=").slice(1, line.split("=").length).join("="), - "shared", - ]); - setData(newData); - setButtonReady(true); + if (e.currentTarget.files === null) return; + const file = e.currentTarget.files[0]; + const reader = new FileReader(); + reader.onload = (event) => { + if (event.target === null || event.target.result === null) return; + const { result } = event.target; + if (typeof result === "string") { + const newData = result + .split("\n") + .map((line: string, index: number) => [ + guidGenerator(), + numCurrentRows + index, + line.split("=")[0], + line.split("=").slice(1, line.split("=").length).join("="), + "shared", + ]); + setData(newData); + setButtonReady(true); + } }; reader.readAsText(file); }; @@ -105,17 +123,17 @@ const DropZone = ({ ) : keysExist ? (
handleDragEnter(e)} - onDragOver={(e) => handleDragOver(e)} - onDragLeave={(e) => handleDragLeave(e)} - onDrop={(e) => handleDrop(e)} + onDragEnter={handleDragEnter} + onDragOver={handleDragOver} + onDragLeave={handleDragLeave} + onDrop={handleDrop} > handleFileSelect(e)} + onChange={handleFileSelect} /> {errorDragAndDrop ? (
@@ -142,10 +160,10 @@ const DropZone = ({ ) : (
handleDragEnter(e)} - onDragOver={(e) => handleDragOver(e)} - onDragLeave={(e) => handleDragLeave(e)} - onDrop={(e) => handleDrop(e)} + onDragEnter={handleDragEnter} + onDragOver={handleDragOver} + onDragLeave={handleDragLeave} + onDrop={handleDrop} >

Drag and drop your .env file here.

@@ -154,7 +172,7 @@ const DropZone = ({ type="file" className="opacity-0 absolute w-full h-full" accept=".txt,.env" - onChange={(e) => handleFileSelect(e)} + onChange={handleFileSelect} />
diff --git a/frontend/components/navigation/NavBarDashboard.js b/frontend/components/navigation/NavBarDashboard.tsx similarity index 91% rename from frontend/components/navigation/NavBarDashboard.js rename to frontend/components/navigation/NavBarDashboard.tsx index 80537dc1a..5a6d63b8e 100644 --- a/frontend/components/navigation/NavBarDashboard.js +++ b/frontend/components/navigation/NavBarDashboard.tsx @@ -47,27 +47,44 @@ const supportOptions = [ ], ]; -export default function Navbar({ onButtonPressed }) { - const router = useRouter(); - const [user, setUser] = useState({}); - const [orgs, setOrgs] = useState([]); - const [currentOrg, setCurrentOrg] = useState([]); +export interface ICurrentOrg { + name: string; +} - useEffect(async () => { - const userData = await getUser(); - setUser(userData); - const orgsData = await getOrganizations(); - setOrgs(orgsData); - const currentOrg = await getOrganization({ - orgId: localStorage.getItem("orgData.id"), - }); - setCurrentOrg(currentOrg); +export interface IUser { + firstName: string; + lastName: string; + email: string; +} + +/** + * This is the navigation bar in the main app. + * It has two main components: support options and user menu (inlcudes billing, logout, org/user settings) + * @returns NavBar + */ +export default function Navbar() { + const router = useRouter(); + const [user, setUser] = useState(); + const [orgs, setOrgs] = useState([]); + const [currentOrg, setCurrentOrg] = useState(); + + useEffect(() => { + (async () => { + const userData = await getUser(); + setUser(userData); + const orgsData = await getOrganizations(); + setOrgs(orgsData); + const currentOrg = await getOrganization({ + orgId: String(localStorage.getItem("orgData.id")), + }); + setCurrentOrg(currentOrg); + })(); }, []); const closeApp = async () => { console.log("Logging out..."); await logout(); - router.push("/"); + router.push("/login"); }; return ( @@ -108,7 +125,7 @@ export default function Navbar({ onButtonPressed }) { key={guidGenerator()} target="_blank" rel="noopener" - href={option[2]} + href={String(option[2])} className="font-normal text-gray-300 duration-200 rounded-md w-full flex items-center py-0.5" >
@@ -238,9 +255,9 @@ export default function Navbar({ onButtonPressed }) {
{orgs .filter( - (org) => org._id != localStorage.getItem("orgData.id") + (org : { _id: string }) => org._id != localStorage.getItem("orgData.id") ) - .map((org) => ( + .map((org : { _id: string; name: string; }) => (
{ diff --git a/frontend/components/navigation/NavHeader.js b/frontend/components/navigation/NavHeader.tsx similarity index 67% rename from frontend/components/navigation/NavHeader.js rename to frontend/components/navigation/NavHeader.tsx index 3f65a5aa6..3d64c2eda 100644 --- a/frontend/components/navigation/NavHeader.js +++ b/frontend/components/navigation/NavHeader.tsx @@ -1,29 +1,37 @@ import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; -import { faCcMastercard, faCcVisa } from "@fortawesome/free-brands-svg-icons"; import { faAngleRight, - faQuestionCircle, } from "@fortawesome/free-solid-svg-icons"; -import { faCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import getOrganization from "~/pages/api/organization/GetOrg"; -import getWorkspaceInfo from "~/pages/api/workspace/getWorkspaceInfo"; +import getProjectInfo from "~/pages/api/workspace/getProjectInfo"; -export default function NavHeader({ pageName, isProjectRelated }) { +/** + * This is the component at the top of almost every page. + * It shows how to navigate to a certain page. + * It future these links should also be clickable and hoverable + * @param obj + * @param obj.pageName - Name of the page + * @param obj.isProjectRelated - whether this page is related to project or now (determine if it's 2 or 3 navigation steps) + * @returns + */ +export default function NavHeader({ pageName, isProjectRelated } : { pageName: string; isProjectRelated: boolean; }): JSX.Element { const [orgName, setOrgName] = useState(""); const [workspaceName, setWorkspaceName] = useState(""); const router = useRouter(); useEffect(() => { (async () => { - let org = await getOrganization({ - orgId: localStorage.getItem("orgData.id"), + const orgId = localStorage.getItem("orgData.id") + const org = await getOrganization({ + orgId: orgId ? orgId : "", }); setOrgName(org.name); - let workspace = await getWorkspaceInfo({ - workspaceId: router.query.id, + + const workspace = await getProjectInfo({ + projectId: String(router.query.id), }); setWorkspaceName(workspace.name); })(); diff --git a/frontend/components/utilities/attemptLogin.js b/frontend/components/utilities/attemptLogin.js index 4e74a40ab..767fcb400 100644 --- a/frontend/components/utilities/attemptLogin.js +++ b/frontend/components/utilities/attemptLogin.js @@ -43,7 +43,7 @@ const attemptLogin = async ( let serverPublicKey, salt; try { - const res = await login1(email, clientPublicKey); + let res = await login1(email, clientPublicKey); res = await res.json(); serverPublicKey = res.serverPublicKey; salt = res.salt; @@ -137,7 +137,15 @@ const attemptLogin = async ( await pushKeys( { DATABASE_URL: [ - "mongodb+srv://this_is:an_example@mongodb.net", + "mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net", + "personal", + ], + DB_USERNAME: [ + "user1234", + "personal", + ], + DB_PASSWORD: [ + "ah8jak3hk8dhiu4dw7whxwe1l", "personal", ], TWILIO_AUTH_TOKEN: [ diff --git a/frontend/components/utilities/cryptography/changePassword.js b/frontend/components/utilities/cryptography/changePassword.js index 8bfaad674..de0fd9c3a 100644 --- a/frontend/components/utilities/cryptography/changePassword.js +++ b/frontend/components/utilities/cryptography/changePassword.js @@ -108,11 +108,7 @@ const changePassword = async ( } ); } catch (error) { - console.log( - "Something went wrong during changing the password", - slat, - serverPublicKey - ); + console.log("Something went wrong during changing the password"); } return true; }; diff --git a/frontend/components/utilities/secrets/pushKeys.js b/frontend/components/utilities/secrets/pushKeys.ts similarity index 69% rename from frontend/components/utilities/secrets/pushKeys.js rename to frontend/components/utilities/secrets/pushKeys.ts index fde5b45a4..0d570f273 100644 --- a/frontend/components/utilities/secrets/pushKeys.js +++ b/frontend/components/utilities/secrets/pushKeys.ts @@ -7,20 +7,30 @@ import { envMapping } from "../../../public/data/frequentConstants"; const crypto = require("crypto"); const { decryptAssymmetric, - decryptSymmetric, encryptSymmetric, encryptAssymmetric, } = require("../cryptography/crypto"); const nacl = require("tweetnacl"); nacl.util = require("tweetnacl-util"); +export interface IK { + publicKey: string; + userId: string; +} -const pushKeys = async (obj, workspaceId, env) => { - let sharedKey = await getLatestFileKey(workspaceId); +/** + * This function pushes the keys to the database after decrypting them end-to-end + * @param {object} obj + * @param {object} obj.obj - object with all the key pairs + * @param {object} obj.workspaceId - the id of a project to which a user is pushing + * @param {object} obj.env - which environment a user is pushing to + */ +const pushKeys = async({ obj, workspaceId, env }: { obj: object; workspaceId: string; env: string; }) => { + const sharedKey = await getLatestFileKey({ workspaceId }); const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); - let randomBytes; + let randomBytes: string; if (Object.keys(sharedKey).length > 0) { // case: a (shared) key exists for the workspace randomBytes = decryptAssymmetric({ @@ -51,11 +61,11 @@ const pushKeys = async (obj, workspaceId, env) => { iv: ivValue, tag: tagValue, } = encryptSymmetric({ - plaintext: obj[key][0], + plaintext: obj[key as keyof typeof obj][0], key: randomBytes, }); - const visibility = obj[key][1] != null ? obj[key][1] : "personal"; + const visibility = obj[key as keyof typeof obj][1] != null ? obj[key as keyof typeof obj][1] : "personal"; return { ciphertextKey, @@ -65,7 +75,7 @@ const pushKeys = async (obj, workspaceId, env) => { ciphertextValue, ivValue, tagValue, - hashValue: crypto.createHash("sha256").update(obj[key][0]).digest("hex"), + hashValue: crypto.createHash("sha256").update(obj[key as keyof typeof obj][0]).digest("hex"), type: visibility, }; }); @@ -76,7 +86,7 @@ const pushKeys = async (obj, workspaceId, env) => { }); // assymmetrically encrypt key with each receiver public keys - const keys = publicKeys.map((k) => { + const keys = publicKeys.map((k: IK) => { const { ciphertext, nonce } = encryptAssymmetric({ plaintext: randomBytes, publicKey: k.publicKey, @@ -95,7 +105,7 @@ const pushKeys = async (obj, workspaceId, env) => { workspaceId, secrets, keys, - environment: envMapping[env], + environment: envMapping[env as keyof typeof envMapping], }); }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ad2ecb75e..7a560ad3f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -50,9 +50,13 @@ "devDependencies": { "@tailwindcss/typography": "^0.5.4", "@types/node": "18.11.9", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", "autoprefixer": "^10.4.7", - "eslint": "^8.28.0", + "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", @@ -60,32 +64,6 @@ "typescript": "^4.9.3" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -97,77 +75,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/core/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", @@ -192,33 +99,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", @@ -261,25 +141,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "peer": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", @@ -288,18 +149,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", @@ -327,29 +176,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "peer": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -1264,6 +1090,12 @@ "hoist-non-react-statics": "^3.3.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1336,6 +1168,12 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "node_modules/@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -1351,15 +1189,71 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, - "node_modules/@typescript-eslint/parser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz", - "integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz", + "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.44.0", - "@typescript-eslint/types": "5.44.0", - "@typescript-eslint/typescript-estree": "5.44.0", + "@typescript-eslint/scope-manager": "5.45.0", + "@typescript-eslint/type-utils": "5.45.0", + "@typescript-eslint/utils": "5.45.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz", + "integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.45.0", + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/typescript-estree": "5.45.0", "debug": "^4.3.4" }, "engines": { @@ -1402,13 +1296,13 @@ "dev": true }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz", - "integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz", + "integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.44.0", - "@typescript-eslint/visitor-keys": "5.44.0" + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/visitor-keys": "5.45.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1418,10 +1312,60 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz", + "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.45.0", + "@typescript-eslint/utils": "5.45.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/@typescript-eslint/types": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz", - "integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz", + "integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1432,13 +1376,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", - "integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz", + "integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.44.0", - "@typescript-eslint/visitor-keys": "5.44.0", + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/visitor-keys": "5.45.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1481,13 +1425,61 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", - "integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==", + "node_modules/@typescript-eslint/utils": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz", + "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.44.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.45.0", + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/typescript-estree": "5.45.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz", + "integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.45.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1890,6 +1882,7 @@ "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2479,7 +2472,8 @@ "node_modules/electron-to-chromium": { "version": "1.4.206", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz", - "integrity": "sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==" + "integrity": "sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==", + "dev": true }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -2601,6 +2595,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } @@ -2614,9 +2609,9 @@ } }, "node_modules/eslint": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", - "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", @@ -2906,6 +2901,27 @@ "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", @@ -3273,6 +3289,12 @@ "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", @@ -3501,15 +3523,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-intrinsic": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", @@ -4240,18 +4253,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/jsonp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", @@ -5091,6 +5092,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/next": { "version": "12.3.1", "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", @@ -5146,7 +5153,8 @@ "node_modules/node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", @@ -5616,6 +5624,18 @@ "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", @@ -7022,6 +7042,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7227,28 +7248,6 @@ } }, "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "peer": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "peer": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -7257,58 +7256,6 @@ "@babel/highlight": "^7.18.6" } }, - "@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", - "peer": true - }, - "@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "peer": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true - } - } - }, "@babel/generator": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", @@ -7327,26 +7274,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "peer": true, - "requires": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true - } - } - }, "@babel/helper-environment-visitor": { "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", @@ -7377,36 +7304,11 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "peer": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, "@babel/helper-plugin-utils": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "peer": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, "@babel/helper-split-export-declaration": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", @@ -7425,23 +7327,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "peer": true - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "peer": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, "@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -7781,8 +7666,7 @@ "@headlessui/react": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz", - "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==", - "requires": {} + "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==" }, "@humanwhocodes/config-array": { "version": "0.11.7", @@ -8070,6 +7954,12 @@ "hoist-non-react-statics": "^3.3.0" } }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -8142,6 +8032,12 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -8157,15 +8053,49 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, - "@typescript-eslint/parser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz", - "integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==", + "@typescript-eslint/eslint-plugin": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz", + "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.44.0", - "@typescript-eslint/types": "5.44.0", - "@typescript-eslint/typescript-estree": "5.44.0", + "@typescript-eslint/scope-manager": "5.45.0", + "@typescript-eslint/type-utils": "5.45.0", + "@typescript-eslint/utils": "5.45.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz", + "integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.45.0", + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/typescript-estree": "5.45.0", "debug": "^4.3.4" }, "dependencies": { @@ -8187,29 +8117,58 @@ } }, "@typescript-eslint/scope-manager": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz", - "integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz", + "integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.44.0", - "@typescript-eslint/visitor-keys": "5.44.0" + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/visitor-keys": "5.45.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz", + "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.45.0", + "@typescript-eslint/utils": "5.45.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "@typescript-eslint/types": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz", - "integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz", + "integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", - "integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==", + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz", + "integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.44.0", - "@typescript-eslint/visitor-keys": "5.44.0", + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/visitor-keys": "5.45.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -8234,13 +8193,47 @@ } } }, - "@typescript-eslint/visitor-keys": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", - "integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==", + "@typescript-eslint/utils": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz", + "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.44.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.45.0", + "@typescript-eslint/types": "5.45.0", + "@typescript-eslint/typescript-estree": "5.45.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz", + "integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -8254,8 +8247,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-node": { "version": "1.8.2", @@ -8458,8 +8450,7 @@ "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==", - "requires": {} + "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==" }, "axobject-query": { "version": "2.2.0", @@ -8540,6 +8531,7 @@ "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "dev": true, "requires": { "caniuse-lite": "^1.0.30001370", "electron-to-chromium": "^1.4.202", @@ -8988,7 +8980,8 @@ "electron-to-chromium": { "version": "1.4.206", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz", - "integrity": "sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==" + "integrity": "sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==", + "dev": true }, "emoji-regex": { "version": "9.2.2", @@ -9089,7 +9082,8 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -9097,9 +9091,9 @@ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "eslint": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", - "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.3", @@ -9406,6 +9400,15 @@ } } }, + "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", @@ -9461,15 +9464,13 @@ "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, - "requires": {} + "dev": true }, "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, - "requires": {} + "dev": true }, "eslint-scope": { "version": "7.1.1", @@ -9582,6 +9583,12 @@ "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", @@ -9748,12 +9755,6 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true - }, "get-intrinsic": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", @@ -10268,12 +10269,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "peer": true - }, "jsonp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", @@ -10824,6 +10819,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "next": { "version": "12.3.1", "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", @@ -10853,7 +10854,8 @@ "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true }, "normalize-path": { "version": "3.0.0", @@ -11159,6 +11161,15 @@ "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", @@ -11430,8 +11441,7 @@ "react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", - "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", - "requires": {} + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==" }, "read-cache": { "version": "1.0.0", @@ -11472,8 +11482,7 @@ "redux-thunk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "requires": {} + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==" }, "regenerator-runtime": { "version": "0.13.11", @@ -11825,8 +11834,7 @@ "styled-jsx": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", - "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", - "requires": {} + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==" }, "stylis": { "version": "4.0.13", @@ -12171,6 +12179,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "dev": true, "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -12188,14 +12197,12 @@ "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==", - "requires": {} + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==" }, "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==", - "requires": {} + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" }, "util-deprecate": { "version": "1.0.2", diff --git a/frontend/package.json b/frontend/package.json index 7d6571da1..ebfdbfe3c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,9 +53,12 @@ "devDependencies": { "@tailwindcss/typography": "^0.5.4", "@types/node": "18.11.9", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", "autoprefixer": "^10.4.7", - "eslint": "^8.28.0", + "eslint": "^8.29.0", "eslint-config-next": "^13.0.5", + "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-simple-import-sort": "^8.0.0", "postcss": "^8.4.14", "prettier": "2.7.1", diff --git a/frontend/pages/api/auth/IssueBackupPrivateKey.js b/frontend/pages/api/auth/IssueBackupPrivateKey.js index 43e9f64ee..9a31f7b00 100644 --- a/frontend/pages/api/auth/IssueBackupPrivateKey.js +++ b/frontend/pages/api/auth/IssueBackupPrivateKey.js @@ -31,8 +31,8 @@ const issueBackupPrivateKey = ({ if (res.status == 200) { return res; } else { - return res; console.log("Failed to issue the backup key"); + return res; } }); }; diff --git a/frontend/pages/api/auth/Logout.js b/frontend/pages/api/auth/Logout.ts similarity index 89% rename from frontend/pages/api/auth/Logout.js rename to frontend/pages/api/auth/Logout.ts index 24c338a27..4dbcb7bca 100644 --- a/frontend/pages/api/auth/Logout.js +++ b/frontend/pages/api/auth/Logout.ts @@ -3,11 +3,8 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route logs the user out. Note: the user should authorized to do this. * We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry - * @param {*} req - * @param {*} res - * @returns */ -const logout = async (req, res) => { +const logout = async () => { return SecurityClient.fetchCall("/api/v1/auth/logout", { method: "POST", headers: { @@ -15,7 +12,7 @@ const logout = async (req, res) => { }, credentials: "include", }).then((res) => { - if (res.status == 200) { + if (res?.status == 200) { SecurityClient.setToken(""); // Delete the cookie by not setting a value; Alternatively clear the local storage localStorage.setItem("publicKey", ""); diff --git a/frontend/pages/api/organization/GetOrg.js b/frontend/pages/api/organization/GetOrg.ts similarity index 65% rename from frontend/pages/api/organization/GetOrg.js rename to frontend/pages/api/organization/GetOrg.ts index 74782a564..ecb07bd2d 100644 --- a/frontend/pages/api/organization/GetOrg.js +++ b/frontend/pages/api/organization/GetOrg.ts @@ -2,18 +2,17 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route lets us get info about a certain org - * @param {*} req - * @param {*} res + * @param {string} orgId - the organization ID * @returns */ -const getOrganization = (req, res) => { - return SecurityClient.fetchCall("/api/v1/organization/" + req.orgId, { +const getOrganization = ({ orgId }: { orgId: string; }) => { + return SecurityClient.fetchCall("/api/v1/organization/" + orgId, { method: "GET", headers: { "Content-Type": "application/json", }, }).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).organization; } else { console.log("Failed to get org info"); diff --git a/frontend/pages/api/organization/GetOrgUsers.js b/frontend/pages/api/organization/GetOrgUsers.ts similarity index 67% rename from frontend/pages/api/organization/GetOrgUsers.js rename to frontend/pages/api/organization/GetOrgUsers.ts index feeb60477..53b9518cf 100644 --- a/frontend/pages/api/organization/GetOrgUsers.js +++ b/frontend/pages/api/organization/GetOrgUsers.ts @@ -2,13 +2,13 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route lets us get all the users in an org. - * @param {*} req - * @param {*} res + * @param {object} obj + * @param {string} obj.orgId - organization Id * @returns */ -const getOrganizationUsers = (req, res) => { +const getOrganizationUsers = ({ orgId }: { orgId: string; }) => { return SecurityClient.fetchCall( - "/api/v1/organization/" + req.orgId + "/users", + "/api/v1/organization/" + orgId + "/users", { method: "GET", headers: { @@ -16,7 +16,7 @@ const getOrganizationUsers = (req, res) => { }, } ).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).users; } else { console.log("Failed to get org users"); diff --git a/frontend/pages/api/organization/getOrgs.js b/frontend/pages/api/organization/getOrgs.ts similarity index 81% rename from frontend/pages/api/organization/getOrgs.js rename to frontend/pages/api/organization/getOrgs.ts index 6720c22a9..cc655642f 100644 --- a/frontend/pages/api/organization/getOrgs.js +++ b/frontend/pages/api/organization/getOrgs.ts @@ -2,18 +2,16 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route lets us get the all the orgs of a certain user. - * @param {*} req - * @param {*} res * @returns */ -const getOrganizations = (req, res) => { +const getOrganizations = () => { return SecurityClient.fetchCall("/api/v1/organization", { method: "GET", headers: { "Content-Type": "application/json", }, }).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).organizations; } else { console.log("Failed to get orgs of a user"); diff --git a/frontend/pages/api/user/getUser.js b/frontend/pages/api/user/getUser.ts similarity index 79% rename from frontend/pages/api/user/getUser.js rename to frontend/pages/api/user/getUser.ts index 10ca0d5f8..4bfebc5fe 100644 --- a/frontend/pages/api/user/getUser.js +++ b/frontend/pages/api/user/getUser.ts @@ -2,18 +2,15 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route gets the information about a specific user. - * @param {*} req - * @param {*} res - * @returns */ -const getUser = (req, res) => { +const getUser = () => { return SecurityClient.fetchCall("/api/v1/user", { method: "GET", headers: { "Content-Type": "application/json", }, }).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).user; } else { console.log("Failed to get user info"); diff --git a/frontend/pages/api/workspace/createWorkspace.js b/frontend/pages/api/workspace/createWorkspace.ts similarity index 61% rename from frontend/pages/api/workspace/createWorkspace.js rename to frontend/pages/api/workspace/createWorkspace.ts index d5c44e2a6..0cedb0a57 100644 --- a/frontend/pages/api/workspace/createWorkspace.js +++ b/frontend/pages/api/workspace/createWorkspace.ts @@ -1,11 +1,12 @@ import SecurityClient from "~/utilities/SecurityClient"; /** - * This route creates a new workspace for a user. - * @param {*} workspaceName + * This route creates a new workspace for a user within a certain organization. + * @param {string} workspaceName - project Name + * @param {string} organizationId - org ID * @returns */ -const createWorkspace = (workspaceName, organizationId) => { +const createWorkspace = ( { workspaceName, organizationId }: { workspaceName: string; organizationId: string; }) => { return SecurityClient.fetchCall("/api/v1/workspace", { method: "POST", headers: { @@ -16,7 +17,7 @@ const createWorkspace = (workspaceName, organizationId) => { organizationId: organizationId, }), }).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).workspace; } else { console.log("Failed to create a project"); diff --git a/frontend/pages/api/workspace/getLatestFileKey.js b/frontend/pages/api/workspace/getLatestFileKey.ts similarity index 79% rename from frontend/pages/api/workspace/getLatestFileKey.js rename to frontend/pages/api/workspace/getLatestFileKey.ts index a5b14520a..86ecb7456 100644 --- a/frontend/pages/api/workspace/getLatestFileKey.js +++ b/frontend/pages/api/workspace/getLatestFileKey.ts @@ -2,10 +2,10 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * Get the latest key pairs from a certain workspace - * @param {*} workspaceId + * @param {string} workspaceId * @returns */ -const getLatestFileKey = (workspaceId) => { +const getLatestFileKey = ({ workspaceId } : { workspaceId: string; }) => { return SecurityClient.fetchCall( "/api/v1/key/" + workspaceId + "/latest", { @@ -15,7 +15,7 @@ const getLatestFileKey = (workspaceId) => { }, } ).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return await res.json(); } else { console.log("Failed to get the latest key pairs for a certain project"); diff --git a/frontend/pages/api/workspace/getWorkspaceInfo.js b/frontend/pages/api/workspace/getProjectInfo.ts similarity index 62% rename from frontend/pages/api/workspace/getWorkspaceInfo.js rename to frontend/pages/api/workspace/getProjectInfo.ts index 4266dbbaa..c6eef9dce 100644 --- a/frontend/pages/api/workspace/getWorkspaceInfo.js +++ b/frontend/pages/api/workspace/getProjectInfo.ts @@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route lets us get the information of a certain project. - * @param {*} req - * @param {*} res + * @param {*} projectId - project ID (we renamed workspaces to projects in the app) * @returns */ -const getWorkspaceInfo = (req, res) => { +const getProjectInfo = ({ projectId }: { projectId: string; }) => { return SecurityClient.fetchCall( - "/api/v1/workspace/" + req.workspaceId, + "/api/v1/workspace/" + projectId, { method: "GET", headers: { @@ -16,7 +15,7 @@ const getWorkspaceInfo = (req, res) => { }, } ).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).workspace; } else { console.log("Failed to get project info"); @@ -24,4 +23,4 @@ const getWorkspaceInfo = (req, res) => { }); }; -export default getWorkspaceInfo; +export default getProjectInfo; diff --git a/frontend/pages/api/workspace/getWorkspaceKeys.js b/frontend/pages/api/workspace/getWorkspaceKeys.ts similarity index 73% rename from frontend/pages/api/workspace/getWorkspaceKeys.js rename to frontend/pages/api/workspace/getWorkspaceKeys.ts index 368d00fa0..09b468662 100644 --- a/frontend/pages/api/workspace/getWorkspaceKeys.js +++ b/frontend/pages/api/workspace/getWorkspaceKeys.ts @@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route lets us get the public keys of everyone in your workspace. - * @param {*} req - * @param {*} res + * @param {string} workspaceId * @returns */ -const getWorkspaceKeys = (req, res) => { +const getWorkspaceKeys = ({ workspaceId }: { workspaceId: string; }) => { return SecurityClient.fetchCall( - "/api/v1/workspace/" + req.workspaceId + "/keys", + "/api/v1/workspace/" + workspaceId + "/keys", { method: "GET", headers: { @@ -16,7 +15,7 @@ const getWorkspaceKeys = (req, res) => { }, } ).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).publicKeys; } else { console.log("Failed to get the public keys of everyone in the workspace"); diff --git a/frontend/pages/api/workspace/getWorkspaceUsers.js b/frontend/pages/api/workspace/getWorkspaceUsers.ts similarity index 69% rename from frontend/pages/api/workspace/getWorkspaceUsers.js rename to frontend/pages/api/workspace/getWorkspaceUsers.ts index 4d87836c7..9805c2695 100644 --- a/frontend/pages/api/workspace/getWorkspaceUsers.js +++ b/frontend/pages/api/workspace/getWorkspaceUsers.ts @@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient"; /** * This route lets us get all the users in the workspace. - * @param {*} req - * @param {*} res + * @param {string} workspaceId - workspace ID * @returns */ -const getWorkspaceUsers = (req, res) => { +const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string; }) => { return SecurityClient.fetchCall( - "/api/v1/workspace/" + req.workspaceId + "/users", + "/api/v1/workspace/" + workspaceId + "/users", { method: "GET", headers: { @@ -16,7 +15,7 @@ const getWorkspaceUsers = (req, res) => { }, } ).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).users; } else { console.log("Failed to get Project Users"); diff --git a/frontend/pages/api/workspace/getWorkspaces.js b/frontend/pages/api/workspace/getWorkspaces.ts similarity index 69% rename from frontend/pages/api/workspace/getWorkspaces.js rename to frontend/pages/api/workspace/getWorkspaces.ts index ccaf49e9b..9427c03d0 100644 --- a/frontend/pages/api/workspace/getWorkspaces.js +++ b/frontend/pages/api/workspace/getWorkspaces.ts @@ -1,19 +1,17 @@ import SecurityClient from "~/utilities/SecurityClient"; /** - * This route lets us get the public keys of everyone in your workspace. - * @param {*} req - * @param {*} res + * This route lets us get the workspaces of a certain user * @returns */ -const getWorkspaces = (req, res) => { +const getWorkspaces = () => { return SecurityClient.fetchCall("/api/v1/workspace", { method: "GET", headers: { "Content-Type": "application/json", }, }).then(async (res) => { - if (res.status == 200) { + if (res?.status == 200) { return (await res.json()).workspaces; } else { console.log("Failed to get projects"); diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js index 42abf24db..b2dfd70f4 100644 --- a/frontend/pages/dashboard/[id].js +++ b/frontend/pages/dashboard/[id].js @@ -378,9 +378,9 @@ export default function Dashboard() { } else if (duplicatesExist) { console.log("Remove the duplicated entries first!"); } else { - // Once "Save changed is clicked", disable that button + // Once "Save changes 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 diff --git a/frontend/pages/home/[id].tsx b/frontend/pages/home/[id].tsx new file mode 100644 index 000000000..21f15fcc3 --- /dev/null +++ b/frontend/pages/home/[id].tsx @@ -0,0 +1,142 @@ +import React, { useEffect, useState } from "react"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { IconProp } from "@fortawesome/fontawesome-svg-core"; +import { faSlack } from "@fortawesome/free-brands-svg-icons"; +import { faCheckCircle, faHandPeace, faNetworkWired, faPlug, faPlus, faStar, faUserPlus } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import getOrganizationUsers from "../api/organization/GetOrgUsers"; +import checkUserAction from "../api/userActions/checkUserAction"; +import registerUserAction from "../api/userActions/registerUserAction"; + +type ItemProps = { + text: string; + subText: string; + complete: boolean; + icon: IconProp; + time: string; + userAction?: string; + link?: string; +}; + +const learningItem = ({ text, subText, complete, icon, time, userAction, link }: ItemProps): JSX.Element => { + if (link) { + return ( + + +
{ + if (userAction) { + await registerUserAction({ + action: userAction + }) + } + }} + className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer"> +
+ + {complete && +
+ +
} +
+
{text}
+
{subText}
+
+
+
+ {complete ? "Complete!" : "About " + time} +
+ {complete &&
} +
+
+ + ); + } else { + return ( +
{ + if (userAction) { + await registerUserAction({ + action: userAction + }) + } + }} + className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer"> +
+ + {complete && +
+ +
} +
+
{text}
+
{subText}
+
+
+
+ {complete ? "Complete!" : "About " + time} +
+ {complete &&
} +
+ ); + } +} + +/** + * This tab is called Home because in the future it will include some company news, + * updates, roadmap, relavant blogs, etc. Currently it only has the setup instruction + * for the new users + */ +export default function Home() { + const router = useRouter(); + const [hasUserClickedSlack, setHasUserClickedSlack] = useState(false); + const [hasUserClickedIntro, setHasUserClickedIntro] = useState(false); + const [hasUserStarred, setHasUserStarred] = useState(false); + const [usersInOrg, setUsersInOrg] = useState(false); + + useEffect(() => { + const checkUserActionsFunction = async () => { + const userActionSlack = await checkUserAction({ + action: "slack_cta_clicked", + }); + setHasUserClickedSlack(userActionSlack ? true : false); + + const userActionIntro = await checkUserAction({ + action: "intro_cta_clicked", + }); + setHasUserClickedIntro(userActionIntro ? true : false); + + const userActionStar = await checkUserAction({ + action: "star_cta_clicked", + }); + setHasUserStarred(userActionStar ? true : false); + + const orgId = localStorage.getItem("orgData.id"); + const orgUsers = await getOrganizationUsers({ + orgId: orgId ? orgId : "", + }); + setUsersInOrg(orgUsers.length > 1) + }; + checkUserActionsFunction(); + }, []); + + return ( +
+
+
Your quick start guide
+
Click on the items below and follow the instructions.
+ {learningItem({ text: "Get to know Infisical", subText: "", complete: hasUserClickedIntro, icon: faHandPeace, time: "3 min", userAction: "intro_cta_clicked", link: "https://www.youtube.com/watch?v=JS3OKYU2078" })} + {learningItem({ text: "Add your secrets", subText: "Click to see example secrets, and add your own.", complete: false, icon: faPlus, time: "2 min", userAction: "first_time_secrets_pushed", link: "/dashboard/" + router.query.id })} + {learningItem({ text: "Inject secrets locally", subText: "Replace .env files with a more secure an efficient alternative.", complete: false, icon: faNetworkWired, time: "8 min", link: "https://infisical.com/docs/getting-started/quickstart" })} + {learningItem({ text: "Integrate Infisical with your infrastructure", subText: "Only a few integrations are currently available. Many more coming soon!", complete: false, icon: faPlug, time: "15 min", link: "https://infisical.com/docs/integrations/overview" })} + {learningItem({ text: "Invite your teammates", subText: "", complete: usersInOrg, icon: faUserPlus, time: "2 min", link: "/settings/org/" + router.query.id + "?invite" })} + {learningItem({ text: "Join Infisical Slack", subText: "Have any questions? Ask us!", complete: hasUserClickedSlack, icon: faSlack, time: "1 min", userAction: "slack_cta_clicked", link: "https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g" })} + {learningItem({ text: "Star Infisical on GitHub", subText: "Like what we're doing? You know what to do! :)", complete: hasUserStarred, icon: faStar, time: "1 min", userAction: "star_cta_clicked", link: "https://github.com/Infisical/infisical" })} +
+
+ ); +} + +Home.requireAuth = true; diff --git a/frontend/pages/signup.js b/frontend/pages/signup.js index 14ae51dcf..77c3c7ef4 100644 --- a/frontend/pages/signup.js +++ b/frontend/pages/signup.js @@ -197,7 +197,7 @@ export default function SignUp() { }, async () => { client.createVerifier(async (err, result) => { - const response = await completeAccountInformationSignup({ + let response = await completeAccountInformationSignup({ email, firstName, lastName, @@ -495,7 +495,9 @@ export default function SignUp() { setBackupKeyError, setBackupKeyIssued, }); - router.push("/dashboard/"); + const userWorkspaces = await getWorkspaces(); + let userWorkspace = userWorkspaces[0]._id; + router.push("/home/" + userWorkspace); }} size="lg" /> diff --git a/frontend/pages/signupinvite.js b/frontend/pages/signupinvite.js index 8e7f1d4a0..15c511739 100644 --- a/frontend/pages/signupinvite.js +++ b/frontend/pages/signupinvite.js @@ -92,7 +92,7 @@ export default function SignupInvite() { }, async () => { client.createVerifier(async (err, result) => { - const response = await completeAccountInformationSignupInvite({ + let response = await completeAccountInformationSignupInvite({ email, firstName, lastName, @@ -291,7 +291,7 @@ export default function SignupInvite() {
)}
-
+