onChangeHandler(e.target.value, position)}
@@ -99,10 +102,13 @@ const DashboardInputField = ({
{value.split(REGEX).map((word, id) => {
if (word.match(REGEX) !== null) {
@@ -153,4 +159,8 @@ const DashboardInputField = ({
return <>Something Wrong>;
};
-export default React.memo(DashboardInputField);
+function inputPropsAreEqual(prev: DashboardInputFieldProps, next: DashboardInputFieldProps) {
+ return prev.value === next.value && prev.type === next.type && prev.position === next.position && prev.blurred === next.blurred && prev.override === next.override && prev.isDuplicate === next.isDuplicate;
+}
+
+export default memo(DashboardInputField, inputPropsAreEqual);
diff --git a/frontend/components/dashboard/GenerateSecretMenu.tsx b/frontend/components/dashboard/GenerateSecretMenu.tsx
new file mode 100644
index 000000000..115e19374
--- /dev/null
+++ b/frontend/components/dashboard/GenerateSecretMenu.tsx
@@ -0,0 +1,93 @@
+import { Fragment,useState } from 'react';
+import { faShuffle } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Menu, Transition } from '@headlessui/react';
+
+
+/**
+ * This is the menu that is used to (re)generate secrets (currently we only have ranom hex, in future we will have more options)
+ * @returns the popup-menu for randomly generating secrets
+ */
+const GenerateSecretMenu = ({ modifyValue, position }: { modifyValue: (value: string, position: number) => void; position: number; }) => {
+ const [randomStringLength, setRandomStringLength] = useState(32);
+
+ return
+}
+
+export default GenerateSecretMenu;
diff --git a/frontend/components/dashboard/KeyPair.tsx b/frontend/components/dashboard/KeyPair.tsx
new file mode 100644
index 000000000..d917f3cee
--- /dev/null
+++ b/frontend/components/dashboard/KeyPair.tsx
@@ -0,0 +1,102 @@
+import React from 'react';
+import { faEllipsis, faShuffle, faX } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import Button from '../basic/buttons/Button';
+import DashboardInputField from './DashboardInputField';
+
+interface SecretDataProps {
+ type: 'personal' | 'shared';
+ pos: number;
+ key: string;
+ value: string;
+ id: string;
+}
+
+interface KeyPairProps {
+ keyPair: SecretDataProps;
+ deleteRow: (id: string) => void;
+ modifyKey: (value: string, position: number) => void;
+ modifyValue: (value: string, position: number) => void;
+ isBlurred: boolean;
+ isDuplicate: boolean;
+ toggleSidebar: (id: string) => void;
+ sidebarSecretId: string;
+}
+
+/**
+ * This component represent a single row for an environemnt variable on the dashboard
+ * @param {object} obj
+ * @param {String[]} obj.keyPair - data related to the environment variable (id, pos, key, value, public/private)
+ * @param {function} obj.deleteRow - a function to delete a certain keyPair
+ * @param {function} obj.modifyKey - modify the key of a certain environment variable
+ * @param {function} obj.modifyValue - modify the value of a certain environment variable
+ * @param {boolean} obj.isBlurred - if the blurring setting is turned on
+ * @param {boolean} obj.isDuplicate - list of all the duplicates secret names on the dashboard
+ * @param {function} obj.toggleSidebar - open/close/switch sidebar
+ * @param {string} obj.sidebarSecretId - the id of a secret for the side bar is displayed
+ * @returns
+ */
+const KeyPair = ({
+ keyPair,
+ deleteRow,
+ modifyKey,
+ modifyValue,
+ isBlurred,
+ isDuplicate,
+ toggleSidebar,
+ sidebarSecretId
+}: KeyPairProps) => {
+ return (
+
+
+ {keyPair.type == "personal" &&
+
+
+ This secret is overriden
+
+
}
+
+
+
toggleSidebar(keyPair.id)} className="cursor-pointer w-9 h-9 bg-mineshaft-700 hover:bg-chicago-700 rounded-md flex flex-row justify-center items-center duration-200">
+
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(KeyPair);
\ No newline at end of file
diff --git a/frontend/components/dashboard/SideBar.tsx b/frontend/components/dashboard/SideBar.tsx
new file mode 100644
index 000000000..60a4641fe
--- /dev/null
+++ b/frontend/components/dashboard/SideBar.tsx
@@ -0,0 +1,171 @@
+import { useState } from 'react';
+import { faX } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import SecretVersionList from 'ee/components/SecretVersionList';
+
+import Button from '../basic/buttons/Button';
+import Toggle from '../basic/Toggle';
+import DashboardInputField from './DashboardInputField';
+import GenerateSecretMenu from './GenerateSecretMenu';
+
+
+interface SecretProps {
+ key: string;
+ value: string;
+ pos: number;
+ type: string;
+ id: string;
+}
+
+interface OverrideProps {
+ id: string;
+ keyName: string;
+ value: string;
+ pos: number;
+}
+
+interface SideBarProps {
+ toggleSidebar: (value: string) => void;
+ data: SecretProps[];
+ modifyKey: (value: string, position: number) => void;
+ modifyValue: (value: string, position: number) => void;
+ addOverride: (value: OverrideProps) => void;
+ deleteOverride: (id: string) => void;
+ buttonReady: boolean;
+ savePush: () => void;
+ sharedToHide: string[];
+ setSharedToHide: (values: string[]) => void;
+}
+
+/**
+ * @param {object} obj
+ * @param {function} obj.toggleSidebar - function that opens or closes the sidebar
+ * @param {SecretProps[]} obj.data - data of a certain key valeu pair
+ * @param {function} obj.modifyKey - function that modifies the secret key
+ * @param {function} obj.modifyValue - function that modifies the secret value
+ * @param {function} obj.addOverride - override a certain secret
+ * @param {function} obj.deleteOverride - delete the personal override for a certain secret
+ * @param {boolean} obj.buttonReady - is the button for saving chagnes active
+ * @param {function} obj.savePush - save changes andp ush secrets
+ * @param {string[]} obj.sharedToHide - an array of shared secrets that we want to hide visually because they are overriden.
+ * @param {function} obj.setSharedToHide - a function that updates the array of secrets that we want to hide visually
+ * @returns the sidebar with 'secret's settings'
+ */
+const SideBar = ({
+ toggleSidebar,
+ data,
+ modifyKey,
+ modifyValue,
+ addOverride,
+ deleteOverride,
+ buttonReady,
+ savePush,
+ sharedToHide,
+ setSharedToHide
+}: SideBarProps) => {
+ const [overrideEnabled, setOverrideEnabled] = useState(data.map(secret => secret.type).includes("personal"));
+
+ return
+
+
+
Secret
+
toggleSidebar("None")}>
+
+
+
+
+ {data.filter(secret => secret.type == "shared")[0]?.value
+ ?
+
Value
+
secret.type == "shared")[0]?.pos}
+ value={data.filter(secret => secret.type == "shared")[0]?.value}
+ isDuplicate={false}
+ blurred={true}
+ />
+
+ secret.type == "shared")[0]?.pos} />
+
+
+ :
+ Note:
+ This secret is personal. It is not shared with any of your teammates.
+
}
+
+ {data.filter(secret => secret.type == "shared")[0]?.value &&
+
+
Override value with a personal value
+
+
}
+
+
secret.type == "personal")[0].pos : data[0].pos}
+ value={overrideEnabled ? data.filter(secret => secret.type == "personal")[0].value : data[0].value}
+ isDuplicate={false}
+ blurred={true}
+ />
+
+ secret.type == "personal")[0].pos : data[0].pos} />
+
+
+
+ {/*
+
Group
+
{}}
+ data={["Group1"]}
+ isFull={true}
+ />
+ */}
+
+
+
+ Leave your comment here...
+
+
+
+
+
+
+
+};
+
+export default SideBar;
diff --git a/frontend/components/integrations/Integration.tsx b/frontend/components/integrations/Integration.tsx
index 3bba41534..ae9a1a613 100644
--- a/frontend/components/integrations/Integration.tsx
+++ b/frontend/components/integrations/Integration.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import {
faArrowRight,
diff --git a/frontend/components/navigation/NavBarDashboard.tsx b/frontend/components/navigation/NavBarDashboard.tsx
index 1834d8117..23f7c0677 100644
--- a/frontend/components/navigation/NavBarDashboard.tsx
+++ b/frontend/components/navigation/NavBarDashboard.tsx
@@ -1,6 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable react/jsx-key */
-import React, { Fragment, useEffect, useState } from 'react';
+import { Fragment, useEffect, useState } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { faGithub, faSlack } from '@fortawesome/free-brands-svg-icons';
diff --git a/frontend/components/navigation/NavHeader.tsx b/frontend/components/navigation/NavHeader.tsx
index 3d64c2eda..6e9fabe39 100644
--- a/frontend/components/navigation/NavHeader.tsx
+++ b/frontend/components/navigation/NavHeader.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import {
faAngleRight,
diff --git a/frontend/components/utilities/secrets/getSecretsForProject.ts b/frontend/components/utilities/secrets/getSecretsForProject.ts
index 3b63f9177..311c0c59a 100644
--- a/frontend/components/utilities/secrets/getSecretsForProject.ts
+++ b/frontend/components/utilities/secrets/getSecretsForProject.ts
@@ -39,7 +39,7 @@ const getSecretsForProject = async ({
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY');
- const tempFileState: { key: string; value: string; type: string }[] = [];
+ const tempFileState: { key: string; value: string; type: 'personal' | 'shared'; }[] = [];
if (file.key) {
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
@@ -97,7 +97,7 @@ const getSecretsForProject = async ({
} catch (error) {
console.log('Something went wrong during accessing or decripting secrets.');
}
- return true;
+ return [];
};
export default getSecretsForProject;
diff --git a/frontend/components/utilities/secrets/pushKeys.ts b/frontend/components/utilities/secrets/pushKeys.ts
index 0d570f273..7b91c0b31 100644
--- a/frontend/components/utilities/secrets/pushKeys.ts
+++ b/frontend/components/utilities/secrets/pushKeys.ts
@@ -51,7 +51,7 @@ const pushKeys = async({ obj, workspaceId, env }: { obj: object; workspaceId: st
iv: ivKey,
tag: tagKey,
} = encryptSymmetric({
- plaintext: key,
+ plaintext: key.slice(1),
key: randomBytes,
});
@@ -65,13 +65,13 @@ const pushKeys = async({ obj, workspaceId, env }: { obj: object; workspaceId: st
key: randomBytes,
});
- const visibility = obj[key as keyof typeof obj][1] != null ? obj[key as keyof typeof obj][1] : "personal";
+ const visibility = key.charAt(0) == "p" ? "personal" : "shared";
return {
ciphertextKey,
ivKey,
tagKey,
- hashKey: crypto.createHash("sha256").update(key).digest("hex"),
+ hashKey: crypto.createHash("sha256").update(key.slice(1)).digest("hex"),
ciphertextValue,
ivValue,
tagValue,
diff --git a/frontend/ee/components/SecretVersionList.tsx b/frontend/ee/components/SecretVersionList.tsx
new file mode 100644
index 000000000..a2147c2af
--- /dev/null
+++ b/frontend/ee/components/SecretVersionList.tsx
@@ -0,0 +1,44 @@
+import { useState } from 'react';
+import { faCircle, faDotCircle } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+interface SecretVersionListProps {}
+
+const versionData = [{
+ value: "Value1",
+ date: "Date1",
+ user: "vlad@infisical.com"
+}, {
+ value: "Value2",
+ date: "Date2",
+ user: "tony@infisical.com"
+}]
+
+/**
+ * @returns a list of the versions for a specific secret
+ */
+const SecretVersionList = () => {
+ return
+
Version History
+
+
+ {versionData.map((version, index) =>
+
+
+
+
{version.date}
+
+
Updated by:{version.user}
+
+
+ )}
+
+
+
+};
+
+export default SecretVersionList;
diff --git a/frontend/pages/dashboard.js b/frontend/pages/dashboard.js
index 5954a9db2..e183347aa 100644
--- a/frontend/pages/dashboard.js
+++ b/frontend/pages/dashboard.js
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import { useEffect } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].tsx
similarity index 50%
rename from frontend/pages/dashboard/[id].js
rename to frontend/pages/dashboard/[id].tsx
index 36f5eb3f2..2535a47ab 100644
--- a/frontend/pages/dashboard/[id].js
+++ b/frontend/pages/dashboard/[id].tsx
@@ -1,4 +1,4 @@
-import React, { Fragment, useCallback, useEffect, useState } from 'react';
+import { Fragment, useCallback, useEffect, useState } from 'react';
import Head from 'next/head';
import Image from 'next/image';
import { useRouter } from 'next/router';
@@ -6,208 +6,68 @@ import {
faArrowDownAZ,
faArrowDownZA,
faCheck,
- faCircleInfo,
faCopy,
faDownload,
- faEllipsis,
faEye,
faEyeSlash,
faFolderOpen,
faMagnifyingGlass,
- faPeopleGroup,
- faPerson,
faPlus,
- faShuffle,
- faX
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Menu, Transition } from '@headlessui/react';
import Button from '~/components/basic/buttons/Button';
import ListBox from '~/components/basic/Listbox';
import BottonRightPopup from '~/components/basic/popups/BottomRightPopup';
import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider';
-import DashboardInputField from '~/components/dashboard/DashboardInputField';
import DropZone from '~/components/dashboard/DropZone';
+import KeyPair from '~/components/dashboard/KeyPair';
+import SideBar from '~/components/dashboard/SideBar';
import NavHeader from '~/components/navigation/NavHeader';
import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject';
import pushKeys from '~/components/utilities/secrets/pushKeys';
-import pushKeysIntegration from '~/components/utilities/secrets/pushKeysIntegration';
import guidGenerator from '~/utilities/randomId';
import { envMapping } from '../../public/data/frequentConstants';
-import getWorkspaceIntegrations from '../api/integrations/getWorkspaceIntegrations';
import getUser from '../api/user/getUser';
import checkUserAction from '../api/userActions/checkUserAction';
import registerUserAction from '../api/userActions/registerUserAction';
import getWorkspaces from '../api/workspace/getWorkspaces';
-/**
- * This component represent a single row for an environemnt variable on the dashboard
- * @param {object} obj
- * @param {String[]} obj.keyPair - data related to the environment variable (id, pos, key, value, public/private)
- * @param {function} obj.deleteRow - a function to delete a certain keyPair
- * @param {function} obj.modifyKey - modify the key of a certain environment variable
- * @param {function} obj.modifyValue - modify the value of a certain environment variable
- * @param {function} obj.modifyVisibility - switch between public/private visibility
- * @param {boolean} obj.isBlurred - if the blurring setting is turned on
- * @param {string[]} obj.duplicates - list of all the duplicates secret names on the dashboard
- * @returns
- */
-const KeyPair = ({
- keyPair,
- deleteRow,
- modifyKey,
- modifyValue,
- modifyVisibility,
- isBlurred,
- duplicates
-}) => {
- const [randomStringLength, setRandomStringLength] = useState(32);
- return (
-
-
-
-
-
-
-
-
-
-
- );
-};
+interface SecretDataProps {
+ type: 'personal' | 'shared';
+ pos: number;
+ key: string;
+ value: string;
+ id: string;
+}
+
+/**
+ * this function finds the teh duplicates in an array
+ * @param arr - array of anything (e.g., with secret keys and types (personal/shared))
+ * @returns - a list with duplicates
+ */
+function findDuplicates(arr: any[]) {
+ const map = new Map();
+ return arr.filter((item) => {
+ if (map.has(item)) {
+ map.set(item, false);
+ return true;
+ } else {
+ map.set(item, true);
+ return false;
+ }
+ });
+}
/**
* This is the main component for the dashboard (aka the screen with all the encironemnt variable & secrets)
* @returns
*/
export default function Dashboard() {
- const [data, setData] = useState();
- const [fileState, setFileState] = useState([]);
+ const [data, setData] = useState
();
+ const [fileState, setFileState] = useState([]);
const [buttonReady, setButtonReady] = useState(false);
const router = useRouter();
const [workspaceId, setWorkspaceId] = useState('');
@@ -227,6 +87,8 @@ export default function Dashboard() {
const [sortMethod, setSortMethod] = useState('alphabetical');
const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false);
const [hasUserEverPushed, setHasUserEverPushed] = useState(false);
+ const [sidebarSecretId, toggleSidebar] = useState("None");
+ const [sharedToHide, setSharedToHide] = useState([]);
const { createNotification } = useNotificationContext();
@@ -249,7 +111,7 @@ export default function Dashboard() {
useEffect(() => {
const warningText =
'Do you want to save your results before leaving this page?';
- const handleWindowClose = (e) => {
+ const handleWindowClose = (e: any) => {
if (!buttonReady) return;
e.preventDefault();
return (e.returnValue = warningText);
@@ -265,18 +127,18 @@ export default function Dashboard() {
/**
* Reorder rows alphabetically or in the opprosite order
*/
- const reorderRows = (dataToReorder) => {
+ const reorderRows = (dataToReorder: SecretDataProps[] | 1) => {
setSortMethod((prevSort) =>
prevSort == 'alphabetical' ? '-alphabetical' : 'alphabetical'
);
- sortValuesHandler(dataToReorder);
+ sortValuesHandler(dataToReorder, undefined);
};
useEffect(() => {
(async () => {
try {
- let userWorkspaces = await getWorkspaces();
+ const userWorkspaces = await getWorkspaces();
const listWorkspaces = userWorkspaces.map((workspace) => workspace._id);
if (
!listWorkspaces.includes(router.asPath.split('/')[2].split('?')[0])
@@ -288,31 +150,41 @@ export default function Dashboard() {
router.push(router.asPath.split('?')[0] + '?' + env);
}
setBlurred(true);
- setWorkspaceId(router.query.id);
+ setWorkspaceId(String(router.query.id));
const dataToSort = await getSecretsForProject({
env,
setFileState,
setIsKeyAvailable,
setData,
- workspaceId: router.query.id
+ workspaceId: String(router.query.id)
});
reorderRows(dataToSort);
+ setSharedToHide(
+ dataToSort?.filter(row => (dataToSort
+ ?.map((item) => item.key)
+ .filter(
+ (item, index) =>
+ index !==
+ dataToSort?.map((item) => item.key).indexOf(item)
+ ).includes(row.key) && row.type == 'shared'))?.map((item) => item.id)
+ )
+
const user = await getUser();
setIsNew(
- (Date.parse(new Date()) - Date.parse(user.createdAt)) / 60000 < 3
+ (Date.parse(String(new Date())) - Date.parse(user.createdAt)) / 60000 < 3
? true
: false
);
- let userAction = await checkUserAction({
+ const userAction = await checkUserAction({
action: 'first_time_secrets_pushed'
});
setHasUserEverPushed(userAction ? true : false);
} catch (error) {
console.log('Error', error);
- setData([]);
+ setData(undefined);
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -321,10 +193,10 @@ export default function Dashboard() {
const addRow = () => {
setIsNew(false);
setData([
- ...data,
+ ...data!,
{
id: guidGenerator(),
- pos: data.length,
+ pos: data!.length,
key: '',
value: '',
type: 'shared'
@@ -332,45 +204,85 @@ export default function Dashboard() {
]);
};
- const deleteRow = (id) => {
- setButtonReady(true);
- setData(data.filter((row) => row.id !== id));
+ interface overrideProps {
+ id: string;
+ keyName: string;
+ value: string;
+ pos: number;
+ }
+
+ /**
+ * This function add an ovverrided version of a certain secret to the current user
+ * @param {object} obj
+ * @param {string} obj.id - if of this secret that is about to be overriden
+ * @param {string} obj.keyName - key name of this secret
+ * @param {string} obj.value - value of this secret
+ * @param {string} obj.pos - position of this secret on the dashboard
+ */
+ const addOverride = ({ id, keyName, value, pos }: overrideProps) => {
+ setIsNew(false);
+ const tempdata: SecretDataProps[] | 1 = [
+ ...data!,
+ {
+ id: id,
+ pos: pos,
+ key: keyName,
+ value: value,
+ type: 'personal'
+ }
+ ];
+ sortValuesHandler(tempdata, sortMethod == "alhpabetical" ? "-alphabetical" : "alphabetical");
};
- const modifyValue = (value, pos) => {
+ const deleteRow = (id: string) => {
+ setButtonReady(true);
+ setData(data!.filter((row: SecretDataProps) => row.id !== id));
+ };
+
+ /**
+ * This function deleted the override of a certain secrer
+ * @param {string} id - id of a secret to be deleted
+ */
+ const deleteOverride = (id: string) => {
+ setButtonReady(true);
+ const tempData = data!.filter((row: SecretDataProps) => !(row.id == id && row.type == 'personal'))
+ sortValuesHandler(tempData, sortMethod == "alhpabetical" ? "-alphabetical" : "alphabetical")
+ };
+
+ const modifyValue = (value: string, pos: number) => {
setData((oldData) => {
- oldData[pos].value = value;
- return [...oldData];
+ oldData![pos].value = value;
+ return [...oldData!];
});
setButtonReady(true);
};
- const modifyKey = (value, pos) => {
+ const modifyKey = (value: string, pos: number) => {
setData((oldData) => {
- oldData[pos].key = value;
- return [...oldData];
+ oldData![pos].key = value;
+ return [...oldData!];
});
setButtonReady(true);
};
- const modifyVisibility = (value, pos) => {
+ const modifyVisibility = (value: "shared" | "personal", pos: number) => {
setData((oldData) => {
- oldData[pos].type = value;
- return [...oldData];
+ oldData![pos].type = value;
+ return [...oldData!];
});
setButtonReady(true);
};
// For speed purposes and better perforamance, we are using useCallback
- const listenChangeValue = useCallback((value, pos) => {
+ const listenChangeValue = useCallback((value: string, pos: number) => {
modifyValue(value, pos);
}, []);
- const listenChangeKey = useCallback((value, pos) => {
+ const listenChangeKey = useCallback((value: string, pos: number) => {
modifyKey(value, pos);
}, []);
- const listenChangeVisibility = useCallback((value, pos) => {
+ const listenChangeVisibility = useCallback((value: "shared" | "personal", pos: number) => {
modifyVisibility(value, pos);
}, []);
@@ -379,21 +291,16 @@ export default function Dashboard() {
*/
const savePush = async () => {
// Format the new object with environment variables
- let obj = Object.assign(
+ const obj = Object.assign(
{},
- ...data.map((row) => ({ [row.key]: [row.value, row.type] }))
+ ...data!.map((row: SecretDataProps) => ({ [row.type.charAt(0) + row.key]: [row.value, row.type] }))
);
// Checking if any of the secret keys start with a number - if so, don't do anything
const nameErrors = !Object.keys(obj)
- .map((key) => !isNaN(key.charAt(0)))
+ .map((key) => !isNaN(Number(key[0].charAt(0))))
.every((v) => v === false);
- const duplicatesExist =
- data
- ?.map((item) => item.key)
- .filter(
- (item, index) => index !== data?.map((item) => item.key).indexOf(item)
- ).length > 0;
+ const duplicatesExist = findDuplicates(data!.map((item: SecretDataProps) => item.key + item.type)).length > 0;
if (nameErrors) {
return createNotification({
@@ -409,9 +316,11 @@ export default function Dashboard() {
});
}
+ console.log('pushing', obj)
+
// Once "Save changed is clicked", disable that button
setButtonReady(false);
- pushKeys({ obj, workspaceId: router.query.id, env });
+ pushKeys({ obj, workspaceId: String(router.query.id), env });
// If this user has never saved environment variables before, show them a prompt to read docs
if (!hasUserEverPushed) {
@@ -420,8 +329,8 @@ export default function Dashboard() {
}
};
- const addData = (newData) => {
- setData(data.concat(newData));
+ const addData = (newData: SecretDataProps[]) => {
+ setData(data!.concat(newData));
setButtonReady(true);
};
@@ -429,37 +338,39 @@ export default function Dashboard() {
setBlurred(!blurred);
};
- const sortValuesHandler = (dataToSort) => {
- const sortedData = (dataToSort != 1 ? dataToSort : data)
- .sort((a, b) =>
- sortMethod == 'alphabetical'
- ? a.key.localeCompare(b.key)
- : b.key.localeCompare(a.key)
- )
- .map((item, index) => {
- return {
- ...item,
- pos: index
- };
- });
+ const sortValuesHandler = (dataToSort: SecretDataProps[] | 1, specificSortMethod?: 'alphabetical' | '-alphabetical') => {
+ const howToSort = specificSortMethod == undefined ? sortMethod : specificSortMethod;
+ const sortedData = (dataToSort != 1 ? dataToSort : data)!
+ .sort((a, b) =>
+ howToSort == 'alphabetical'
+ ? a.key.localeCompare(b.key)
+ : b.key.localeCompare(a.key)
+ )
+ .map((item: SecretDataProps, index: number) => {
+ return {
+ ...item,
+ pos: index
+ };
+ });
+ console.log('override', sortedData)
setData(sortedData);
};
// This function downloads the secrets as a .env file
const download = () => {
- const file = data
- .map((item) => [item.key, item.value].join('='))
+ const file = data!
+ .map((item: SecretDataProps) => [item.key, item.value].join('='))
.join('\n');
const blob = new Blob([file]);
const fileDownloadUrl = URL.createObjectURL(blob);
- let alink = document.createElement('a');
+ const alink = document.createElement('a');
alink.href = fileDownloadUrl;
alink.download = envMapping[env] + '.env';
alink.click();
};
- const deleteCertainRow = (id) => {
+ const deleteCertainRow = (id: string) => {
deleteRow(id);
};
@@ -467,15 +378,17 @@ export default function Dashboard() {
* This function copies the project id to the clipboard
*/
function copyToClipboard() {
- var copyText = document.getElementById('myInput');
+ const copyText = document.getElementById('myInput') as HTMLInputElement;
+
+ if (copyText) {
+ copyText.select();
+ copyText.setSelectionRange(0, 99999); // For mobile devices
- copyText.select();
- copyText.setSelectionRange(0, 99999); // For mobile devices
-
- navigator.clipboard.writeText(copyText.value);
-
- setProjectIdCopied(true);
- setTimeout(() => setProjectIdCopied(false), 2000);
+ navigator.clipboard.writeText(copyText.value);
+
+ setProjectIdCopied(true);
+ setTimeout(() => setProjectIdCopied(false), 2000);
+ }
}
return data ? (
@@ -491,6 +404,18 @@ export default function Dashboard() {
/>
+ {sidebarSecretId != "None" &&
row.id == sidebarSecretId)}
+ modifyKey={listenChangeKey}
+ modifyValue={listenChangeValue}
+ addOverride={addOverride}
+ deleteOverride={deleteOverride}
+ buttonReady={buttonReady}
+ savePush={savePush}
+ sharedToHide={sharedToHide}
+ setSharedToHide={setSharedToHide}
+ />}
{checkDocsPopUpVisible && (
@@ -513,7 +438,6 @@ export default function Dashboard() {
data={['Development', 'Staging', 'Production', 'Testing']}
// ref={useRef(123)}
onChange={setEnv}
- className="z-40"
/>
)}
@@ -568,7 +492,6 @@ export default function Dashboard() {
data={['Development', 'Staging', 'Production', 'Testing']}
// ref={useRef(123)}
onChange={setEnv}
- className="z-40"
/>
{data?.length !== 0 ? (
-
-
-
- {/*
*/}
-
-
Personal
-
-
-
- Personal keys are only visible to you
-
-
-
-
-
- {data
- .filter(
- (keyPair) =>
- keyPair.key
- .toLowerCase()
- .includes(searchKeys.toLowerCase()) &&
- keyPair.type == 'personal'
- )
- ?.map((keyPair) => (
-
+
+
+
+ {data?.filter(row => !(sharedToHide.includes(row.id) && row.type == 'shared')).map((keyPair) => (
+ item.key)
- .filter(
- (item, index) =>
- index !==
- data?.map((item) => item.key).indexOf(item)
- )}
+ isDuplicate={findDuplicates(data?.map((item) => item.key + item.type))?.includes(keyPair.key + keyPair.type)}
+ toggleSidebar={toggleSidebar}
+ sidebarSecretId={sidebarSecretId}
/>
))}
-
-
-
8 ? 'h-3/4' : 'h-min'
- }`}
- >
-
- {/*
*/}
-
-
Shared
-
-
-
- Shared keys are visible to your whole team
-
-
+
+
+
-
- {data
- .filter(
- (keyPair) =>
- keyPair.key
- .toLowerCase()
- .includes(searchKeys.toLowerCase()) &&
- keyPair.type == 'shared'
- )
- ?.map((keyPair) => (
- item.key)
- .filter(
- (item, index) =>
- index !==
- data?.map((item) => item.key).indexOf(item)
- )}
- />
- ))}
-
-
-
-
) : (
- {fileState.message != "There's nothing to pull" &&
- fileState.message != undefined && (
-
- )}
- {(fileState.message == "There's nothing to pull" ||
- fileState.message == undefined) &&
- isKeyAvailable && (
-
- )}
- {fileState.message ==
- 'Failed membership validation for workspace' && (
-
You are not authorized to view this project.
+ {isKeyAvailable && (
+
)}
- {fileState.message == 'Access needed to pull the latest file' ||
+ {
+ // fileState.message == 'Access needed to pull the latest file' ||
(!isKeyAvailable && (
<>
{
+ if (!email || !password) {
+ return;
+ }
+
setIsLoading(true);
await attemptLogin(
email,
@@ -45,7 +49,7 @@ export default function Login() {
setErrorLogin,
router,
false,
- true
+ true,
).then(() => {
setTimeout(function () {
setIsLoading(false);
@@ -75,68 +79,73 @@ export default function Login() {
/>
-
-
- Log in to your account
-
-
-
-
-
-
-
- Forgot password?
-
-
- {errorLogin &&
}
-
-
-
);
}
diff --git a/frontend/pages/netlify.js b/frontend/pages/netlify.js
index 6907d6db4..fc58042d5 100644
--- a/frontend/pages/netlify.js
+++ b/frontend/pages/netlify.js
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import { useEffect } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
const queryString = require("query-string");
diff --git a/frontend/pages/password-reset.tsx b/frontend/pages/password-reset.tsx
index a09b85ab0..45d17d194 100644
--- a/frontend/pages/password-reset.tsx
+++ b/frontend/pages/password-reset.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { faCheck, faX } from '@fortawesome/free-solid-svg-icons';
diff --git a/frontend/pages/settings/billing/[id].js b/frontend/pages/settings/billing/[id].js
index 00d1db23f..485dfab8d 100644
--- a/frontend/pages/settings/billing/[id].js
+++ b/frontend/pages/settings/billing/[id].js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import { useEffect, useState } from "react";
import Head from "next/head";
import Plan from "~/components/billing/Plan";
diff --git a/frontend/pages/settings/org/[id].js b/frontend/pages/settings/org/[id].js
index 80f6efc5d..c54e8e193 100644
--- a/frontend/pages/settings/org/[id].js
+++ b/frontend/pages/settings/org/[id].js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import Head from 'next/head';
import { useRouter } from 'next/router';
import {
diff --git a/frontend/pages/settings/personal/[id].js b/frontend/pages/settings/personal/[id].js
index aa497bbfd..60dcba1be 100644
--- a/frontend/pages/settings/personal/[id].js
+++ b/frontend/pages/settings/personal/[id].js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import { useEffect, useState } from "react";
import Head from "next/head";
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
diff --git a/frontend/pages/settings/project/[id].js b/frontend/pages/settings/project/[id].js
index ec4864919..64ea96093 100644
--- a/frontend/pages/settings/project/[id].js
+++ b/frontend/pages/settings/project/[id].js
@@ -1,4 +1,4 @@
-import React, { useEffect, useRef, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
import { faCheck, faPlus } from "@fortawesome/free-solid-svg-icons";
diff --git a/frontend/pages/signup.tsx b/frontend/pages/signup.tsx
index a5e17a8c5..e1a50406c 100644
--- a/frontend/pages/signup.tsx
+++ b/frontend/pages/signup.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import ReactCodeInput from 'react-code-input';
import Head from 'next/head';
import Image from 'next/image';
@@ -260,46 +260,49 @@ export default function SignUp() {
// Step 1 of the sign up process (enter the email or choose google authentication)
const step1 = (
-
-
- {'Let\''}s get started
-
-
+
+
+
+ {'Let\''}s get started
+
+
+
+
+ {/*
+
+
I do not want to receive emails about Infisical and its products.
+
*/}
+
+
+ By creating an account, you agree to our Terms and have read and
+ acknowledged the Privacy Policy.
+
+
+
+
+
+
+
-
-
+
+
Have an account? Log in
-
-
-
- {/*
-
-
I do not want to receive emails about Infisical and its products.
-
*/}
-
-
- By creating an account, you agree to our Terms and have read and
- acknowledged the Privacy Policy.
-
-
-
-
-
+
);
// Step 2 of the signup process (enter the email verification code)
@@ -340,11 +343,11 @@ export default function SignUp() {
-
+
Not seeing an email?
-
+
{isResendingVerificationEmail ? 'Resending...' : 'Resend'}
@@ -512,7 +515,7 @@ export default function SignUp() {
It contains your Secret Key which we cannot access or recover for you if
you lose it.
-
+
{
@@ -521,11 +524,9 @@ export default function SignUp() {
password,
personalName: firstName + ' ' + lastName,
setBackupKeyError,
- setBackupKeyIssued,
+ setBackupKeyIssued
});
- const userWorkspaces = await getWorkspaces();
- const userWorkspace = userWorkspaces[0]._id;
- router.push('/home/' + userWorkspace);
+ router.push('/dashboard/');
}}
size="lg"
/>
@@ -571,7 +572,9 @@ export default function SignUp() {
/>
- {step == 1 ? step1 : step == 2 ? step2 : step == 3 ? step3 : step4}
+
);
diff --git a/frontend/pages/signupinvite.js b/frontend/pages/signupinvite.js
index a41010aea..7686161a2 100644
--- a/frontend/pages/signupinvite.js
+++ b/frontend/pages/signupinvite.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
diff --git a/frontend/pages/users/[id].js b/frontend/pages/users/[id].js
index fe96ded3a..c1739b0a9 100644
--- a/frontend/pages/users/[id].js
+++ b/frontend/pages/users/[id].js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import Head from 'next/head';
import Image from 'next/image';
import { useRouter } from 'next/router';
diff --git a/frontend/pages/vercel.js b/frontend/pages/vercel.js
index adfffe77e..7b15769b1 100644
--- a/frontend/pages/vercel.js
+++ b/frontend/pages/vercel.js
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import { useEffect } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
const queryString = require("query-string");
diff --git a/frontend/pages/verify-email.tsx b/frontend/pages/verify-email.tsx
index 7dfc1427e..ae2c9fff1 100644
--- a/frontend/pages/verify-email.tsx
+++ b/frontend/pages/verify-email.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';