mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 08:34:52 +00:00
refactor: move overview resource env determination logic to the client side to preserve ordering of resources
This commit is contained in:
@@ -15,7 +15,6 @@ import {
|
||||
} from "@app/hooks/api/dashboard/types";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { mergePersonalSecrets } from "@app/hooks/api/secrets/queries";
|
||||
import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types";
|
||||
|
||||
export const dashboardKeys = {
|
||||
all: () => ["dashboard"] as const,
|
||||
@@ -170,21 +169,9 @@ export const useGetProjectSecretsOverview = (
|
||||
select: useCallback((data: Awaited<ReturnType<typeof fetchProjectSecretsOverview>>) => {
|
||||
const { secrets, ...select } = data;
|
||||
|
||||
let sanitizedSecrets: Record<string, Record<string, SecretV3RawSanitized>> = {};
|
||||
|
||||
if (secrets) {
|
||||
sanitizedSecrets = {};
|
||||
Object.entries(secrets).forEach(([env, rawSecrets]) => {
|
||||
sanitizedSecrets[env] = mergePersonalSecrets(rawSecrets).reduce<
|
||||
Record<string, SecretV3RawSanitized>
|
||||
>((prev, curr) => ({ ...prev, [curr.key]: curr }), {});
|
||||
});
|
||||
}
|
||||
return {
|
||||
...select,
|
||||
...(secrets && {
|
||||
secrets: sanitizedSecrets
|
||||
})
|
||||
secrets: secrets ? mergePersonalSecrets(secrets) : undefined
|
||||
};
|
||||
}, []),
|
||||
keepPreviousData: true
|
||||
|
||||
@@ -5,9 +5,9 @@ import { TSecretImport } from "@app/hooks/api/secretImports/types";
|
||||
import { SecretV3Raw, SecretV3RawSanitized } from "@app/hooks/api/secrets/types";
|
||||
|
||||
export type DashboardProjectSecretsOverviewResponse = {
|
||||
folders?: { [key: string]: TSecretFolder[] };
|
||||
dynamicSecrets?: { [key: string]: TDynamicSecret[] };
|
||||
secrets?: { [key: string]: SecretV3Raw[] };
|
||||
folders?: (TSecretFolder & { environment: string })[];
|
||||
dynamicSecrets?: (TDynamicSecret & { environment: string })[];
|
||||
secrets?: SecretV3Raw[];
|
||||
totalSecretCount?: number;
|
||||
totalFolderCount?: number;
|
||||
totalDynamicSecretCount?: number;
|
||||
@@ -30,7 +30,7 @@ export type DashboardProjectSecretsOverview = Omit<
|
||||
DashboardProjectSecretsOverviewResponse,
|
||||
"secrets"
|
||||
> & {
|
||||
secrets?: Record<string, Record<string, SecretV3RawSanitized>>;
|
||||
secrets?: SecretV3RawSanitized[];
|
||||
};
|
||||
|
||||
export type DashboardProjectSecretsDetails = Omit<
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
import { useCallback, useMemo } from "react";
|
||||
|
||||
import { DashboardProjectSecretsOverview } from "@app/hooks/api/dashboard/types";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
|
||||
export const useFolderOverview = (
|
||||
folders: DashboardProjectSecretsOverview["folders"],
|
||||
orderDirection: OrderByDirection
|
||||
) => {
|
||||
export const useFolderOverview = (folders: DashboardProjectSecretsOverview["folders"]) => {
|
||||
const folderNames = useMemo(() => {
|
||||
const names = new Set<string>();
|
||||
Object.values(folders ?? {})?.forEach((folderGroup) => {
|
||||
folderGroup.forEach((folder) => {
|
||||
names.add(folder.name);
|
||||
});
|
||||
folders?.forEach((folder) => {
|
||||
names.add(folder.name);
|
||||
});
|
||||
return [...names].sort((a, b) =>
|
||||
orderDirection === OrderByDirection.ASC ? a.localeCompare(b) : b.localeCompare(a)
|
||||
);
|
||||
return [...names];
|
||||
}, [folders]);
|
||||
|
||||
const isFolderPresentInEnv = useCallback(
|
||||
(name: string, env: string) => {
|
||||
return Boolean(folders?.[env]?.find(({ name: folderName }) => folderName === name));
|
||||
return Boolean(
|
||||
folders?.find(
|
||||
({ name: folderName, environment }) => folderName === name && environment === env
|
||||
)
|
||||
);
|
||||
},
|
||||
[folders]
|
||||
);
|
||||
|
||||
const getFolderByNameAndEnv = useCallback(
|
||||
(name: string, env: string) => {
|
||||
return folders?.[env]?.find(({ name: folderName }) => folderName === name);
|
||||
return folders?.find(
|
||||
({ name: folderName, environment }) => folderName === name && environment === env
|
||||
);
|
||||
},
|
||||
[folders]
|
||||
);
|
||||
@@ -37,25 +35,23 @@ export const useFolderOverview = (
|
||||
};
|
||||
|
||||
export const useDynamicSecretOverview = (
|
||||
dynamicSecrets: DashboardProjectSecretsOverview["dynamicSecrets"],
|
||||
orderDirection: OrderByDirection
|
||||
dynamicSecrets: DashboardProjectSecretsOverview["dynamicSecrets"]
|
||||
) => {
|
||||
const dynamicSecretNames = useMemo(() => {
|
||||
const names = new Set<string>();
|
||||
Object.values(dynamicSecrets ?? {})?.forEach((folderGroup) => {
|
||||
folderGroup.forEach((folder) => {
|
||||
names.add(folder.name);
|
||||
});
|
||||
dynamicSecrets?.forEach((dynamicSecret) => {
|
||||
names.add(dynamicSecret.name);
|
||||
});
|
||||
return [...names].sort((a, b) =>
|
||||
orderDirection === OrderByDirection.ASC ? a.localeCompare(b) : b.localeCompare(a)
|
||||
);
|
||||
return [...names];
|
||||
}, [dynamicSecrets]);
|
||||
|
||||
const isDynamicSecretPresentInEnv = useCallback(
|
||||
(name: string, env: string) => {
|
||||
return Boolean(
|
||||
dynamicSecrets?.[env]?.find(({ name: dynamicSecretName }) => dynamicSecretName === name)
|
||||
dynamicSecrets?.find(
|
||||
({ name: dynamicSecretName, environment }) =>
|
||||
dynamicSecretName === name && environment === env
|
||||
)
|
||||
);
|
||||
},
|
||||
[dynamicSecrets]
|
||||
@@ -64,32 +60,23 @@ export const useDynamicSecretOverview = (
|
||||
return { dynamicSecretNames, isDynamicSecretPresentInEnv };
|
||||
};
|
||||
|
||||
export const useSecretOverview = (
|
||||
secrets: DashboardProjectSecretsOverview["secrets"],
|
||||
orderDirection: OrderByDirection
|
||||
) => {
|
||||
export const useSecretOverview = (secrets: DashboardProjectSecretsOverview["secrets"]) => {
|
||||
const secKeys = useMemo(() => {
|
||||
const keys = new Set<string>();
|
||||
Object.values(secrets ?? {})?.forEach((secretGroup) => {
|
||||
Object.keys(secretGroup || {}).forEach((key) => {
|
||||
keys.add(key);
|
||||
});
|
||||
});
|
||||
return [...keys].sort((a, b) =>
|
||||
orderDirection === OrderByDirection.ASC ? a.localeCompare(b) : b.localeCompare(a)
|
||||
);
|
||||
secrets?.forEach((secret) => keys.add(secret.key));
|
||||
return [...keys];
|
||||
}, [secrets]);
|
||||
|
||||
const getEnvSecretKeyCount = useCallback(
|
||||
(env: string) => {
|
||||
return Object.keys(secrets?.[env] || {}).length;
|
||||
return secrets?.filter((secret) => secret.env === env).length ?? 0;
|
||||
},
|
||||
[secrets]
|
||||
);
|
||||
|
||||
const getSecretByKey = useCallback(
|
||||
(env: string, key: string) => {
|
||||
const sec = secrets?.[env]?.[key];
|
||||
const sec = secrets?.find((s) => s.env === env && s.key === key);
|
||||
return sec;
|
||||
},
|
||||
[secrets]
|
||||
|
||||
+1
-1
@@ -277,7 +277,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
})}
|
||||
</TBody>
|
||||
</Table>
|
||||
{!isLoading && data && data.totalCount > INIT_PER_PAGE && (
|
||||
{!isLoading && data && (
|
||||
<Pagination
|
||||
count={data.totalCount}
|
||||
page={page}
|
||||
|
||||
@@ -369,7 +369,7 @@ export const IdentityTab = withProjectPermission(
|
||||
})}
|
||||
</TBody>
|
||||
</Table>
|
||||
{!isLoading && data && data.totalCount > INIT_PER_PAGE && (
|
||||
{!isLoading && data && (
|
||||
<Pagination
|
||||
count={data.totalCount}
|
||||
page={page}
|
||||
|
||||
@@ -358,7 +358,7 @@ export const SecretMainPage = () => {
|
||||
{!canReadSecret && folders?.length === 0 && <PermissionDeniedBanner />}
|
||||
</div>
|
||||
</div>
|
||||
{!isDetailsLoading && totalCount > INIT_PER_PAGE && (
|
||||
{!isDetailsLoading && (
|
||||
<Pagination
|
||||
startAdornment={
|
||||
<SecretTableResourceCount
|
||||
|
||||
@@ -242,20 +242,12 @@ export const SecretOverviewPage = () => {
|
||||
totalDynamicSecretCount
|
||||
} = overview ?? {};
|
||||
|
||||
const { folderNames, getFolderByNameAndEnv, isFolderPresentInEnv } = useFolderOverview(
|
||||
folders,
|
||||
orderDirection
|
||||
);
|
||||
const { folderNames, getFolderByNameAndEnv, isFolderPresentInEnv } = useFolderOverview(folders);
|
||||
|
||||
const { dynamicSecretNames, isDynamicSecretPresentInEnv } = useDynamicSecretOverview(
|
||||
dynamicSecrets,
|
||||
orderDirection
|
||||
);
|
||||
const { dynamicSecretNames, isDynamicSecretPresentInEnv } =
|
||||
useDynamicSecretOverview(dynamicSecrets);
|
||||
|
||||
const { secKeys, getSecretByKey, getEnvSecretKeyCount } = useSecretOverview(
|
||||
secrets,
|
||||
orderDirection
|
||||
);
|
||||
const { secKeys, getSecretByKey, getEnvSecretKeyCount } = useSecretOverview(secrets);
|
||||
|
||||
const { mutateAsync: createSecretV3 } = useCreateSecretV3();
|
||||
const { mutateAsync: updateSecretV3 } = useUpdateSecretV3();
|
||||
@@ -961,7 +953,7 @@ export const SecretOverviewPage = () => {
|
||||
</Tr>
|
||||
</TFoot>
|
||||
</Table>
|
||||
{!isOverviewLoading && totalCount > INIT_PER_PAGE && (
|
||||
{!isOverviewLoading && (
|
||||
<Pagination
|
||||
startAdornment={
|
||||
<SecretTableResourceCount
|
||||
|
||||
Reference in New Issue
Block a user