diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 283c69b53..7f52e04ae 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,6 +20,7 @@ "@radix-ui/react-checkbox": "^1.0.1", "@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dropdown-menu": "^2.0.2", + "@radix-ui/react-hover-card": "^1.0.3", "@radix-ui/react-label": "^2.0.0", "@radix-ui/react-popover": "^1.0.3", "@radix-ui/react-progress": "^1.0.1", @@ -3858,6 +3859,27 @@ "react-dom": "^16.8 || ^17.0 || ^18.0" } }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.3.tgz", + "integrity": "sha512-rr2+DxPlMhR57IPcNvZ85X8chytdfj7kyVToyR5Ge0r4IJEFiyPs0Cs8/K8oe5zt+yo0F8f29vtC8tNNK+ZIkA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/@radix-ui/react-id": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", @@ -25050,6 +25072,23 @@ "@radix-ui/react-use-callback-ref": "1.0.0" } }, + "@radix-ui/react-hover-card": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.3.tgz", + "integrity": "sha512-rr2+DxPlMhR57IPcNvZ85X8chytdfj7kyVToyR5Ge0r4IJEFiyPs0Cs8/K8oe5zt+yo0F8f29vtC8tNNK+ZIkA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0" + } + }, "@radix-ui/react-id": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 322e60f31..db8153a0a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "@radix-ui/react-checkbox": "^1.0.1", "@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dropdown-menu": "^2.0.2", + "@radix-ui/react-hover-card": "^1.0.3", "@radix-ui/react-label": "^2.0.0", "@radix-ui/react-popover": "^1.0.3", "@radix-ui/react-progress": "^1.0.1", diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index e02c4f474..3d840c663 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -14,7 +14,7 @@ "save-changes": "Save Changes", "saved": "Saved", "drop-zone": "Drag and drop a .env or .yml file here.", - "drop-zone-keys": "Drag and drop a .env or .yml file here to add more keys.", + "drop-zone-keys": "Drag and drop a .env or .yml file here to add more secrets.", "role": "Role", "role_admin": "admin", "display-name": "Display Name", diff --git a/frontend/src/components/basic/Listbox.tsx b/frontend/src/components/basic/Listbox.tsx index a2f08d9b9..19bdd1dd5 100644 --- a/frontend/src/components/basic/Listbox.tsx +++ b/frontend/src/components/basic/Listbox.tsx @@ -58,7 +58,7 @@ const ListBox = ({ leaveFrom="opacity-100" leaveTo="opacity-0" > - + {data.map((person, personIdx) => ( { return (
- {}}> + {}}>
void; value: string | undefined; - type: 'varName' | 'value'; + type: 'varName' | 'value' | 'comment'; blurred?: boolean; isDuplicate?: boolean; - override?: boolean; + overrideEnabled?: boolean; + modifyValueOverride?: (value: string | undefined, position: number) => void; + isSideBarOpen?: boolean; } /** @@ -26,6 +30,8 @@ interface DashboardInputFieldProps { * @param {boolean} obj.blurred - whether the input field should be blurred (behind the gray dots) or not; this can be turned on/off in the dashboard * @param {boolean} obj.isDuplicate - if the key name is duplicated * @param {boolean} obj.override - whether a secret/row should be displalyed as overriden + * + * * @returns */ @@ -36,7 +42,9 @@ const DashboardInputField = ({ value, blurred, isDuplicate, - override + overrideEnabled, + modifyValueOverride, + isSideBarOpen }: DashboardInputFieldProps) => { const ref = useRef(null); const syncScroll = (e: SyntheticEvent) => { @@ -51,41 +59,97 @@ const DashboardInputField = ({ const error = startsWithNumber || isDuplicate; return ( -
+
onChangeHandler(e.target.value.toUpperCase(), position)} type={type} value={value} - className={`z-10 peer font-mono ph-no-capture bg-bunker-800 rounded-md caret-white text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 ${ - error ? 'focus:ring-red/50' : 'focus:ring-primary/50' + className={`z-10 peer font-mono ph-no-capture bg-transparent h-full caret-bunker-200 text-sm px-2 w-full min-w-16 outline-none ${ + error ? 'text-red-600 focus:text-red-500' : 'text-bunker-300 focus:text-bunker-100' } duration-200`} spellCheck="false" />
{startsWithNumber && ( -

- Should not start with a number -

+
+ +
)} - {isDuplicate && !startsWithNumber && ( -

- Secret names should be unique -

+ {isDuplicate && value !== '' && !startsWithNumber && ( +
+ +
)} + {!error &&
+ +
} +
+ ); + } + if (type === 'comment') { + const startsWithNumber = !Number.isNaN(Number(value?.charAt(0))) && value !== ''; + const error = startsWithNumber || isDuplicate; + + return ( +
+
+ onChangeHandler(e.target.value, position)} + type={type} + value={value} + className='z-10 peer font-mono ph-no-capture bg-transparent py-2.5 caret-bunker-200 text-sm px-2 w-full min-w-16 outline-none text-bunker-300 focus:text-bunker-100 placeholder:text-bunker-400 placeholder:focus:text-transparent placeholder duration-200' + spellCheck="false" + placeholder='–' + /> +
); } if (type === 'value') { return (
-
- {override === true && ( -
+
+ {overrideEnabled === true && ( +
Override enabled
)} @@ -95,19 +159,19 @@ const DashboardInputField = ({ onScroll={syncScroll} className={`${ blurred - ? 'text-transparent group-hover:text-transparent focus:text-transparent active:text-transparent' + ? 'text-transparent focus:text-transparent active:text-transparent' : '' - } z-10 peer font-mono ph-no-capture bg-transparent rounded-md caret-white text-transparent text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 focus:ring-primary/50 duration-200 no-scrollbar no-scrollbar::-webkit-scrollbar`} + } z-10 peer font-mono ph-no-capture bg-transparent caret-white text-transparent text-sm px-2 py-2 w-full min-w-16 outline-none duration-200 no-scrollbar no-scrollbar::-webkit-scrollbar`} spellCheck="false" />
{value?.split(REGEX).map((word, id) => { if (word.match(REGEX) !== null) { @@ -137,7 +201,9 @@ const DashboardInputField = ({ })}
{blurred && ( -
+
{value?.split('').map(() => ( ))} + {value?.split('').length === 0 && EMPTY}
+
)}
@@ -163,8 +231,8 @@ function inputPropsAreEqual(prev: DashboardInputFieldProps, next: DashboardInput prev.type === next.type && prev.position === next.position && prev.blurred === next.blurred && - prev.override === next.override && - prev.isDuplicate === next.isDuplicate + prev.overrideEnabled === next.overrideEnabled && + prev.isDuplicate === next.isDuplicate ); } diff --git a/frontend/src/components/dashboard/DeleteActionButton.tsx b/frontend/src/components/dashboard/DeleteActionButton.tsx index e4d56dd95..d0708f239 100644 --- a/frontend/src/components/dashboard/DeleteActionButton.tsx +++ b/frontend/src/components/dashboard/DeleteActionButton.tsx @@ -1,26 +1,42 @@ import React, { useState } from 'react' import { useTranslation } from 'react-i18next'; +import { faXmark } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import Button from '../basic/buttons/Button'; import { DeleteEnvVar } from '../basic/dialog/DeleteEnvVar'; type Props = { - onSubmit: () => void + onSubmit: () => void; + isPlain?: boolean; } -export const DeleteActionButton = ({ onSubmit }: Props) => { +export const DeleteActionButton = ({ onSubmit, isPlain }: Props) => { const { t } = useTranslation(); const [open, setOpen] = useState(false) return ( -
-
- {!snapshotData && data?.length === 0 && ( + {!snapshotData && data?.length === 0 && selectedEnv && ( name)} @@ -629,7 +646,7 @@ export default function Dashboard() { />
)} - {snapshotData && ( + {snapshotData && selectedEnv && (
-
+
- {(snapshotData || data?.length !== 0) && ( + {(snapshotData || data?.length !== 0) && selectedEnv && ( <> {!snapshotData ? ( )} -
+
setSearchKeys(e.target.value)} placeholder={String(t('dashboard:search-keys'))} />
- {!snapshotData && ( -
-
- )} {!snapshotData && (
@@ -765,13 +773,30 @@ export default function Dashboard() { />
) : data?.length !== 0 ? ( -
+
-
+
+
+
+ Key + {!snapshotData && reorderRows(1)} + > + {sortMethod === 'alphabetical' ? : } + } +
+
Value
+
Comment
+ {!snapshotData &&
} +
+
{!snapshotData && data ?.filter((row) => row.key?.toUpperCase().includes(searchKeys.toUpperCase())) @@ -783,6 +808,7 @@ export default function Dashboard() { modifyValue={listenChangeValue} modifyValueOverride={listenChangeValueOverride} modifyKey={listenChangeKey} + modifyComment={listenChangeComment} isBlurred={blurred} isDuplicate={findDuplicates(data?.map((item) => item.key))?.includes( keyPair.key @@ -790,6 +816,7 @@ export default function Dashboard() { toggleSidebar={toggleSidebar} sidebarSecretId={sidebarSecretId} isSnapshot={false} + deleteRow={deleteCertainRow} /> ))} {snapshotData && @@ -820,6 +847,7 @@ export default function Dashboard() { modifyValue={listenChangeValue} modifyValueOverride={listenChangeValueOverride} modifyKey={listenChangeKey} + modifyComment={listenChangeComment} isBlurred={blurred} isDuplicate={findDuplicates(data?.map((item) => item.key))?.includes( keyPair.key @@ -829,9 +857,20 @@ export default function Dashboard() { isSnapshot /> ))} +
+
+ +
{!snapshotData && ( -
+
) : ( -
+
{isKeyAvailable && !snapshotData && (