mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 11:26:17 +00:00
Fix: Restructured frontend
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user