From a4e495ea1c7be529d71c617e14ef97a65c5dbb5d Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:42:34 +0100 Subject: [PATCH] Fix: Restructured frontend --- .../src/hooks/api/secretFolders/queries.tsx | 36 ++------- frontend/src/hooks/api/secretFolders/types.ts | 18 ----- frontend/src/hooks/api/secretImports/index.ts | 2 +- .../src/hooks/api/secretImports/queries.tsx | 74 ++++++++++++++++++- frontend/src/hooks/api/secretImports/types.ts | 25 +++++++ .../views/SecretMainPage/SecretMainPage.tsx | 12 ++- .../SecretOverviewPage/SecretOverviewPage.tsx | 18 +++-- 7 files changed, 122 insertions(+), 63 deletions(-) diff --git a/frontend/src/hooks/api/secretFolders/queries.tsx b/frontend/src/hooks/api/secretFolders/queries.tsx index 5c9db551b..0eb5223b9 100644 --- a/frontend/src/hooks/api/secretFolders/queries.tsx +++ b/frontend/src/hooks/api/secretFolders/queries.tsx @@ -13,9 +13,9 @@ import { secretSnapshotKeys } from "../secretSnapshots/queries"; import { TCreateFolderDTO, TDeleteFolderDTO, - TFetchProjectFoldersResponse, TGetFoldersByEnvDTO, TGetProjectFoldersDTO, + TSecretFolder, TUpdateFolderDTO } from "./types"; @@ -25,14 +25,14 @@ export const folderQueryKeys = { }; const fetchProjectFolders = async (workspaceId: string, environment: string, path = "/") => { - const { data } = await apiRequest.get("/api/v1/folders", { + const { data } = await apiRequest.get<{ folders: TSecretFolder[] }>("/api/v1/folders", { params: { workspaceId, environment, path } }); - return data; + return data.folders; }; export const useGetProjectFolders = ({ @@ -43,9 +43,9 @@ export const useGetProjectFolders = ({ }: TGetProjectFoldersDTO & { options?: Omit< UseQueryOptions< - TFetchProjectFoldersResponse, + TSecretFolder[], unknown, - TFetchProjectFoldersResponse, + TSecretFolder[], ReturnType >, "queryKey" | "queryFn" @@ -63,8 +63,6 @@ export const useGetFoldersByEnv = ({ projectId, environments }: TGetFoldersByEnvDTO) => { - const queryParams = new URLSearchParams(window.location.search); - const folders = useQueries({ queries: environments.map((environment) => ({ queryKey: folderQueryKeys.getSecretFolders({ projectId, environment, path }), @@ -76,7 +74,7 @@ export const useGetFoldersByEnv = ({ const folderNames = useMemo(() => { const names = new Set(); folders?.forEach(({ data }) => { - data?.folders?.forEach(({ name }) => { + data?.forEach(({ name }) => { names.add(name); }); }); @@ -87,7 +85,7 @@ export const useGetFoldersByEnv = ({ (name: string, env: string) => { const selectedEnvIndex = environments.indexOf(env); if (selectedEnvIndex !== -1) { - const isPresent = folders?.[selectedEnvIndex]?.data?.folders.find( + const isPresent = folders?.[selectedEnvIndex]?.data?.find( ({ name: folderName }) => folderName === name ); @@ -98,25 +96,7 @@ export const useGetFoldersByEnv = ({ [(folders || []).map((response) => response.data)] ); - const isImportedFolderPresentInEnv = useCallback( - (name: string, env: string) => { - const selectedEnvIndex = environments.indexOf(env); - - if (selectedEnvIndex !== -1) { - const currentlyBrowsingPath = queryParams.get("secretPath") || ""; - - const isPresent = folders?.[selectedEnvIndex]?.data?.importedFolders.find( - ({ importPath }) => importPath === `${currentlyBrowsingPath}/${name}` - ); - - return Boolean(isPresent); - } - return false; - }, - [(folders || []).map((response) => response.data)] - ); - - return { folders, folderNames, isFolderPresentInEnv, isImportedFolderPresentInEnv }; + return { folders, folderNames, isFolderPresentInEnv }; }; export const useCreateFolder = () => { diff --git a/frontend/src/hooks/api/secretFolders/types.ts b/frontend/src/hooks/api/secretFolders/types.ts index e676fcc8e..eac202389 100644 --- a/frontend/src/hooks/api/secretFolders/types.ts +++ b/frontend/src/hooks/api/secretFolders/types.ts @@ -3,24 +3,6 @@ export type TSecretFolder = { name: string; }; -export type TImportedSecretFolder = { - id: string; - folderId: string; - importEnv: { - id: string; - name: string; - slug: string; - }; - importPath: string; - - // ... It got more fields, but we won't need them. -}; - -export type TFetchProjectFoldersResponse = { - folders: TSecretFolder[]; - importedFolders: TImportedSecretFolder[]; -}; - export type TGetProjectFoldersDTO = { projectId: string; environment: string; diff --git a/frontend/src/hooks/api/secretImports/index.ts b/frontend/src/hooks/api/secretImports/index.ts index 2e1150cb8..9c76d597e 100644 --- a/frontend/src/hooks/api/secretImports/index.ts +++ b/frontend/src/hooks/api/secretImports/index.ts @@ -1,2 +1,2 @@ export { useCreateSecretImport, useDeleteSecretImport, useUpdateSecretImport } from "./mutation"; -export { useGetImportedSecrets, useGetSecretImports } from "./queries"; +export { useGetImportedFoldersByEnv, useGetImportedSecrets, useGetSecretImports } from "./queries"; diff --git a/frontend/src/hooks/api/secretImports/queries.tsx b/frontend/src/hooks/api/secretImports/queries.tsx index 1af6ca878..1714f45ff 100644 --- a/frontend/src/hooks/api/secretImports/queries.tsx +++ b/frontend/src/hooks/api/secretImports/queries.tsx @@ -1,5 +1,5 @@ import { useCallback } from "react"; -import { useQuery, UseQueryOptions } from "@tanstack/react-query"; +import { useQueries, useQuery, UseQueryOptions } from "@tanstack/react-query"; import { decryptAssymmetric, @@ -7,7 +7,15 @@ import { } from "@app/components/utilities/cryptography/crypto"; import { apiRequest } from "@app/config/request"; -import { TGetImportedSecrets, TGetSecretImports, TImportedSecrets, TSecretImport } from "./types"; +import { + TGetImportedFoldersByEnvDTO, + TGetImportedSecrets, + TGetSecretImports, + TImportedSecretFolder, + TImportedSecrets, + TSecretImport, + TuseGetImportedFoldersByEnv +} from "./types"; export const secretImportKeys = { getProjectSecretImports: ({ environment, projectId, path }: TGetSecretImports) => @@ -17,7 +25,9 @@ export const secretImportKeys = { projectId, path }: Omit) => - [{ environment, path, projectId }, "secrets-import-sec"] as const + [{ environment, path, projectId }, "secrets-import-sec"] as const, + getImportedFoldersByEnv: ({ environment, projectId, path }: TGetImportedFoldersByEnvDTO) => + [{ environment, projectId, path }, "imported-folders"] as const }; const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSecretImports) => { @@ -75,6 +85,24 @@ const fetchImportedSecrets = async ( return data.secrets; }; +const fetchImportedFolders = async ({ + projectId, + environment, + path +}: TGetImportedFoldersByEnvDTO) => { + const { data } = await apiRequest.get<{ secretImports: TImportedSecretFolder[] }>( + "/api/v1/secret-imports", + { + params: { + workspaceId: projectId, + environment, + path + } + } + ); + return data.secretImports; +}; + export const useGetImportedSecrets = ({ environment, decryptFileKey, @@ -159,3 +187,43 @@ export const useGetImportedSecrets = ({ [decryptFileKey] ) }); + +export const useGetImportedFoldersByEnv = ({ + projectId, + environments, + path = "/" +}: TuseGetImportedFoldersByEnv) => { + const queryParams = new URLSearchParams(window.location.search); + + const importedFolders = useQueries({ + queries: environments.map((env) => ({ + queryKey: secretImportKeys.getImportedFoldersByEnv({ + projectId, + environment: env, + path + }), + queryFn: async () => fetchImportedFolders({ projectId, environment: env, path }), + enabled: Boolean(projectId) && Boolean(env) + })) + }); + + const isImportedFolderPresentInEnv = useCallback( + (name: string, env: string) => { + const selectedEnvIndex = environments.indexOf(env); + + if (selectedEnvIndex !== -1) { + const currentlyBrowsingPath = queryParams.get("secretPath") || ""; + + const isPresent = importedFolders?.[selectedEnvIndex]?.data?.find( + ({ importPath }) => importPath === `${currentlyBrowsingPath}/${name}` + ); + + return Boolean(isPresent); + } + return false; + }, + [(importedFolders || []).map((response) => response.data)] + ); + + return { importedFolders, isImportedFolderPresentInEnv }; +}; diff --git a/frontend/src/hooks/api/secretImports/types.ts b/frontend/src/hooks/api/secretImports/types.ts index eb63e8a96..7c69a8516 100644 --- a/frontend/src/hooks/api/secretImports/types.ts +++ b/frontend/src/hooks/api/secretImports/types.ts @@ -12,6 +12,25 @@ export type TSecretImport = { updatedAt: string; }; +export type TImportedSecretFolder = { + id: string; + folderId: string; + importEnv: { + id: string; + name: string; + slug: string; + }; + importPath: string; + + // ... It got more fields, but we won't need them. +}; + +export type TGetImportedFoldersByEnvDTO = { + projectId: string; + environment: string; + path?: string; +}; + export type TImportedSecrets = { environment: string; environmentInfo: WorkspaceEnv; @@ -33,6 +52,12 @@ export type TGetImportedSecrets = { decryptFileKey: UserWsKeyPair; }; +export type TuseGetImportedFoldersByEnv = { + environments: string[]; + projectId: string; + path?: string; +}; + export type TCreateSecretImportDTO = { projectId: string; environment: string; diff --git a/frontend/src/views/SecretMainPage/SecretMainPage.tsx b/frontend/src/views/SecretMainPage/SecretMainPage.tsx index bd8f0e7fe..312b676b7 100644 --- a/frontend/src/views/SecretMainPage/SecretMainPage.tsx +++ b/frontend/src/views/SecretMainPage/SecretMainPage.tsx @@ -104,7 +104,7 @@ export const SecretMainPage = () => { } }); // fetch folders - const { data: folderData, isLoading: isFoldersLoading } = useGetProjectFolders({ + const { data: folders, isLoading: isFoldersLoading } = useGetProjectFolders({ projectId: workspaceId, environment, path: secretPath @@ -163,9 +163,7 @@ export const SecretMainPage = () => { isPaused: !canDoReadRollback }); - const isNotEmtpy = Boolean( - secrets?.length || folderData?.folders?.length || secretImports?.length - ); + const isNotEmtpy = Boolean(secrets?.length || folders?.length || secretImports?.length); const handleSortToggle = () => setSortDir((state) => (state === SortDir.ASC ? SortDir.DESC : SortDir.ASC)); @@ -294,7 +292,7 @@ export const SecretMainPage = () => { /> )} { isProtectedBranch={isProtectedBranch} /> )} - {!canReadSecret && folderData?.folders?.length === 0 && } + {!canReadSecret && folders?.length === 0 && } { workspaceId={workspaceId} secretPath={secretPath} secrets={secrets} - folders={folderData?.folders} + folders={folders} snapshotCount={snapshotCount} onGoBack={handleResetSnapshot} onClickListSnapshot={() => handlePopUpToggle("snapshots", true)} diff --git a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx index ea70506b5..7eda5c203 100644 --- a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx +++ b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx @@ -55,6 +55,7 @@ import { useCreateSecretV3, useDeleteSecretV3, useGetFoldersByEnv, + useGetImportedFoldersByEnv, useGetProjectSecretsAllEnv, useGetUserWsKey, useUpdateSecretV3 @@ -125,12 +126,17 @@ export const SecretOverviewPage = () => { secretPath, decryptFileKey: latestFileKey! }); - const { folders, folderNames, isFolderPresentInEnv, isImportedFolderPresentInEnv } = - useGetFoldersByEnv({ - projectId: workspaceId, - path: secretPath, - environments: userAvailableEnvs.map(({ slug }) => slug) - }); + const { folders, folderNames, isFolderPresentInEnv } = useGetFoldersByEnv({ + projectId: workspaceId, + path: secretPath, + environments: userAvailableEnvs.map(({ slug }) => slug) + }); + + const { isImportedFolderPresentInEnv } = useGetImportedFoldersByEnv({ + projectId: workspaceId, + path: secretPath, + environments: userAvailableEnvs.map(({ slug }) => slug) + }); const { mutateAsync: createSecretV3 } = useCreateSecretV3(); const { mutateAsync: updateSecretV3 } = useUpdateSecretV3();