Fix: Restructured frontend

This commit is contained in:
Daniel Hougaard
2024-03-20 14:42:34 +01:00
parent a750d68363
commit a4e495ea1c
7 changed files with 122 additions and 63 deletions
@@ -13,9 +13,9 @@ import { secretSnapshotKeys } from "../secretSnapshots/queries";
import { import {
TCreateFolderDTO, TCreateFolderDTO,
TDeleteFolderDTO, TDeleteFolderDTO,
TFetchProjectFoldersResponse,
TGetFoldersByEnvDTO, TGetFoldersByEnvDTO,
TGetProjectFoldersDTO, TGetProjectFoldersDTO,
TSecretFolder,
TUpdateFolderDTO TUpdateFolderDTO
} from "./types"; } from "./types";
@@ -25,14 +25,14 @@ export const folderQueryKeys = {
}; };
const fetchProjectFolders = async (workspaceId: string, environment: string, path = "/") => { const fetchProjectFolders = async (workspaceId: string, environment: string, path = "/") => {
const { data } = await apiRequest.get<TFetchProjectFoldersResponse>("/api/v1/folders", { const { data } = await apiRequest.get<{ folders: TSecretFolder[] }>("/api/v1/folders", {
params: { params: {
workspaceId, workspaceId,
environment, environment,
path path
} }
}); });
return data; return data.folders;
}; };
export const useGetProjectFolders = ({ export const useGetProjectFolders = ({
@@ -43,9 +43,9 @@ export const useGetProjectFolders = ({
}: TGetProjectFoldersDTO & { }: TGetProjectFoldersDTO & {
options?: Omit< options?: Omit<
UseQueryOptions< UseQueryOptions<
TFetchProjectFoldersResponse, TSecretFolder[],
unknown, unknown,
TFetchProjectFoldersResponse, TSecretFolder[],
ReturnType<typeof folderQueryKeys.getSecretFolders> ReturnType<typeof folderQueryKeys.getSecretFolders>
>, >,
"queryKey" | "queryFn" "queryKey" | "queryFn"
@@ -63,8 +63,6 @@ export const useGetFoldersByEnv = ({
projectId, projectId,
environments environments
}: TGetFoldersByEnvDTO) => { }: TGetFoldersByEnvDTO) => {
const queryParams = new URLSearchParams(window.location.search);
const folders = useQueries({ const folders = useQueries({
queries: environments.map((environment) => ({ queries: environments.map((environment) => ({
queryKey: folderQueryKeys.getSecretFolders({ projectId, environment, path }), queryKey: folderQueryKeys.getSecretFolders({ projectId, environment, path }),
@@ -76,7 +74,7 @@ export const useGetFoldersByEnv = ({
const folderNames = useMemo(() => { const folderNames = useMemo(() => {
const names = new Set<string>(); const names = new Set<string>();
folders?.forEach(({ data }) => { folders?.forEach(({ data }) => {
data?.folders?.forEach(({ name }) => { data?.forEach(({ name }) => {
names.add(name); names.add(name);
}); });
}); });
@@ -87,7 +85,7 @@ export const useGetFoldersByEnv = ({
(name: string, env: string) => { (name: string, env: string) => {
const selectedEnvIndex = environments.indexOf(env); const selectedEnvIndex = environments.indexOf(env);
if (selectedEnvIndex !== -1) { if (selectedEnvIndex !== -1) {
const isPresent = folders?.[selectedEnvIndex]?.data?.folders.find( const isPresent = folders?.[selectedEnvIndex]?.data?.find(
({ name: folderName }) => folderName === name ({ name: folderName }) => folderName === name
); );
@@ -98,25 +96,7 @@ export const useGetFoldersByEnv = ({
[(folders || []).map((response) => response.data)] [(folders || []).map((response) => response.data)]
); );
const isImportedFolderPresentInEnv = useCallback( return { folders, folderNames, isFolderPresentInEnv };
(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 };
}; };
export const useCreateFolder = () => { export const useCreateFolder = () => {
@@ -3,24 +3,6 @@ export type TSecretFolder = {
name: string; 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 = { export type TGetProjectFoldersDTO = {
projectId: string; projectId: string;
environment: string; environment: string;
@@ -1,2 +1,2 @@
export { useCreateSecretImport, useDeleteSecretImport, useUpdateSecretImport } from "./mutation"; export { useCreateSecretImport, useDeleteSecretImport, useUpdateSecretImport } from "./mutation";
export { useGetImportedSecrets, useGetSecretImports } from "./queries"; export { useGetImportedFoldersByEnv, useGetImportedSecrets, useGetSecretImports } from "./queries";
@@ -1,5 +1,5 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { useQuery, UseQueryOptions } from "@tanstack/react-query"; import { useQueries, useQuery, UseQueryOptions } from "@tanstack/react-query";
import { import {
decryptAssymmetric, decryptAssymmetric,
@@ -7,7 +7,15 @@ import {
} from "@app/components/utilities/cryptography/crypto"; } from "@app/components/utilities/cryptography/crypto";
import { apiRequest } from "@app/config/request"; 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 = { export const secretImportKeys = {
getProjectSecretImports: ({ environment, projectId, path }: TGetSecretImports) => getProjectSecretImports: ({ environment, projectId, path }: TGetSecretImports) =>
@@ -17,7 +25,9 @@ export const secretImportKeys = {
projectId, projectId,
path path
}: Omit<TGetImportedSecrets, "decryptFileKey">) => }: Omit<TGetImportedSecrets, "decryptFileKey">) =>
[{ 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) => { const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSecretImports) => {
@@ -75,6 +85,24 @@ const fetchImportedSecrets = async (
return data.secrets; 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 = ({ export const useGetImportedSecrets = ({
environment, environment,
decryptFileKey, decryptFileKey,
@@ -159,3 +187,43 @@ export const useGetImportedSecrets = ({
[decryptFileKey] [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 };
};
@@ -12,6 +12,25 @@ export type TSecretImport = {
updatedAt: string; 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 = { export type TImportedSecrets = {
environment: string; environment: string;
environmentInfo: WorkspaceEnv; environmentInfo: WorkspaceEnv;
@@ -33,6 +52,12 @@ export type TGetImportedSecrets = {
decryptFileKey: UserWsKeyPair; decryptFileKey: UserWsKeyPair;
}; };
export type TuseGetImportedFoldersByEnv = {
environments: string[];
projectId: string;
path?: string;
};
export type TCreateSecretImportDTO = { export type TCreateSecretImportDTO = {
projectId: string; projectId: string;
environment: string; environment: string;
@@ -104,7 +104,7 @@ export const SecretMainPage = () => {
} }
}); });
// fetch folders // fetch folders
const { data: folderData, isLoading: isFoldersLoading } = useGetProjectFolders({ const { data: folders, isLoading: isFoldersLoading } = useGetProjectFolders({
projectId: workspaceId, projectId: workspaceId,
environment, environment,
path: secretPath path: secretPath
@@ -163,9 +163,7 @@ export const SecretMainPage = () => {
isPaused: !canDoReadRollback isPaused: !canDoReadRollback
}); });
const isNotEmtpy = Boolean( const isNotEmtpy = Boolean(secrets?.length || folders?.length || secretImports?.length);
secrets?.length || folderData?.folders?.length || secretImports?.length
);
const handleSortToggle = () => const handleSortToggle = () =>
setSortDir((state) => (state === SortDir.ASC ? SortDir.DESC : SortDir.ASC)); setSortDir((state) => (state === SortDir.ASC ? SortDir.DESC : SortDir.ASC));
@@ -294,7 +292,7 @@ export const SecretMainPage = () => {
/> />
)} )}
<FolderListView <FolderListView
folders={folderData?.folders} folders={folders}
environment={environment} environment={environment}
workspaceId={workspaceId} workspaceId={workspaceId}
secretPath={secretPath} secretPath={secretPath}
@@ -314,7 +312,7 @@ export const SecretMainPage = () => {
isProtectedBranch={isProtectedBranch} isProtectedBranch={isProtectedBranch}
/> />
)} )}
{!canReadSecret && folderData?.folders?.length === 0 && <PermissionDeniedBanner />} {!canReadSecret && folders?.length === 0 && <PermissionDeniedBanner />}
</div> </div>
</div> </div>
<CreateSecretForm <CreateSecretForm
@@ -354,7 +352,7 @@ export const SecretMainPage = () => {
workspaceId={workspaceId} workspaceId={workspaceId}
secretPath={secretPath} secretPath={secretPath}
secrets={secrets} secrets={secrets}
folders={folderData?.folders} folders={folders}
snapshotCount={snapshotCount} snapshotCount={snapshotCount}
onGoBack={handleResetSnapshot} onGoBack={handleResetSnapshot}
onClickListSnapshot={() => handlePopUpToggle("snapshots", true)} onClickListSnapshot={() => handlePopUpToggle("snapshots", true)}
@@ -55,6 +55,7 @@ import {
useCreateSecretV3, useCreateSecretV3,
useDeleteSecretV3, useDeleteSecretV3,
useGetFoldersByEnv, useGetFoldersByEnv,
useGetImportedFoldersByEnv,
useGetProjectSecretsAllEnv, useGetProjectSecretsAllEnv,
useGetUserWsKey, useGetUserWsKey,
useUpdateSecretV3 useUpdateSecretV3
@@ -125,12 +126,17 @@ export const SecretOverviewPage = () => {
secretPath, secretPath,
decryptFileKey: latestFileKey! decryptFileKey: latestFileKey!
}); });
const { folders, folderNames, isFolderPresentInEnv, isImportedFolderPresentInEnv } = const { folders, folderNames, isFolderPresentInEnv } = useGetFoldersByEnv({
useGetFoldersByEnv({ projectId: workspaceId,
projectId: workspaceId, path: secretPath,
path: secretPath, environments: userAvailableEnvs.map(({ slug }) => slug)
environments: userAvailableEnvs.map(({ slug }) => slug) });
});
const { isImportedFolderPresentInEnv } = useGetImportedFoldersByEnv({
projectId: workspaceId,
path: secretPath,
environments: userAvailableEnvs.map(({ slug }) => slug)
});
const { mutateAsync: createSecretV3 } = useCreateSecretV3(); const { mutateAsync: createSecretV3 } = useCreateSecretV3();
const { mutateAsync: updateSecretV3 } = useUpdateSecretV3(); const { mutateAsync: updateSecretV3 } = useUpdateSecretV3();