mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 07:26:45 +00:00
Feat: Import indicator
This commit is contained in:
@@ -11,7 +11,7 @@ import {
|
|||||||
TGetImportedFoldersByEnvDTO,
|
TGetImportedFoldersByEnvDTO,
|
||||||
TGetImportedSecrets,
|
TGetImportedSecrets,
|
||||||
TGetSecretImports,
|
TGetSecretImports,
|
||||||
TImportedSecretFolder,
|
TGetSecretImportsAllEnvs,
|
||||||
TImportedSecrets,
|
TImportedSecrets,
|
||||||
TSecretImport,
|
TSecretImport,
|
||||||
TuseGetImportedFoldersByEnv
|
TuseGetImportedFoldersByEnv
|
||||||
@@ -27,7 +27,9 @@ export const secretImportKeys = {
|
|||||||
}: 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) =>
|
getImportedFoldersByEnv: ({ environment, projectId, path }: TGetImportedFoldersByEnvDTO) =>
|
||||||
[{ environment, projectId, path }, "imported-folders"] as const
|
[{ environment, projectId, path }, "imported-folders"] as const,
|
||||||
|
getImportedFoldersAllEnvs: ({ projectId, path, environment }: TGetImportedFoldersByEnvDTO) =>
|
||||||
|
[{ projectId, path, environment }, "imported-folders-all-envs"] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSecretImports) => {
|
const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSecretImports) => {
|
||||||
@@ -90,7 +92,7 @@ const fetchImportedFolders = async ({
|
|||||||
environment,
|
environment,
|
||||||
path
|
path
|
||||||
}: TGetImportedFoldersByEnvDTO) => {
|
}: TGetImportedFoldersByEnvDTO) => {
|
||||||
const { data } = await apiRequest.get<{ secretImports: TImportedSecretFolder[] }>(
|
const { data } = await apiRequest.get<{ secretImports: TSecretImport[] }>(
|
||||||
"/api/v1/secret-imports",
|
"/api/v1/secret-imports",
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
@@ -103,7 +105,7 @@ const fetchImportedFolders = async ({
|
|||||||
return data.secretImports;
|
return data.secretImports;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetImportedSecrets = ({
|
export const useGetImportedSecretsSingleEnv = ({
|
||||||
environment,
|
environment,
|
||||||
decryptFileKey,
|
decryptFileKey,
|
||||||
path,
|
path,
|
||||||
@@ -188,6 +190,98 @@ export const useGetImportedSecrets = ({
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const useGetImportedSecretsAllEnvs = ({
|
||||||
|
projectId,
|
||||||
|
environments,
|
||||||
|
path = "/",
|
||||||
|
decryptFileKey
|
||||||
|
}: TGetSecretImportsAllEnvs) => {
|
||||||
|
const secretImports = useQueries({
|
||||||
|
queries: environments.map((env) => ({
|
||||||
|
queryKey: secretImportKeys.getImportedFoldersAllEnvs({
|
||||||
|
environment: env,
|
||||||
|
projectId,
|
||||||
|
path
|
||||||
|
}),
|
||||||
|
queryFn: () => fetchImportedSecrets(projectId, env, path).catch(() => []),
|
||||||
|
enabled: Boolean(projectId) && Boolean(env),
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
select: useCallback(
|
||||||
|
(data: TImportedSecrets[]) => {
|
||||||
|
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
|
||||||
|
const latestKey = decryptFileKey;
|
||||||
|
const key = decryptAssymmetric({
|
||||||
|
ciphertext: latestKey.encryptedKey,
|
||||||
|
nonce: latestKey.nonce,
|
||||||
|
publicKey: latestKey.sender.publicKey,
|
||||||
|
privateKey: PRIVATE_KEY
|
||||||
|
});
|
||||||
|
|
||||||
|
return data.map((el) => ({
|
||||||
|
environment: el.environment,
|
||||||
|
secretPath: el.secretPath,
|
||||||
|
environmentInfo: el.environmentInfo,
|
||||||
|
folderId: el.folderId,
|
||||||
|
secrets: el.secrets.map((encSecret) => {
|
||||||
|
const secretKey = decryptSymmetric({
|
||||||
|
ciphertext: encSecret.secretKeyCiphertext,
|
||||||
|
iv: encSecret.secretKeyIV,
|
||||||
|
tag: encSecret.secretKeyTag,
|
||||||
|
key
|
||||||
|
});
|
||||||
|
|
||||||
|
const secretValue = decryptSymmetric({
|
||||||
|
ciphertext: encSecret.secretValueCiphertext,
|
||||||
|
iv: encSecret.secretValueIV,
|
||||||
|
tag: encSecret.secretValueTag,
|
||||||
|
key
|
||||||
|
});
|
||||||
|
|
||||||
|
const secretComment = decryptSymmetric({
|
||||||
|
ciphertext: encSecret.secretCommentCiphertext,
|
||||||
|
iv: encSecret.secretCommentIV,
|
||||||
|
tag: encSecret.secretCommentTag,
|
||||||
|
key
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: encSecret.id,
|
||||||
|
env: encSecret.environment,
|
||||||
|
key: secretKey,
|
||||||
|
value: secretValue,
|
||||||
|
tags: encSecret.tags,
|
||||||
|
comment: secretComment,
|
||||||
|
createdAt: encSecret.createdAt,
|
||||||
|
updatedAt: encSecret.updatedAt,
|
||||||
|
version: encSecret.version
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[decryptFileKey]
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
const isImportedSecretPresentInEnv = useCallback(
|
||||||
|
(secPath: string, envSlug: string) => {
|
||||||
|
const selectedEnvIndex = environments.indexOf(envSlug);
|
||||||
|
|
||||||
|
if (selectedEnvIndex !== -1) {
|
||||||
|
const isPresent = secretImports?.[selectedEnvIndex]?.data?.find(
|
||||||
|
({ secretPath }) => secretPath === secPath
|
||||||
|
);
|
||||||
|
|
||||||
|
return Boolean(isPresent);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[(secretImports || []).map((response) => response.data)]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { secretImports, isImportedSecretPresentInEnv };
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetImportedFoldersByEnv = ({
|
export const useGetImportedFoldersByEnv = ({
|
||||||
projectId,
|
projectId,
|
||||||
environments,
|
environments,
|
||||||
@@ -195,14 +289,16 @@ export const useGetImportedFoldersByEnv = ({
|
|||||||
}: TuseGetImportedFoldersByEnv) => {
|
}: TuseGetImportedFoldersByEnv) => {
|
||||||
const queryParams = new URLSearchParams(window.location.search);
|
const queryParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
const currentPath = path;
|
||||||
|
|
||||||
const importedFolders = useQueries({
|
const importedFolders = useQueries({
|
||||||
queries: environments.map((env) => ({
|
queries: environments.map((env) => ({
|
||||||
queryKey: secretImportKeys.getImportedFoldersByEnv({
|
queryKey: secretImportKeys.getImportedFoldersByEnv({
|
||||||
projectId,
|
projectId,
|
||||||
environment: env,
|
environment: env,
|
||||||
path
|
path: currentPath
|
||||||
}),
|
}),
|
||||||
queryFn: async () => fetchImportedFolders({ projectId, environment: env, path }),
|
queryFn: async () => fetchImportedFolders({ projectId, environment: env, path: currentPath }),
|
||||||
enabled: Boolean(projectId) && Boolean(env)
|
enabled: Boolean(projectId) && Boolean(env)
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
} from "@app/context";
|
} from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import {
|
import {
|
||||||
useGetImportedSecrets,
|
useGetImportedSecretsSingleEnv,
|
||||||
useGetProjectFolders,
|
useGetProjectFolders,
|
||||||
useGetProjectSecrets,
|
useGetProjectSecrets,
|
||||||
useGetSecretApprovalPolicyOfABoard,
|
useGetSecretApprovalPolicyOfABoard,
|
||||||
@@ -124,7 +124,7 @@ export const SecretMainPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// fetch imported secrets to show user the overriden ones
|
// fetch imported secrets to show user the overriden ones
|
||||||
const { data: importedSecrets } = useGetImportedSecrets({
|
const { data: importedSecrets } = useGetImportedSecretsSingleEnv({
|
||||||
projectId: workspaceId,
|
projectId: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
decryptFileKey: decryptFileKey!,
|
decryptFileKey: decryptFileKey!,
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import {
|
|||||||
useDeleteSecretV3,
|
useDeleteSecretV3,
|
||||||
useGetFoldersByEnv,
|
useGetFoldersByEnv,
|
||||||
useGetImportedFoldersByEnv,
|
useGetImportedFoldersByEnv,
|
||||||
|
useGetImportedSecretsAllEnvs,
|
||||||
useGetProjectSecretsAllEnv,
|
useGetProjectSecretsAllEnv,
|
||||||
useGetUserWsKey,
|
useGetUserWsKey,
|
||||||
useUpdateSecretV3
|
useUpdateSecretV3
|
||||||
@@ -134,7 +135,12 @@ export const SecretOverviewPage = () => {
|
|||||||
|
|
||||||
const { isImportedFolderPresentInEnv } = useGetImportedFoldersByEnv({
|
const { isImportedFolderPresentInEnv } = useGetImportedFoldersByEnv({
|
||||||
projectId: workspaceId,
|
projectId: workspaceId,
|
||||||
path: secretPath,
|
environments: userAvailableEnvs.map(({ slug }) => slug)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { isImportedSecretPresentInEnv } = useGetImportedSecretsAllEnvs({
|
||||||
|
projectId: workspaceId,
|
||||||
|
decryptFileKey: latestFileKey!,
|
||||||
environments: userAvailableEnvs.map(({ slug }) => slug)
|
environments: userAvailableEnvs.map(({ slug }) => slug)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -657,6 +663,7 @@ export const SecretOverviewPage = () => {
|
|||||||
filteredSecretNames.map((key, index) => (
|
filteredSecretNames.map((key, index) => (
|
||||||
<SecretOverviewTableRow
|
<SecretOverviewTableRow
|
||||||
secretPath={secretPath}
|
secretPath={secretPath}
|
||||||
|
isImportedSecretPresentInEnv={isImportedSecretPresentInEnv}
|
||||||
onSecretCreate={handleSecretCreate}
|
onSecretCreate={handleSecretCreate}
|
||||||
onSecretDelete={handleSecretDelete}
|
onSecretDelete={handleSecretDelete}
|
||||||
onSecretUpdate={handleSecretUpdate}
|
onSecretUpdate={handleSecretUpdate}
|
||||||
|
|||||||
+5
-1
@@ -40,7 +40,11 @@ export const SecretOverviewFolderRow = ({
|
|||||||
isPresent || isImportPresent ? "text-green-600" : "text-red-600"
|
isPresent || isImportPresent ? "text-green-600" : "text-red-600"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Tooltip isDisabled={!isImportPresent} content="Folder is imported">
|
<Tooltip
|
||||||
|
center
|
||||||
|
isDisabled={!isImportPresent}
|
||||||
|
content="Folder is imported from another environment"
|
||||||
|
>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
// eslint-disable-next-line no-nested-ternary
|
// eslint-disable-next-line no-nested-ternary
|
||||||
|
|||||||
Reference in New Issue
Block a user