This commit is contained in:
Maidul Islam
2022-12-04 22:37:59 -05:00
16 changed files with 95 additions and 85 deletions
+6 -1
View File
@@ -10,7 +10,12 @@
"rules": { "rules": {
"react-hooks/exhaustive-deps": "off", "react-hooks/exhaustive-deps": "off",
"no-unused-vars": "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/exports": "warn",
"simple-import-sort/imports": [ "simple-import-sort/imports": [
"warn", "warn",
+5 -5
View File
@@ -6,7 +6,7 @@ import {
FontAwesomeIconProps, FontAwesomeIconProps,
} from "@fortawesome/react-fontawesome"; } from "@fortawesome/react-fontawesome";
var classNames = require("classnames"); const classNames = require("classnames");
type ButtonProps = { type ButtonProps = {
text: string; text: string;
@@ -40,7 +40,7 @@ export default function Button(props: ButtonProps): JSX.Element {
const activityStatus = const activityStatus =
props.active || (props.text != "" && props.textDisabled == undefined); 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", "group m-auto md:m-0 inline-block rounded-md duration-200",
// Setting background colors and hover modes // 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" 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", "relative font-medium flex items-center",
// Setting the text color for the text and icon // 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" props.size == "icon" && "flex items-center justify-center"
); );
let textStyle = classNames( const textStyle = classNames(
"relative duration-200", "relative duration-200",
// Show the loading sign if the loading indicator is on // 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 == "md" && "text-sm",
props.size == "lg" && "text-lg" props.size == "lg" && "text-lg"
); );
+5 -11
View File
@@ -19,6 +19,7 @@ import getOrganizationUsers from "~/pages/api/organization/GetOrgUsers";
import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace"; import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace";
import createWorkspace from "~/pages/api/workspace/createWorkspace"; import createWorkspace from "~/pages/api/workspace/createWorkspace";
import getWorkspaces from "~/pages/api/workspace/getWorkspaces"; import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
import uploadKeys from "~/pages/api/workspace/uploadKeys";
import NavBarDashboard from "../navigation/NavBarDashboard"; import NavBarDashboard from "../navigation/NavBarDashboard";
import { import {
@@ -156,9 +157,7 @@ export default function Layout({ children }) {
router.push("/noprojects"); router.push("/noprojects");
} else if (router.asPath != "/noprojects") { } else if (router.asPath != "/noprojects") {
const intendedWorkspaceId = router.asPath const intendedWorkspaceId = router.asPath
.split("/") .split("/")[router.asPath.split("/").length - 1].split("?")[0];
[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 a user is not a member of a workspace they are trying to access, just push them to one of theirs
if ( if (
intendedWorkspaceId != "heroku" && intendedWorkspaceId != "heroku" &&
@@ -179,9 +178,7 @@ export default function Layout({ children }) {
userWorkspaces.map((workspace) => [workspace._id, workspace.name]) userWorkspaces.map((workspace) => [workspace._id, workspace.name])
)[ )[
router.asPath router.asPath
.split("/") .split("/")[router.asPath.split("/").length - 1].split("?")[0]]
[router.asPath.split("/").length - 1].split("?")[0]
]
); );
} }
} }
@@ -193,12 +190,9 @@ export default function Layout({ children }) {
workspaceMapping[workspaceSelected] && workspaceMapping[workspaceSelected] &&
workspaceMapping[workspaceSelected] !== workspaceMapping[workspaceSelected] !==
router.asPath router.asPath
.split("/") .split("/")[router.asPath.split("/").length - 1].split("?")[0]
[router.asPath.split("/").length - 1].split("?")[0]
) { ) {
router.push( router.push("/dashboard/" + workspaceMapping[workspaceSelected] + "?Development");
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development"
);
localStorage.setItem( localStorage.setItem(
"projectData.id", "projectData.id",
workspaceMapping[workspaceSelected] workspaceMapping[workspaceSelected]
@@ -47,27 +47,44 @@ const supportOptions = [
], ],
]; ];
export default function Navbar({ onButtonPressed }) { export interface ICurrentOrg {
const router = useRouter(); name: string;
const [user, setUser] = useState({}); }
const [orgs, setOrgs] = useState([]);
const [currentOrg, setCurrentOrg] = useState([]);
useEffect(async () => { export interface IUser {
const userData = await getUser(); firstName: string;
setUser(userData); lastName: string;
const orgsData = await getOrganizations(); email: string;
setOrgs(orgsData); }
const currentOrg = await getOrganization({
orgId: localStorage.getItem("orgData.id"), /**
}); * This is the navigation bar in the main app.
setCurrentOrg(currentOrg); * 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<IUser | undefined>();
const [orgs, setOrgs] = useState([]);
const [currentOrg, setCurrentOrg] = useState<ICurrentOrg | undefined>();
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 () => { const closeApp = async () => {
console.log("Logging out..."); console.log("Logging out...");
await logout(); await logout();
router.push("/"); router.push("/login");
}; };
return ( return (
@@ -108,7 +125,7 @@ export default function Navbar({ onButtonPressed }) {
key={guidGenerator()} key={guidGenerator()}
target="_blank" target="_blank"
rel="noopener" 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" className="font-normal text-gray-300 duration-200 rounded-md w-full flex items-center py-0.5"
> >
<div className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full"> <div className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full">
@@ -238,9 +255,9 @@ export default function Navbar({ onButtonPressed }) {
<div className="flex flex-col items-start px-1 mt-3 mb-2"> <div className="flex flex-col items-start px-1 mt-3 mb-2">
{orgs {orgs
.filter( .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; }) => (
<div <div
key={guidGenerator()} key={guidGenerator()}
onClick={() => { onClick={() => {
@@ -1,29 +1,37 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faCcMastercard, faCcVisa } from "@fortawesome/free-brands-svg-icons";
import { import {
faAngleRight, faAngleRight,
faQuestionCircle,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { faCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import getOrganization from "~/pages/api/organization/GetOrg"; 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 [orgName, setOrgName] = useState("");
const [workspaceName, setWorkspaceName] = useState(""); const [workspaceName, setWorkspaceName] = useState("");
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
const orgId = localStorage.getItem("orgData.id")
let org = await getOrganization({ let org = await getOrganization({
orgId: localStorage.getItem("orgData.id"), orgId: orgId ? orgId : "",
}); });
setOrgName(org.name); setOrgName(org.name);
let workspace = await getWorkspaceInfo({
workspaceId: router.query.id, let workspace = await getProjectInfo({
projectId: String(router.query.id),
}); });
setWorkspaceName(workspace.name); setWorkspaceName(workspace.name);
})(); })();
@@ -43,7 +43,7 @@ const attemptLogin = async (
let serverPublicKey, salt; let serverPublicKey, salt;
try { try {
const res = await login1(email, clientPublicKey); let res = await login1(email, clientPublicKey);
res = await res.json(); res = await res.json();
serverPublicKey = res.serverPublicKey; serverPublicKey = res.serverPublicKey;
salt = res.salt; salt = res.salt;
@@ -108,11 +108,7 @@ const changePassword = async (
} }
); );
} catch (error) { } catch (error) {
console.log( console.log("Something went wrong during changing the password");
"Something went wrong during changing the password",
slat,
serverPublicKey
);
} }
return true; return true;
}; };
@@ -31,8 +31,8 @@ const issueBackupPrivateKey = ({
if (res.status == 200) { if (res.status == 200) {
return res; return res;
} else { } else {
return res;
console.log("Failed to issue the backup key"); console.log("Failed to issue the backup key");
return res;
} }
}); });
}; };
@@ -3,11 +3,8 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route logs the user out. Note: the user should authorized to do this. * 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 * 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", { return SecurityClient.fetchCall("/api/v1/auth/logout", {
method: "POST", method: "POST",
headers: { headers: {
@@ -15,7 +12,7 @@ const logout = async (req, res) => {
}, },
credentials: "include", credentials: "include",
}).then((res) => { }).then((res) => {
if (res.status == 200) { if (res?.status == 200) {
SecurityClient.setToken(""); SecurityClient.setToken("");
// Delete the cookie by not setting a value; Alternatively clear the local storage // Delete the cookie by not setting a value; Alternatively clear the local storage
localStorage.setItem("publicKey", ""); localStorage.setItem("publicKey", "");
@@ -2,18 +2,17 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get info about a certain org * This route lets us get info about a certain org
* @param {*} req * @param {string} orgId - the organization ID
* @param {*} res
* @returns * @returns
*/ */
const getOrganization = (req, res) => { const getOrganization = ({ orgId }: { orgId: string; }) => {
return SecurityClient.fetchCall("/api/v1/organization/" + req.orgId, { return SecurityClient.fetchCall("/api/v1/organization/" + orgId, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).organization; return (await res.json()).organization;
} else { } else {
console.log("Failed to get org info"); console.log("Failed to get org info");
@@ -2,18 +2,16 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get the all the orgs of a certain user. * This route lets us get the all the orgs of a certain user.
* @param {*} req
* @param {*} res
* @returns * @returns
*/ */
const getOrganizations = (req, res) => { const getOrganizations = () => {
return SecurityClient.fetchCall("/api/v1/organization", { return SecurityClient.fetchCall("/api/v1/organization", {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).organizations; return (await res.json()).organizations;
} else { } else {
console.log("Failed to get orgs of a user"); console.log("Failed to get orgs of a user");
@@ -2,18 +2,15 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route gets the information about a specific user. * 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", { return SecurityClient.fetchCall("/api/v1/user", {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}).then(async (res) => { }).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).user; return (await res.json()).user;
} else { } else {
console.log("Failed to get user info"); console.log("Failed to get user info");
@@ -2,13 +2,12 @@ import SecurityClient from "~/utilities/SecurityClient";
/** /**
* This route lets us get the information of a certain project. * This route lets us get the information of a certain project.
* @param {*} req * @param {*} projectId - project ID (we renamed workspaces to projects in the app)
* @param {*} res
* @returns * @returns
*/ */
const getWorkspaceInfo = (req, res) => { const getProjectInfo = ({ projectId }: { projectId: string; }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/workspace/" + req.workspaceId, "/api/v1/workspace/" + projectId,
{ {
method: "GET", method: "GET",
headers: { headers: {
@@ -16,7 +15,7 @@ const getWorkspaceInfo = (req, res) => {
}, },
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res?.status == 200) {
return (await res.json()).workspace; return (await res.json()).workspace;
} else { } else {
console.log("Failed to get project info"); console.log("Failed to get project info");
@@ -24,4 +23,4 @@ const getWorkspaceInfo = (req, res) => {
}); });
}; };
export default getWorkspaceInfo; export default getProjectInfo;
+7 -7
View File
@@ -98,22 +98,22 @@ export default function Home() {
useEffect(() => { useEffect(() => {
const checkUserActionsFunction = async () => { const checkUserActionsFunction = async () => {
let userActionSlack = await checkUserAction({ const userActionSlack = await checkUserAction({
action: "slack_cta_clicked", action: "slack_cta_clicked",
}); });
setHasUserClickedSlack(userActionSlack ? true : false); setHasUserClickedSlack(userActionSlack ? true : false);
let userActionIntro = await checkUserAction({ const userActionIntro = await checkUserAction({
action: "intro_cta_clicked", action: "intro_cta_clicked",
}); });
setHasUserClickedIntro(userActionIntro ? true : false); setHasUserClickedIntro(userActionIntro ? true : false);
let userActionStar = await checkUserAction({ const userActionStar = await checkUserAction({
action: "star_cta_clicked", action: "star_cta_clicked",
}); });
setHasUserStarred(userActionStar ? true : false); setHasUserStarred(userActionStar ? true : false);
let orgId = localStorage.getItem("orgData.id"); const orgId = localStorage.getItem("orgData.id");
const orgUsers = await getOrganizationUsers({ const orgUsers = await getOrganizationUsers({
orgId: orgId ? orgId : "", orgId: orgId ? orgId : "",
}); });
@@ -123,9 +123,9 @@ export default function Home() {
}, []); }, []);
return ( return (
<div className="mx-6 lg:mx-0 w-full overflow-y-scroll pt-28 h-screen"> <div className="mx-6 lg:mx-0 w-full overflow-y-scroll pt-20 h-screen">
<div className="flex flex-col items-center text-gray-300 text-lg mx-auto max-w-2xl lg:max-w-3xl xl:max-w-4xl"> <div className="flex flex-col items-center text-gray-300 text-lg mx-auto max-w-2xl lg:max-w-3xl xl:max-w-4xl py-6">
<div className="text-3xl font-bold text-left w-full pt-6">Your quick start guide</div> <div className="text-3xl font-bold text-left w-full">Your quick start guide</div>
<div className="text-md text-left w-full pt-2 pb-4 text-bunker-300">Click on the items below and follow the instructions.</div> <div className="text-md text-left w-full pt-2 pb-4 text-bunker-300">Click on the items below and follow the instructions.</div>
{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: "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: "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 })}
+1 -1
View File
@@ -197,7 +197,7 @@ export default function SignUp() {
}, },
async () => { async () => {
client.createVerifier(async (err, result) => { client.createVerifier(async (err, result) => {
const response = await completeAccountInformationSignup({ let response = await completeAccountInformationSignup({
email, email,
firstName, firstName,
lastName, lastName,
+2 -2
View File
@@ -92,7 +92,7 @@ export default function SignupInvite() {
}, },
async () => { async () => {
client.createVerifier(async (err, result) => { client.createVerifier(async (err, result) => {
const response = await completeAccountInformationSignupInvite({ let response = await completeAccountInformationSignupInvite({
email, email,
firstName, firstName,
lastName, lastName,
@@ -291,7 +291,7 @@ export default function SignupInvite() {
<div className="py-2"></div> <div className="py-2"></div>
)} )}
</div> </div>
<div className="flex flex-col items-center justify-center w-full md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-md mx-auto text-lg"> <div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
<Button <Button
text="Sign Up" text="Sign Up"
onButtonPressed={() => { onButtonPressed={() => {