diff --git a/frontend/.eslintrc b/frontend/.eslintrc index cfb3f694b..b562aaa1f 100644 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -10,7 +10,12 @@ "rules": { "react-hooks/exhaustive-deps": "off", "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": "error", + "@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", diff --git a/frontend/components/basic/buttons/Button.tsx b/frontend/components/basic/buttons/Button.tsx index 863dc4b48..5fe2db803 100644 --- a/frontend/components/basic/buttons/Button.tsx +++ b/frontend/components/basic/buttons/Button.tsx @@ -6,7 +6,7 @@ import { FontAwesomeIconProps, } from "@fortawesome/react-fontawesome"; -var classNames = require("classnames"); +const classNames = require("classnames"); type ButtonProps = { text: string; @@ -40,7 +40,7 @@ export default function Button(props: ButtonProps): JSX.Element { const activityStatus = props.active || (props.text != "" && props.textDisabled == undefined); - let styleButton = classNames( + const styleButton = classNames( "group m-auto md:m-0 inline-block rounded-md duration-200", // Setting background colors and hover modes @@ -67,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 @@ -79,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 - Boolean(props.loading) ? "opacity-0" : "opacity-100", + props.loading ? "opacity-0" : "opacity-100", props.size == "md" && "text-sm", props.size == "lg" && "text-lg" ); diff --git a/frontend/components/basic/layout.js b/frontend/components/basic/layout.js index 63dbf5dea..6482c57ac 100644 --- a/frontend/components/basic/layout.js +++ b/frontend/components/basic/layout.js @@ -19,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 { @@ -156,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" && @@ -179,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]] ); } } @@ -193,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] 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 69% rename from frontend/components/navigation/NavHeader.js rename to frontend/components/navigation/NavHeader.tsx index 3f65a5aa6..d6d8713ba 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 () => { + const orgId = localStorage.getItem("orgData.id") let org = await getOrganization({ - orgId: localStorage.getItem("orgData.id"), + orgId: orgId ? orgId : "", }); setOrgName(org.name); - let workspace = await getWorkspaceInfo({ - workspaceId: router.query.id, + + let 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 c2e6bfc4b..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; 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/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/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/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/home/[id].tsx b/frontend/pages/home/[id].tsx index 5ee7e920b..21f15fcc3 100644 --- a/frontend/pages/home/[id].tsx +++ b/frontend/pages/home/[id].tsx @@ -98,22 +98,22 @@ export default function Home() { useEffect(() => { const checkUserActionsFunction = async () => { - let userActionSlack = await checkUserAction({ + const userActionSlack = await checkUserAction({ action: "slack_cta_clicked", }); setHasUserClickedSlack(userActionSlack ? true : false); - let userActionIntro = await checkUserAction({ + const userActionIntro = await checkUserAction({ action: "intro_cta_clicked", }); setHasUserClickedIntro(userActionIntro ? true : false); - let userActionStar = await checkUserAction({ + const userActionStar = await checkUserAction({ action: "star_cta_clicked", }); setHasUserStarred(userActionStar ? true : false); - let orgId = localStorage.getItem("orgData.id"); + const orgId = localStorage.getItem("orgData.id"); const orgUsers = await getOrganizationUsers({ orgId: orgId ? orgId : "", }); @@ -123,9 +123,9 @@ export default function Home() { }, []); return ( -
-
-
Your quick start guide
+
+
+
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 })} diff --git a/frontend/pages/signup.js b/frontend/pages/signup.js index dfd497cd7..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, 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() {
)}
-
+