From 092436b6a3e0eab86a9108b5c9b83f092395b8f7 Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Thu, 22 Dec 2022 14:15:12 -0500 Subject: [PATCH 01/11] Finished the first ddraft of the dashboard sidebar --- frontend/components/basic/Toggle.tsx | 28 +++++ frontend/components/basic/buttons/Button.tsx | 2 +- .../dashboard/GenerateSecretMenu.tsx | 93 ++++++++++++++ frontend/components/dashboard/SideBar.tsx | 84 +++++++++++++ frontend/pages/dashboard/[id].js | 115 ++---------------- 5 files changed, 216 insertions(+), 106 deletions(-) create mode 100644 frontend/components/basic/Toggle.tsx create mode 100644 frontend/components/dashboard/GenerateSecretMenu.tsx create mode 100644 frontend/components/dashboard/SideBar.tsx diff --git a/frontend/components/basic/Toggle.tsx b/frontend/components/basic/Toggle.tsx new file mode 100644 index 0000000000..c2cf3cb079 --- /dev/null +++ b/frontend/components/basic/Toggle.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { Switch } from "@headlessui/react"; + +/** + * This is a typical 'iPhone' toggle (e.g., user for overriding secrets with personal values) + * @param obj + * @param {boolean} obj.enabled - whether the toggle is turned on or off + * @param {function} obj.setEnabled - change the state of the toggle + * @returns + */ +export default function Toggle ({ enabled, setEnabled }: { enabled: boolean; setEnabled: (value: boolean) => void; }): JSX.Element { + return ( + + Enable notifications + + + ) +} diff --git a/frontend/components/basic/buttons/Button.tsx b/frontend/components/basic/buttons/Button.tsx index 562a82a36f..f8bd1941df 100644 --- a/frontend/components/basic/buttons/Button.tsx +++ b/frontend/components/basic/buttons/Button.tsx @@ -80,7 +80,7 @@ export default function Button(props: ButtonProps): JSX.Element { ); const textStyle = classNames( - "relative duration-200", + "relative duration-200 text-center w-full", // Show the loading sign if the loading indicator is on props.loading ? "opacity-0" : "opacity-100", diff --git a/frontend/components/dashboard/GenerateSecretMenu.tsx b/frontend/components/dashboard/GenerateSecretMenu.tsx new file mode 100644 index 0000000000..1d71749e52 --- /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 = () => { + const [randomStringLength, setRandomStringLength] = useState(32); + + return +
+ +
+ +
+
+
+ + +
{ + if (randomStringLength > 32) { + setRandomStringLength(32); + } else if (randomStringLength < 2) { + setRandomStringLength(2); + } else { + // modifyValue( + // [...Array(randomStringLength)] + // .map(() => Math.floor(Math.random() * 16).toString(16)) + // .join(''), + // keyPair.pos + // ); + } + }} + className="relative flex flex-row 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" + > + +
+

Generate Random Hex

+

digits

+
+
+
+
{ + if (randomStringLength > 1) { + setRandomStringLength(randomStringLength - 1); + } + }} + > + - +
+ + setRandomStringLength(parseInt(e.target.value)) + } + value={randomStringLength} + className="text-center z-20 peer text-sm bg-transparent w-full outline-none" + spellCheck="false" + /> +
{ + if (randomStringLength < 32) { + setRandomStringLength(randomStringLength + 1); + } + }} + > + + +
+
+
+
+
+} + +export default GenerateSecretMenu; diff --git a/frontend/components/dashboard/SideBar.tsx b/frontend/components/dashboard/SideBar.tsx new file mode 100644 index 0000000000..11f756ccbd --- /dev/null +++ b/frontend/components/dashboard/SideBar.tsx @@ -0,0 +1,84 @@ +import { useState } from 'react'; +import { faX } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '../basic/buttons/Button'; +import Toggle from '../basic/Toggle'; +import DashboardInputField from './DashboardInputField'; +import GenerateSecretMenu from './GenerateSecretMenu'; + +/** + * @returns the sidebar with 'secret's settings' + */ +const SideBar = () => { + const [overrideEnabled, setOverrideEnabled] = useState(false) + + return
+
+
+

Secret

+ +
+
+

Key

+ {}} + type="varName" + position={1} + value={"KeyKeyKey"} + duplicates={[]} + blurred={false} + /> +
+
+

Value

+ {}} + type="value" + position={1} + value={"ValueValueValue"} + duplicates={[]} + blurred={true} + /> +
+ +
+
+
+
+

Override value with a personal value

+ +
+
+ {}} + type="value" + position={1} + value={"ValueValueValue"} + duplicates={[]} + blurred={true} + /> +
+ +
+
+
+

Comments & notes

+
+ Leave your comment here... +
+
+
+
+
+
+
+}; + +export default SideBar; diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js index 36f5eb3f24..db1f4a746b 100644 --- a/frontend/pages/dashboard/[id].js +++ b/frontend/pages/dashboard/[id].js @@ -1,4 +1,4 @@ -import React, { Fragment, useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import Head from 'next/head'; import Image from 'next/image'; import { useRouter } from 'next/router'; @@ -14,14 +14,10 @@ import { 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'; @@ -29,14 +25,13 @@ 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 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'; @@ -63,7 +58,6 @@ const KeyPair = ({ isBlurred, duplicates }) => { - const [randomStringLength, setRandomStringLength] = useState(32); return (
@@ -90,103 +84,12 @@ const KeyPair = ({ />
- -
- -
- -
-
-
- - -
- modifyVisibility( - keyPair.type == 'personal' ? 'shared' : 'personal', - keyPair.pos - ) - } - 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" - > - -
- {keyPair.type == 'personal' ? 'Make Shared' : 'Make Personal'} -
-
-
{ - if (randomStringLength > 32) { - setRandomStringLength(32); - } else if (randomStringLength < 2) { - setRandomStringLength(2); - } else { - modifyValue( - [...Array(randomStringLength)] - .map(() => Math.floor(Math.random() * 16).toString(16)) - .join(''), - keyPair.pos - ); - } - }} - className="relative flex flex-row 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" - > - -
-

Generate Random Hex

-

digits

-
-
-
-
{ - if (randomStringLength > 1) { - setRandomStringLength(randomStringLength - 1); - } - }} - > - - -
- - setRandomStringLength(parseInt(e.target.value)) - } - value={randomStringLength} - className="text-center z-20 peer text-sm bg-transparent w-full outline-none" - spellCheck="false" - /> -
{ - if (randomStringLength < 32) { - setRandomStringLength(randomStringLength + 1); - } - }} - > - + -
-
-
-
-
+
+ +
-
+
{data .filter( (keyPair) => @@ -582,6 +590,8 @@ export default function Dashboard() { index !== data?.map((item) => item.key).indexOf(item) )} + toggleSidebar={toggleSidebar} + sidebarSecretNumber={sidebarSecretNumber} /> ))}
@@ -631,6 +641,8 @@ export default function Dashboard() { index !== data?.map((item) => item.key).indexOf(item) )} + toggleSidebar={toggleSidebar} + sidebarSecretNumber={sidebarSecretNumber} /> ))}
From 205bf70861e7f4311ef761caba076ca0f6108a14 Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Fri, 23 Dec 2022 23:00:26 -0500 Subject: [PATCH 03/11] Added overrides for secrets --- frontend/components/basic/Toggle.tsx | 31 +++- .../dashboard/DashboardInputField.tsx | 12 +- frontend/components/dashboard/SideBar.tsx | 90 ++++++++-- frontend/pages/dashboard/[id].js | 167 +++++++----------- 4 files changed, 183 insertions(+), 117 deletions(-) diff --git a/frontend/components/basic/Toggle.tsx b/frontend/components/basic/Toggle.tsx index c2cf3cb079..6a32d588aa 100644 --- a/frontend/components/basic/Toggle.tsx +++ b/frontend/components/basic/Toggle.tsx @@ -1,6 +1,25 @@ import React from "react"; import { Switch } from "@headlessui/react"; + +interface OverrideProps { + id: string; + keyName: string; + value: string; + pos: number; +} + +interface ToggleProps { + enabled: boolean; + setEnabled: (value: boolean) => void; + addOverride: (value: OverrideProps) => void; + keyName: string; + value: string; + pos: number; + id: string; + deleteOverride: (id: string) => void; +} + /** * This is a typical 'iPhone' toggle (e.g., user for overriding secrets with personal values) * @param obj @@ -8,11 +27,19 @@ import { Switch } from "@headlessui/react"; * @param {function} obj.setEnabled - change the state of the toggle * @returns */ -export default function Toggle ({ enabled, setEnabled }: { enabled: boolean; setEnabled: (value: boolean) => void; }): JSX.Element { +export default function Toggle ({ enabled, setEnabled, addOverride, keyName, value, pos, id, deleteOverride }: ToggleProps): JSX.Element { + console.log(755, pos, enabled) return ( { + if (enabled == false) { + addOverride({ id, keyName, value, pos }); + } else { + deleteOverride(id); + } + setEnabled(!enabled); + }} className={`${ enabled ? 'bg-primary' : 'bg-bunker-400' } relative inline-flex h-5 w-9 items-center rounded-full`} diff --git a/frontend/components/dashboard/DashboardInputField.tsx b/frontend/components/dashboard/DashboardInputField.tsx index cb75dcf8c6..3a5cd80ee4 100644 --- a/frontend/components/dashboard/DashboardInputField.tsx +++ b/frontend/components/dashboard/DashboardInputField.tsx @@ -13,6 +13,7 @@ interface DashboardInputFieldProps { type: 'varName' | 'value'; blurred: boolean; duplicates: string[]; + override?: boolean; } /** @@ -33,7 +34,8 @@ const DashboardInputField = ({ type, value, blurred, - duplicates + duplicates, + override }: DashboardInputFieldProps) => { const ref = useRef(null); const syncScroll = (e: SyntheticEvent) => { @@ -85,6 +87,7 @@ const DashboardInputField = ({
+ {override == true &&
Override enabled
} onChangeHandler(e.target.value, position)} @@ -99,10 +102,13 @@ const DashboardInputField = ({
{value.split(REGEX).map((word, id) => { if (word.match(REGEX) !== null) { diff --git a/frontend/components/dashboard/SideBar.tsx b/frontend/components/dashboard/SideBar.tsx index 5e77e7d75f..38f575c6b9 100644 --- a/frontend/components/dashboard/SideBar.tsx +++ b/frontend/components/dashboard/SideBar.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { faX } from '@fortawesome/free-solid-svg-icons'; +import { faBackward, faDotCircle, faRotateLeft, faX } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import Button from '../basic/buttons/Button'; @@ -13,7 +13,14 @@ interface SecretProps { key: string; value: string; pos: number; - visibility: string; + id: string; +} + +interface OverrideProps { + id: string; + keyName: string; + value: string; + pos: number; } interface SideBarProps { @@ -22,6 +29,8 @@ interface SideBarProps { modifyKey: (value: string) => void; modifyValue: (value: string) => void; modifyVisibility: (value: string) => void; + addOverride: (value: OverrideProps) => void; + deleteOverride: (id: string) => void; } /** @@ -33,7 +42,7 @@ interface SideBarProps { * @param {function} obj.modifyVisibility - function that modifies the secret visibility * @returns the sidebar with 'secret's settings' */ -const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility }: SideBarProps) => { +const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility, addOverride, deleteOverride }: SideBarProps) => { const [overrideEnabled, setOverrideEnabled] = useState(false); return
@@ -44,7 +53,7 @@ const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility
-
+

Key

-
+

Override value with a personal value

- +
@@ -97,9 +115,57 @@ const SideBar = ({ toggleSidebar, data, modifyKey, modifyValue, modifyVisibility isFull={true} />
-
-

Comments & notes

-
+
+

Version History

+
+
+
+
+
+
+
+
+
Current
+

Key:{data[0].key}

+

Value:{data[0].value}

+

Visibility:{'shared'}

+
+
+
+
+
+
+
+
+
12/22/2022 12:36 EST
+
Key: KeyKeyKey
+
Value: ValueValueValue
+

Visibility:{'shared'}

+
+
+
+
+
+
+
+
+
12/21/2022 09:11 EST
+
Key: KeyKey
+
Value: ValueValue
+

Visibility:{'shared'}

+
+
+
+
+
+
+
+

Comments & notes

+
+

Coming soon!

+
+
+
Leave your comment here...
diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js index ef4db42bdc..11519578ed 100644 --- a/frontend/pages/dashboard/[id].js +++ b/frontend/pages/dashboard/[id].js @@ -6,7 +6,6 @@ import { faArrowDownAZ, faArrowDownZA, faCheck, - faCircleInfo, faCopy, faDownload, faEllipsis, @@ -83,6 +82,7 @@ const KeyPair = ({ position={keyPair.pos} value={keyPair.value} blurred={isBlurred} + override={keyPair.value == "user1234" && true} />
@@ -176,7 +176,7 @@ export default function Dashboard() { prevSort == 'alphabetical' ? '-alphabetical' : 'alphabetical' ); - sortValuesHandler(dataToReorder); + sortValuesHandler(dataToReorder, ""); }; useEffect(() => { @@ -238,11 +238,43 @@ export default function Dashboard() { ]); }; + /** + * 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 }) => { + setIsNew(false); + const tempdata = [ + ...data, + { + id: id, + pos: pos, + key: keyName, + value: value, + type: 'personal' + } + ]; + sortValuesHandler(tempdata, sortMethod == "alhpabetical" ? "-alphabetical" : "alphabetical"); + }; + const deleteRow = (id) => { setButtonReady(true); setData(data.filter((row) => 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) => { + setButtonReady(true); + setData(data.filter((row) => !(row.id == id && row.type == 'personal'))); + }; + const modifyValue = (value, pos) => { setData((oldData) => { oldData[pos].value = value; @@ -335,10 +367,11 @@ export default function Dashboard() { setBlurred(!blurred); }; - const sortValuesHandler = (dataToSort) => { + const sortValuesHandler = (dataToSort, specificSortMethod) => { + const howToSort = specificSortMethod != "" ? specificSortMethod : sortMethod const sortedData = (dataToSort != 1 ? dataToSort : data) .sort((a, b) => - sortMethod == 'alphabetical' + howToSort == 'alphabetical' ? a.key.localeCompare(b.key) : b.key.localeCompare(a.key) ) @@ -397,12 +430,14 @@ export default function Dashboard() { />
- {sidebarSecretNumber != -1 && row.pos == sidebarSecretNumber)} modifyKey={listenChangeKey} modifyValue={listenChangeValue} modifyVisibility={listenChangeVisibility} + addOverride={addOverride} + deleteOverride={deleteOverride} />}
@@ -550,101 +585,33 @@ export default function Dashboard() {
-
- {/* */} -
-

Personal

-
- - - Personal keys are only visible to you - -
-
-
-
- {data - .filter( - (keyPair) => - keyPair.key - .toLowerCase() - .includes(searchKeys.toLowerCase()) && - keyPair.type == 'personal' - ) - ?.map((keyPair) => ( - item.key) - .filter( - (item, index) => - index !== - data?.map((item) => item.key).indexOf(item) - )} - toggleSidebar={toggleSidebar} - sidebarSecretNumber={sidebarSecretNumber} - /> - ))} -
-
-
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) - )} - toggleSidebar={toggleSidebar} - sidebarSecretNumber={sidebarSecretNumber} - /> - ))} +
+ {data?.filter(row => !(data + ?.map((item) => item.key) + .filter( + (item, index) => + index !== + data?.map((item) => item.key).indexOf(item) + ).includes(row.key) && row.type == 'shared')).map((keyPair) => ( + item.key) + .filter( + (item, index) => + index !== + data?.map((item) => item.key).indexOf(item) + )} + toggleSidebar={toggleSidebar} + sidebarSecretNumber={sidebarSecretNumber} + /> + ))}
From d89af29070589eec8425998b6e847322b68eff3d Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Sun, 25 Dec 2022 00:33:37 -0500 Subject: [PATCH 04/11] Refactored dashboard to TS - still some bugs and inefficiencies --- frontend/components/basic/Toggle.tsx | 1 - frontend/components/basic/buttons/Button.tsx | 2 +- ...ttomRightPopup.js => BottomRightPopup.tsx} | 22 +- .../dashboard/DashboardInputField.tsx | 4 +- .../dashboard/GenerateSecretMenu.tsx | 14 +- frontend/components/dashboard/SideBar.tsx | 60 +++-- .../utilities/secrets/getSecretsForProject.ts | 4 +- .../components/utilities/secrets/pushKeys.ts | 6 +- .../pages/dashboard/{[id].js => [id].tsx} | 251 ++++++++++-------- 9 files changed, 211 insertions(+), 153 deletions(-) rename frontend/components/basic/popups/{BottomRightPopup.js => BottomRightPopup.tsx} (71%) rename frontend/pages/dashboard/{[id].js => [id].tsx} (76%) diff --git a/frontend/components/basic/Toggle.tsx b/frontend/components/basic/Toggle.tsx index 6a32d588aa..7702bb29ef 100644 --- a/frontend/components/basic/Toggle.tsx +++ b/frontend/components/basic/Toggle.tsx @@ -28,7 +28,6 @@ interface ToggleProps { * @returns */ export default function Toggle ({ enabled, setEnabled, addOverride, keyName, value, pos, id, deleteOverride }: ToggleProps): JSX.Element { - console.log(755, pos, enabled) return ( void; +} + /** * This is the notification that pops up at the bottom right when a user performs a certain action * @param {object} org @@ -23,16 +33,16 @@ export default function BottonRightPopup({ textLine1, textLine2, setCheckDocsPopUpVisible, -}) { +}: PopupProps): JSX.Element { return (