From 74534cfbaac919e567046e62447aec48190890f0 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Fri, 29 Sep 2023 13:34:44 +0530 Subject: [PATCH 1/2] feat(dashboard-v3): patched dashboard copy sec bug and add secret in empty state --- frontend/src/components/v2/Modal/Modal.tsx | 2 +- .../SecretMainPage/SecretMainPage.store.tsx | 41 ++++++++++++++++--- .../views/SecretMainPage/SecretMainPage.tsx | 32 +++++++++------ .../components/ActionBar/ActionBar.tsx | 29 ++++--------- .../CreateSecretForm.tsx | 22 +++++----- .../components/CreateSecretForm/index.tsx | 1 + .../SecretDropzone/CopySecretsFromBoard.tsx | 10 +++-- .../SecretDropzone/SecretDropzone.tsx | 9 +++- .../SecretListView/SecretListView.tsx | 6 +-- 9 files changed, 94 insertions(+), 58 deletions(-) rename frontend/src/views/SecretMainPage/components/{ActionBar => CreateSecretForm}/CreateSecretForm.tsx (87%) create mode 100644 frontend/src/views/SecretMainPage/components/CreateSecretForm/index.tsx diff --git a/frontend/src/components/v2/Modal/Modal.tsx b/frontend/src/components/v2/Modal/Modal.tsx index 97e1f3d3c..ae1e7fd4a 100644 --- a/frontend/src/components/v2/Modal/Modal.tsx +++ b/frontend/src/components/v2/Modal/Modal.tsx @@ -29,7 +29,7 @@ export const ModalContent = forwardRef( diff --git a/frontend/src/views/SecretMainPage/SecretMainPage.store.tsx b/frontend/src/views/SecretMainPage/SecretMainPage.store.tsx index 99f4e135f..a92960b31 100644 --- a/frontend/src/views/SecretMainPage/SecretMainPage.store.tsx +++ b/frontend/src/views/SecretMainPage/SecretMainPage.store.tsx @@ -28,13 +28,39 @@ const createSelectedSecretStore: StateCreator = (set) => ({ } }); -const StoreContext = createContext | null>(null); +export enum PopUpNames { + CreateSecretForm = "create-secret-form" +} +type PopUpState = { + popUp: Record; + popUpActions: { + togglePopUp: (id: PopUpNames, isOpen?: boolean) => void; + closePopUp: (id: PopUpNames) => void; + openPopUp: (id: PopUpNames, data?: any) => void; + }; +}; +const createPopUpStore: StateCreator = (set) => ({ + popUp: {}, + popUpActions: { + closePopUp: (id) => set((state) => ({ popUp: { ...state.popUp, [id]: { isOpen: false } } })), + openPopUp: (id, data) => + set((state) => ({ popUp: { ...state.popUp, [id]: { isOpen: true, data } } })), + togglePopUp: (id, isOpen) => + set((state) => ({ + popUp: { ...state.popUp, [id]: { isOpen: isOpen ?? !state.popUp[id].isOpen } } + })) + } +}); + +type CombinedState = SelectedSecretState & PopUpState; +const StoreContext = createContext | null>(null); export const StoreProvider = ({ children }: { children: ReactNode }) => { - const storeRef = useRef>(); + const storeRef = useRef>(); const router = useRouter(); if (!storeRef.current) { - storeRef.current = createStore((...a) => ({ - ...createSelectedSecretStore(...a) + storeRef.current = createStore((...a) => ({ + ...createSelectedSecretStore(...a), + ...createPopUpStore(...a) })); } @@ -53,7 +79,7 @@ export const StoreProvider = ({ children }: { children: ReactNode }) => { return {children}; }; -const useStoreContext = (selector: (state: SelectedSecretState) => T): T => { +const useStoreContext = (selector: (state: CombinedState) => T): T => { const ctx = useContext(StoreContext); if (!ctx) throw new Error("Missing "); return useStore(ctx, selector); @@ -62,3 +88,8 @@ const useStoreContext = (selector: (state: SelectedSecretStat // selected secret context export const useSelectedSecrets = () => useStoreContext((state) => state.selectedSecret); export const useSelectedSecretActions = () => useStoreContext((state) => state.action); + +// popup context +export const usePopUpState = (id: PopUpNames) => + useStoreContext((state) => state.popUp?.[id] || { isOpen: false }); +export const usePopUpAction = () => useStoreContext((state) => state.popUpActions); diff --git a/frontend/src/views/SecretMainPage/SecretMainPage.tsx b/frontend/src/views/SecretMainPage/SecretMainPage.tsx index e41543990..b25cd60d5 100644 --- a/frontend/src/views/SecretMainPage/SecretMainPage.tsx +++ b/frontend/src/views/SecretMainPage/SecretMainPage.tsx @@ -28,6 +28,7 @@ import { } from "@app/hooks/api"; import { ActionBar } from "./components/ActionBar"; +import { CreateSecretForm } from "./components/CreateSecretForm"; import { FolderListView } from "./components/FolderListView"; import { PitDrawer } from "./components/PitDrawer"; import { SecretDropzone } from "./components/SecretDropzone"; @@ -218,7 +219,6 @@ export const SecretMainPage = () => { workspaceId={workspaceId} secretPath={secretPath} isVisible={isVisible} - decryptFileKey={decryptFileKey!} filter={filter} tags={tags} onVisiblilityToggle={handleToggleVisibility} @@ -226,13 +226,12 @@ export const SecretMainPage = () => { onSearchChange={handleSearchChange} onToggleTagFilter={handleTagToggle} snapshotCount={snapshotCount || 0} - autoCapitalization={currentWorkspace?.autoCapitalization} isSnapshotCountLoading={isSnapshotCountLoading} onClickRollbackMode={() => handlePopUpToggle("snapshots", true)} />
@@ -292,6 +291,13 @@ export const SecretMainPage = () => { {!canReadSecret && folders?.length === 0 && }
+ { isSmaller={isNotEmtpy} environments={currentWorkspace?.environments} /> + handlePopUpToggle("snapshots", isOpen)} + hasNextPage={hasNextSnapshotListPage} + fetchNextPage={fetchNextSnapshotList} + onSelectSnapshot={handleSelectSnapshot} + isFetchingNextPage={isFetchingNextSnapshotList} + /> ) : ( { onClickListSnapshot={() => handlePopUpToggle("snapshots", true)} /> )} - handlePopUpToggle("snapshots", isOpen)} - hasNextPage={hasNextSnapshotListPage} - fetchNextPage={fetchNextSnapshotList} - onSelectSnapshot={handleSelectSnapshot} - isFetchingNextPage={isFetchingNextSnapshotList} - /> ); diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx index 5240c242f..c15d27788 100644 --- a/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx +++ b/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx @@ -43,11 +43,15 @@ import { import { ProjectPermissionActions, ProjectPermissionSub, useSubscription } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useCreateFolder, useDeleteSecretBatch } from "@app/hooks/api"; -import { DecryptedSecret, TImportedSecrets, UserWsKeyPair, WsTag } from "@app/hooks/api/types"; +import { DecryptedSecret, TImportedSecrets, WsTag } from "@app/hooks/api/types"; -import { useSelectedSecretActions, useSelectedSecrets } from "../../SecretMainPage.store"; +import { + PopUpNames, + usePopUpAction, + useSelectedSecretActions, + useSelectedSecrets +} from "../../SecretMainPage.store"; import { Filter, GroupBy } from "../../SecretMainPage.types"; -import { CreateSecretForm } from "./CreateSecretForm"; import { CreateSecretImportForm } from "./CreateSecretImportForm"; import { FolderForm } from "./FolderForm"; @@ -58,13 +62,11 @@ type Props = { environment: string; workspaceId: string; secretPath?: string; - decryptFileKey: UserWsKeyPair; filter: Filter; tags?: WsTag[]; isVisible?: boolean; snapshotCount: number; isSnapshotCountLoading?: boolean; - autoCapitalization?: boolean; onGroupByChange: (opt?: GroupBy) => void; onSearchChange: (term: string) => void; onToggleTagFilter: (tagId: string) => void; @@ -77,14 +79,12 @@ export const ActionBar = ({ importedSecrets = [], environment, workspaceId, - decryptFileKey, secretPath = "/", filter, tags = [], isVisible, snapshotCount, isSnapshotCountLoading, - autoCapitalization, onSearchChange, onToggleTagFilter, onGroupByChange, @@ -92,7 +92,6 @@ export const ActionBar = ({ onClickRollbackMode }: Props) => { const { handlePopUpOpen, handlePopUpToggle, handlePopUpClose, popUp } = usePopUp([ - "addSecret", "addFolder", "addSecretImport", "bulkDeleteSecrets", @@ -101,6 +100,7 @@ export const ActionBar = ({ ] as const); const { subscription } = useSubscription(); const { createNotification } = useNotificationContext(); + const { openPopUp } = usePopUpAction(); const { mutateAsync: createFolder } = useCreateFolder(); const { mutateAsync: deleteBatchSecretV3 } = useDeleteSecretBatch(); @@ -300,7 +300,7 @@ export const ActionBar = ({ @@ -264,7 +266,7 @@ export const CopySecretsFromBoard = ({ Include secret values -
+
-
diff --git a/frontend/src/views/SecretMainPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/views/SecretMainPage/components/SecretDropzone/SecretDropzone.tsx index aeb97e772..838a5f0fb 100644 --- a/frontend/src/views/SecretMainPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretDropzone/SecretDropzone.tsx @@ -17,6 +17,7 @@ import { useCreateSecretBatch, useUpdateSecretBatch } from "@app/hooks/api"; import { secretKeys } from "@app/hooks/api/secrets/queries"; import { DecryptedSecret, UserWsKeyPair } from "@app/hooks/api/types"; +import { PopUpNames, usePopUpAction } from "../../SecretMainPage.store"; import { CopySecretsFromBoard } from "./CopySecretsFromBoard"; const parseJson = (src: ArrayBuffer) => { @@ -62,6 +63,7 @@ export const SecretDropzone = ({ "overlapKeyWarning" ] as const); const queryClient = useQueryClient(); + const { openPopUp } = usePopUpAction(); const { mutateAsync: updateSecretBatch, isLoading: isUpdatingSecrets } = useUpdateSecretBatch({ options: { onSuccess: undefined } @@ -274,6 +276,7 @@ export const SecretDropzone = ({ workspaceId={workspaceId} decryptFileKey={decryptFileKey} secretPath={secretPath} + isSmaller={isSmaller} /> {!isSmaller && ( {(isAllowed) => ( - )} diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx b/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx index fb98bef98..050480456 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.tsx @@ -207,7 +207,7 @@ export const SecretListView = ({ // personal secret change if (overrideAction === "deleted") { await handleSecretOperation("delete", "personal", key); - } else if (overrideAction && idOverride){ + } else if (overrideAction && idOverride) { await handleSecretOperation("update", "personal", oldKey, { value: valueOverride, newKey: hasKeyChanged ? key : undefined, @@ -239,7 +239,7 @@ export const SecretListView = ({ }); } }, - [] + [environment, secretPath] ); const handleSecretDelete = useCallback(async () => { @@ -268,7 +268,7 @@ export const SecretListView = ({ text: "Failed to delete secret" }); } - }, [(popUp.deleteSecret?.data as DecryptedSecret)?.key]); + }, [(popUp.deleteSecret?.data as DecryptedSecret)?.key, environment, secretPath]); // for optimization on minimise re-rendering of secret items const onCreateTag = useCallback(() => handlePopUpOpen("createTag"), []); From 2cf5fd80ca1351eca5e52a936cf05867109a4180 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Fri, 29 Sep 2023 14:31:31 +0530 Subject: [PATCH 2/2] feat(dashboard-v3): removed a line at top on empty state --- frontend/src/views/SecretMainPage/SecretMainPage.tsx | 7 +------ .../SecretMainPage/components/ActionBar/ActionBar.tsx | 5 ++++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/frontend/src/views/SecretMainPage/SecretMainPage.tsx b/frontend/src/views/SecretMainPage/SecretMainPage.tsx index b25cd60d5..60fe31dce 100644 --- a/frontend/src/views/SecretMainPage/SecretMainPage.tsx +++ b/frontend/src/views/SecretMainPage/SecretMainPage.tsx @@ -4,7 +4,6 @@ import { useRouter } from "next/router"; import { subject } from "@casl/ability"; import { faArrowDown, faArrowUp } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { twMerge } from "tailwind-merge"; import NavHeader from "@app/components/navigation/NavHeader"; import { PermissionDeniedBanner } from "@app/components/permissions"; @@ -229,11 +228,7 @@ export const SecretMainPage = () => { isSnapshotCountLoading={isSnapshotCountLoading} onClickRollbackMode={() => handlePopUpToggle("snapshots", true)} /> -
+
{isNotEmtpy && (
diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx index c15d27788..0c3f3b03e 100644 --- a/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx +++ b/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx @@ -235,7 +235,10 @@ export const ActionBar = ({ Apply tags to filter secrets {tags.map(({ _id, name, tagColor }) => ( onToggleTagFilter(_id)} + onClick={(evt) => { + evt.preventDefault(); + onToggleTagFilter(_id); + }} key={_id} icon={filter?.tags[_id] && } iconPos="right"