Merge remote-tracking branch 'upstream/main' into feat/39

This commit is contained in:
이강준
2022-12-06 22:07:29 +09:00
163 changed files with 2639 additions and 1327 deletions
@@ -1,8 +1,8 @@
import React, { useState } from "react";
import React from "react";
import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export default function Error({ text }) {
export default function Error({ text }: { text: string }): JSX.Element {
return (
<div className="relative bg-red-500 opacity-100 border flex flex-row justify-center m-auto items-center w-fit rounded-full mb-4">
<FontAwesomeIcon
@@ -1,6 +1,5 @@
import React from "react";
import { Fragment } from "react";
import { useRouter } from "next/router";
import {
faAngleDown,
faCheck,
@@ -9,9 +8,25 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Listbox, Transition } from "@headlessui/react";
type ListBoxProps = {
selected: string,
onChange: () => void,
data: string[],
text: string,
buttonAction: () => void,
width: string,
}
/**
* This is the component that we use for drop down lists.
* @param {*} param0
* @param {object} obj
* @param {string} obj.selected - the item that is currently selected
* @param {function} obj.onChange - what happends if you select the item inside a list
* @param {string[]} obj.data - all the options available
* @param {string} obj.text - the text that shows us in front of the select option
* @param {function} obj.buttonAction - if there is a button at the bottom of the list, this is the action that happens when you click the button
* @param {string} obj.width - button width
* @returns
*/
export default function ListBox({
@@ -21,10 +36,7 @@ export default function ListBox({
text,
buttonAction,
width,
workspaceMapping = [],
}) {
const router = useRouter();
} : ListBoxProps): JSX.Element {
return (
<Listbox value={selected} onChange={onChange}>
<div className="relative">
@@ -61,7 +73,7 @@ export default function ListBox({
`my-0.5 relative cursor-default select-none py-2 pl-10 pr-4 rounded-md ${
selected ? "bg-white/10 text-gray-400 font-bold" : ""
} ${
active & !selected
active && !selected
? "bg-white/5 text-mineshaft-200 cursor-pointer"
: "text-gray-400"
} `
+46 -20
View File
@@ -1,35 +1,59 @@
import React from "react";
import Image from "next/image";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } 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;
};
export default function Button (props: ButtonProps): JSX.Element {
/**
* This is the main butto component in the app.
* @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
* @param {string} props.color - button color
* @param {string} props.size - button size
* @param {FontAwesomeIconProps} props.icon - the icon inside the button
* @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
*/
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
@@ -43,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
@@ -55,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"
);
@@ -86,7 +110,7 @@ export default function Button (props: ButtonProps): JSX.Element {
</div>
{props.icon && (
<FontAwesomeIcon
icon={props.icon as IconProp}
icon={props.icon}
className={`flex my-auto font-extrabold ${
props.size == "icon-sm" ? "text-sm" : "text-md"
} ${(props.text || props.textDisabled) && "mr-2"}`}
@@ -101,7 +125,9 @@ export default function Button (props: ButtonProps): JSX.Element {
/>
)}
{(props.text || props.textDisabled) && (
<p className={textStyle}>{activityStatus ? props.text : props.textDisabled}</p>
<p className={textStyle}>
{activityStatus ? props.text : props.textDisabled}
</p>
)}
</div>
</button>
@@ -9,6 +9,7 @@ import nacl from "tweetnacl";
import addServiceToken from "~/pages/api/serviceToken/addServiceToken";
import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey";
import { envMapping } from "../../../public/data/frequentConstants";
import {
decryptAssymmetric,
encryptAssymmetric,
@@ -17,13 +18,6 @@ import Button from "../buttons/Button";
import InputField from "../InputField";
import ListBox from "../Listbox";
const envMapping = {
Development: "dev",
Staging: "staging",
Production: "prod",
Testing: "test",
};
const expiryMapping = {
"1 day": 86400,
"7 days": 604800,
@@ -45,7 +39,7 @@ const AddServiceTokenDialog = ({
const { t } = useTranslate();
const generateServiceToken = async () => {
const latestFileKey = await getLatestFileKey(workspaceId);
const latestFileKey = await getLatestFileKey({ workspaceId });
const key = decryptAssymmetric({
ciphertext: latestFileKey.latestKey.encryptedKey,
+98 -63
View File
@@ -4,10 +4,11 @@ import Link from "next/link";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation";
import {
faBookOpen,
faGear,
faHouse,
faLink,
faKey,
faMobile,
faPlug,
faUser,
} from "@fortawesome/free-solid-svg-icons";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
@@ -19,6 +20,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 {
@@ -57,10 +59,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;
@@ -117,7 +119,7 @@ export default function Layout({ children }) {
href:
"/dashboard/" + workspaceMapping[workspaceSelected] + "?Development",
title: t("nav:menu.secrets"),
emoji: <FontAwesomeIcon icon={faHouse} />,
emoji: <FontAwesomeIcon icon={faKey} />,
},
{
href: "/users/" + workspaceMapping[workspaceSelected],
@@ -127,7 +129,7 @@ export default function Layout({ children }) {
{
href: "/integrations/" + workspaceMapping[workspaceSelected],
title: t("nav:menu.integrations"),
emoji: <FontAwesomeIcon icon={faLink} />,
emoji: <FontAwesomeIcon icon={faPlug} />,
},
{
href: "/settings/project/" + workspaceMapping[workspaceSelected],
@@ -160,7 +162,6 @@ export default function Layout({ children }) {
const intendedWorkspaceId = router.asPath
.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" &&
@@ -217,66 +218,100 @@ export default function Layout({ children }) {
<NavBarDashboard />
<div className="flex flex-col md:flex-row flex-1">
<aside className="bg-bunker-600 border-r border-mineshaft-500 w-full md:w-60 h-screen">
<nav>
<div className="py-6"></div>
<div className="flex justify-center w-full mt-7 mb-8 bg-bunker-600 w-full h-full flex flex-col items-center px-4">
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
{t("nav:menu.project")}
<nav className="flex flex-col justify-between items-between h-full">
{/* <div className="py-6"></div> */}
<div>
<div className="flex justify-center w-full mt-[4.5rem] mb-6 bg-bunker-600 w-full h-20 flex flex-col items-center px-4">
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
{t("nav:menu.project")}
</div>
{workspaceList.length > 0 ? (
<Listbox
selected={workspaceSelected}
onChange={setWorkspaceSelected}
data={workspaceList}
buttonAction={openModal}
text=""
workspaceMapping={workspaceMapping}
/>
) : (
<Button
text="Add Project"
onButtonPressed={openModal}
color="mineshaft"
size="md"
icon={faPlus}
/>
)}
</div>
{workspaceList.length > 0 ? (
<Listbox
selected={workspaceSelected}
onChange={setWorkspaceSelected}
data={workspaceList}
buttonAction={openModal}
text=""
workspaceMapping={workspaceMapping}
/>
) : (
<Button
text="Add Project"
onButtonPressed={openModal}
color="mineshaft"
size="md"
icon={faPlus}
/>
)}
</div>
<ul>
{workspaceList.length > 0 &&
menuItems.map(({ href, title, emoji }) => (
<li className="mt-1.5 mx-2" key={title}>
{router.asPath.split("/")[1] === href.split("/")[1] &&
(["project", "billing", "org", "personal"].includes(
router.asPath.split("/")[2]
)
? router.asPath.split("/")[2] === href.split("/")[2]
: true) ? (
<div
className={`flex p-2 text-white text-sm rounded cursor-pointer bg-mineshaft-50/10`}
>
<div className="bg-primary w-1 rounded-xl mr-1"></div>
<p className="ml-2 mr-4">{emoji}</p>
{title}
</div>
) : router.asPath == "/noprojects" ? (
<div className={`flex p-2 text-white text-sm rounded`}>
<p className="ml-2 mr-4">{emoji}</p>
{title}
</div>
) : (
<Link href={href}>
<ul>
{workspaceList.length > 0 &&
menuItems.map(({ href, title, emoji }) => (
<li className="mt-0.5 mx-2" key={title}>
{router.asPath.split("/")[1] === href.split("/")[1] &&
(["project", "billing", "org", "personal"].includes(
router.asPath.split("/")[2]
)
? router.asPath.split("/")[2] === href.split("/")[2]
: true) ? (
<div
className={`flex p-2 text-white text-sm rounded cursor-pointer hover:bg-mineshaft-50/5`}
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
>
<p className="ml-2 mr-4">{emoji}</p>
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div>
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
{emoji}
</p>
{title}
</div>
</Link>
)}
</li>
))}
</ul>
) : router.asPath == "/noprojects" ? (
<div
className={`flex p-2.5 text-white text-sm rounded`}
>
<p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title}
</div>
) : (
<Link href={href}>
<div
className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5`}
>
<p className="w-10 flex items-center justify-center text-lg">
{emoji}
</p>
{title}
</div>
</Link>
)}
</li>
))}
</ul>
</div>
<div className="w-full mt-40 mb-4 px-2">
{router.asPath.split("/")[1] === "home" ? (
<div
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
>
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1"></div>
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
<FontAwesomeIcon icon={faBookOpen} />
</p>
Infisical Guide
</div>
) : (
<Link href={`/home/` + workspaceMapping[workspaceSelected]}>
<div
className={`flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5 mt-max border border-dashed border-bunker-400`}
>
<p className="w-10 flex items-center justify-center text-lg">
<FontAwesomeIcon icon={faBookOpen} />
</p>
Infisical Guide
</div>
</Link>
)}
</div>
</nav>
</aside>
<AddWorkspaceDialog
@@ -2,6 +2,19 @@ import React from "react";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
/**
* This is the notification that pops up at the bottom right when a user performs a certain action
* @param {object} org
* @param {string} org.buttonText - text of the button inside the notification
* @param {string} org.buttonLink - where the button leads to
* @param {string} org.titleText - the text at the top of a notification
* @param {string} org.emoji - the emoji in the notification title
* @param {string} org.textLine1 - first line of the text in the notification
* @param {string} org.textLine2 - second line of the text in the notification
* @param {string} org.setCheckDocsPopUpVisible - the functions that closes the popup
* @returns
*/
export default function BottonRightPopup({
buttonText,
buttonLink,
@@ -2,18 +2,10 @@ import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { faX } from "@fortawesome/free-solid-svg-icons";
import { reverseEnvMapping } from "../../../public/data/frequentConstants";
import guidGenerator from "../../utilities/randomId";
import Button from "../buttons/Button";
const roles = ["admin", "user"];
const reverseEnvMapping = {
dev: "Development",
staging: "Staging",
prod: "Production",
test: "Testing",
};
/**
* This is the component that we utilize for the user table - in future, can reuse it for some other purposes too.
* #TODO: add the possibility of choosing and doing operations on multiple users.
+1 -1
View File
@@ -88,7 +88,7 @@ const UserTable = ({
}, [userData, myUser]);
const grantAccess = async (id, publicKey) => {
let result = await getLatestFileKey(router.query.id);
let result = await getLatestFileKey({workspaceId: router.query.id});
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY");