mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 14:26:25 +00:00
Improve referenced secret deletion message logic
This commit is contained in:
@@ -577,13 +577,21 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
|||||||
totalSecretCount: z.number().optional(),
|
totalSecretCount: z.number().optional(),
|
||||||
importedBy: z
|
importedBy: z
|
||||||
.object({
|
.object({
|
||||||
envName: z.string(),
|
environment: z.object({
|
||||||
envSlug: z.string(),
|
name: z.string(),
|
||||||
|
slug: z.string()
|
||||||
|
}),
|
||||||
folders: z
|
folders: z
|
||||||
.object({
|
.object({
|
||||||
folderName: z.string(),
|
name: z.string(),
|
||||||
folderImported: z.boolean(),
|
isImported: z.boolean(),
|
||||||
secrets: z.array(z.string()).optional()
|
secrets: z
|
||||||
|
.object({
|
||||||
|
secretId: z.string(),
|
||||||
|
referencedSecretKey: z.string()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.optional()
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
})
|
})
|
||||||
@@ -856,7 +864,8 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
|||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
actorOrgId: req.permission.orgId
|
actorOrgId: req.permission.orgId,
|
||||||
|
secrets
|
||||||
});
|
});
|
||||||
|
|
||||||
if (secrets?.length || secretRotations?.length) {
|
if (secrets?.length || secretRotations?.length) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { TableName, TSecretImports } from "@app/db/schemas";
|
|||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
import { EnvInfo, FolderInfo, FolderResult, SecretResult } from "./secret-import-types";
|
import { EnvironmentInfo, FolderInfo, FolderResult, SecretResult } from "./secret-import-types";
|
||||||
|
|
||||||
export type TSecretImportDALFactory = ReturnType<typeof secretImportDALFactory>;
|
export type TSecretImportDALFactory = ReturnType<typeof secretImportDALFactory>;
|
||||||
|
|
||||||
@@ -179,31 +179,31 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
|||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const knexInstance = tx || db.replicaNode();
|
const folderImports = await (tx || db.replicaNode())(TableName.SecretImport)
|
||||||
|
|
||||||
const folderImports = await knexInstance(TableName.SecretImport)
|
|
||||||
.where({ importPath: secretPath, importEnv: environmentId })
|
.where({ importPath: secretPath, importEnv: environmentId })
|
||||||
.join(TableName.SecretFolder, `${TableName.SecretImport}.folderId`, `${TableName.SecretFolder}.id`)
|
.join(TableName.SecretFolder, `${TableName.SecretImport}.folderId`, `${TableName.SecretFolder}.id`)
|
||||||
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||||
.select(
|
.select(
|
||||||
knexInstance.ref("name").withSchema(TableName.Environment).as("envName"),
|
db.ref("name").withSchema(TableName.Environment).as("envName"),
|
||||||
knexInstance.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
knexInstance.ref("name").withSchema(TableName.SecretFolder).as("folderName"),
|
db.ref("name").withSchema(TableName.SecretFolder).as("folderName"),
|
||||||
knexInstance.ref("id").withSchema(TableName.SecretFolder).as("folderId")
|
db.ref("id").withSchema(TableName.SecretFolder).as("folderId")
|
||||||
);
|
);
|
||||||
|
|
||||||
const secretReferences = await knexInstance(TableName.SecretReferenceV2)
|
const secretReferences = await (tx || db.replicaNode())(TableName.SecretReferenceV2)
|
||||||
.where({ secretPath, environment })
|
.where({ secretPath, environment })
|
||||||
.join(TableName.SecretV2, `${TableName.SecretReferenceV2}.secretId`, `${TableName.SecretV2}.id`)
|
.join(TableName.SecretV2, `${TableName.SecretReferenceV2}.secretId`, `${TableName.SecretV2}.id`)
|
||||||
.join(TableName.SecretFolder, `${TableName.SecretV2}.folderId`, `${TableName.SecretFolder}.id`)
|
.join(TableName.SecretFolder, `${TableName.SecretV2}.folderId`, `${TableName.SecretFolder}.id`)
|
||||||
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||||
.where(`${TableName.Environment}.projectId`, projectId)
|
.where(`${TableName.Environment}.projectId`, projectId)
|
||||||
|
.where(`${TableName.SecretFolder}.isReserved`, false)
|
||||||
.select(
|
.select(
|
||||||
knexInstance.ref("key").withSchema(TableName.SecretV2).as("secretId"),
|
db.ref("key").withSchema(TableName.SecretV2).as("secretId"),
|
||||||
knexInstance.ref("name").withSchema(TableName.SecretFolder).as("folderName"),
|
db.ref("name").withSchema(TableName.SecretFolder).as("folderName"),
|
||||||
knexInstance.ref("name").withSchema(TableName.Environment).as("envName"),
|
db.ref("name").withSchema(TableName.Environment).as("envName"),
|
||||||
knexInstance.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
knexInstance.ref("id").withSchema(TableName.SecretFolder).as("folderId")
|
db.ref("id").withSchema(TableName.SecretFolder).as("folderId"),
|
||||||
|
db.ref("secretKey").withSchema(TableName.SecretReferenceV2).as("referencedSecretKey")
|
||||||
);
|
);
|
||||||
|
|
||||||
const folderResults = folderImports.map(({ envName, envSlug, folderName, folderId }) => ({
|
const folderResults = folderImports.map(({ envName, envSlug, folderName, folderId }) => ({
|
||||||
@@ -213,13 +213,16 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
|||||||
folderId
|
folderId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const secretResults = secretReferences.map(({ envName, envSlug, secretId, folderName, folderId }) => ({
|
const secretResults = secretReferences.map(
|
||||||
envName,
|
({ envName, envSlug, secretId, folderName, folderId, referencedSecretKey }) => ({
|
||||||
envSlug,
|
envName,
|
||||||
secretId,
|
envSlug,
|
||||||
folderName,
|
secretId,
|
||||||
folderId
|
folderName,
|
||||||
}));
|
folderId,
|
||||||
|
referencedSecretKey
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
type ResultItem = FolderResult | SecretResult;
|
type ResultItem = FolderResult | SecretResult;
|
||||||
const allResults: ResultItem[] = [...folderResults, ...secretResults];
|
const allResults: ResultItem[] = [...folderResults, ...secretResults];
|
||||||
@@ -229,7 +232,10 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
|||||||
envSlug: string;
|
envSlug: string;
|
||||||
folders: {
|
folders: {
|
||||||
[folderName: string]: {
|
[folderName: string]: {
|
||||||
secrets: string[];
|
secrets: {
|
||||||
|
secretId: string;
|
||||||
|
referencedSecretKey: string;
|
||||||
|
}[];
|
||||||
folderId: string;
|
folderId: string;
|
||||||
folderImported: boolean;
|
folderImported: boolean;
|
||||||
};
|
};
|
||||||
@@ -256,7 +262,10 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ("secretId" in item && item.secretId) {
|
if ("secretId" in item && item.secretId) {
|
||||||
updatedAcc[env].folders[folder].secrets = [...updatedAcc[env].folders[folder].secrets, item.secretId];
|
updatedAcc[env].folders[folder].secrets = [
|
||||||
|
...updatedAcc[env].folders[folder].secrets,
|
||||||
|
{ secretId: item.secretId, referencedSecretKey: item.referencedSecretKey }
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
updatedAcc[env].folders[folder].folderImported = true;
|
updatedAcc[env].folders[folder].folderImported = true;
|
||||||
}
|
}
|
||||||
@@ -264,7 +273,7 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
|||||||
return updatedAcc;
|
return updatedAcc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const formattedResult: EnvInfo[] = Object.keys(groupedByEnv).map((envName) => {
|
const formattedResult: EnvironmentInfo[] = Object.keys(groupedByEnv).map((envName) => {
|
||||||
const envData = groupedByEnv[envName];
|
const envData = groupedByEnv[envName];
|
||||||
|
|
||||||
const folders: FolderInfo[] = Object.keys(envData.folders).map((folderName) => {
|
const folders: FolderInfo[] = Object.keys(envData.folders).map((folderName) => {
|
||||||
@@ -288,7 +297,7 @@ export const secretImportDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
return formattedResult;
|
return formattedResult;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "get secret imports and references" });
|
throw new DatabaseError({ error, name: "GetSecretImportsAndReferences" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -801,8 +801,11 @@ export const secretImportServiceFactory = ({
|
|||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
}: TGetSecretImportsDTO) => {
|
secrets
|
||||||
|
}: TGetSecretImportsDTO & {
|
||||||
|
secrets: { secretKey: string; secretValue: string }[] | undefined;
|
||||||
|
}) => {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -823,7 +826,6 @@ export const secretImportServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const importedBy = await secretImportDAL.getFolderIsImportedBy(secretPath, folder.envId, environment, projectId);
|
const importedBy = await secretImportDAL.getFolderIsImportedBy(secretPath, folder.envId, environment, projectId);
|
||||||
console.log({ importedBy });
|
|
||||||
const deepPaths: { path: string; folderId: string }[] = [];
|
const deepPaths: { path: string; folderId: string }[] = [];
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -839,15 +841,90 @@ export const secretImportServiceFactory = ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return importedBy.map((el) => ({
|
const result = importedBy.map((el) => ({
|
||||||
...el,
|
environment: {
|
||||||
|
name: el.envName,
|
||||||
|
slug: el.envSlug
|
||||||
|
},
|
||||||
folders: el.folders.map((folderItem) => ({
|
folders: el.folders.map((folderItem) => ({
|
||||||
folderId: folderItem.folderId,
|
folderId: folderItem.folderId,
|
||||||
folderImported: folderItem.folderImported,
|
isImported: folderItem.folderImported,
|
||||||
secrets: folderItem.secrets,
|
secrets: folderItem.secrets,
|
||||||
folderName: deepPaths.find((p) => p.folderId === folderItem.folderId)?.path || `...${folderItem.folderName}`
|
name: deepPaths.find((p) => p.folderId === folderItem.folderId)?.path || `...${folderItem.folderName}`
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Special case for same folder references as these do not have an entry on the references table
|
||||||
|
const locallyReferenced =
|
||||||
|
secrets
|
||||||
|
?.filter((secret) => {
|
||||||
|
return secrets.some(
|
||||||
|
(otherSecret) =>
|
||||||
|
otherSecret.secretKey !== secret.secretKey && secret.secretValue.includes(`\${${otherSecret.secretKey}}`)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.flatMap((secret) => {
|
||||||
|
return secrets
|
||||||
|
.filter(
|
||||||
|
(otherSecret) =>
|
||||||
|
otherSecret.secretKey !== secret.secretKey &&
|
||||||
|
secret.secretValue.includes(`\${${otherSecret.secretKey}}`)
|
||||||
|
)
|
||||||
|
.map((otherSecret) => ({
|
||||||
|
secretId: secret.secretKey,
|
||||||
|
referencedSecretKey: otherSecret.secretKey
|
||||||
|
}));
|
||||||
|
}) || [];
|
||||||
|
if (locallyReferenced.length > 0) {
|
||||||
|
const existingEnvIndex = result.findIndex((item) => item.environment.slug === environment);
|
||||||
|
|
||||||
|
if (existingEnvIndex >= 0) {
|
||||||
|
const existingFolderIndex = result[existingEnvIndex].folders.findIndex(
|
||||||
|
(folderItem) => folderItem.name === secretPath
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingFolderIndex >= 0) {
|
||||||
|
if (!result[existingEnvIndex].folders[existingFolderIndex].secrets) {
|
||||||
|
result[existingEnvIndex].folders[existingFolderIndex].secrets = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingSecrets = result[existingEnvIndex].folders[existingFolderIndex].secrets || [];
|
||||||
|
locallyReferenced.forEach((ref) => {
|
||||||
|
if (
|
||||||
|
!existingSecrets.some(
|
||||||
|
(s) => s.secretId === ref.secretId && s.referencedSecretKey === ref.referencedSecretKey
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
existingSecrets.push(ref);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result[existingEnvIndex].folders.push({
|
||||||
|
folderId: folder.id,
|
||||||
|
isImported: false,
|
||||||
|
secrets: locallyReferenced,
|
||||||
|
name: secretPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.push({
|
||||||
|
environment: {
|
||||||
|
slug: environment,
|
||||||
|
name: environment
|
||||||
|
},
|
||||||
|
folders: [
|
||||||
|
{
|
||||||
|
folderId: folder.id,
|
||||||
|
isImported: false,
|
||||||
|
secrets: locallyReferenced,
|
||||||
|
name: secretPath
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -54,22 +54,19 @@ export type FolderResult = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type SecretResult = {
|
export type SecretResult = {
|
||||||
envName: string;
|
|
||||||
secretId: string;
|
secretId: string;
|
||||||
folderName: string;
|
referencedSecretKey: string;
|
||||||
folderId: string;
|
} & FolderResult;
|
||||||
envSlug: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FolderInfo = {
|
export type FolderInfo = {
|
||||||
folderName: string;
|
folderName: string;
|
||||||
secrets?: string[];
|
secrets?: { secretId: string; referencedSecretKey: string }[];
|
||||||
folderId: string;
|
folderId: string;
|
||||||
folderImported: boolean;
|
folderImported: boolean;
|
||||||
envSlug?: string;
|
envSlug?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EnvInfo = {
|
export type EnvironmentInfo = {
|
||||||
envName: string;
|
envName: string;
|
||||||
envSlug: string;
|
envSlug: string;
|
||||||
folders: FolderInfo[];
|
folders: FolderInfo[];
|
||||||
|
|||||||
@@ -42,9 +42,12 @@ export type DashboardProjectSecretsDetailsResponse = {
|
|||||||
totalSecretRotationCount?: number;
|
totalSecretRotationCount?: number;
|
||||||
totalCount: number;
|
totalCount: number;
|
||||||
importedBy?: {
|
importedBy?: {
|
||||||
envName: string;
|
environment: { name: string; slug: string };
|
||||||
envSlug: string;
|
folders: {
|
||||||
folders: { folderName: string; secrets?: string[]; folderImported: boolean }[];
|
name: string;
|
||||||
|
secrets?: { secretId: string; referencedSecretKey: string }[];
|
||||||
|
isImported: boolean;
|
||||||
|
}[];
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+39
-32
@@ -5,26 +5,35 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
import { Table, TBody, Td, Th, THead, Tr } from "@app/components/v2";
|
import { Table, TBody, Td, Th, THead, Tr } from "@app/components/v2";
|
||||||
import { useWorkspace } from "@app/context";
|
import { useWorkspace } from "@app/context";
|
||||||
|
|
||||||
|
enum ItemType {
|
||||||
|
Folder = "Folder",
|
||||||
|
Secret = "Secret"
|
||||||
|
}
|
||||||
|
|
||||||
interface FlatItem {
|
interface FlatItem {
|
||||||
type: "folder" | "secret";
|
type: ItemType;
|
||||||
path: string;
|
path: string;
|
||||||
secretKey?: string;
|
secretKey?: string;
|
||||||
reference: string;
|
reference: string;
|
||||||
id: string;
|
id: string;
|
||||||
envName: string;
|
environment: { name: string; slug: string };
|
||||||
envSlug: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CollapsibleSecretImportsProps {
|
interface CollapsibleSecretImportsProps {
|
||||||
importedBy?: {
|
importedBy?: {
|
||||||
envName: string;
|
environment: { name: string; slug: string };
|
||||||
envSlug: string;
|
folders: {
|
||||||
folders: { folderName: string; secrets?: string[]; folderImported: boolean }[];
|
name: string;
|
||||||
|
secrets?: { secretId: string; referencedSecretKey: string }[];
|
||||||
|
isImported: boolean;
|
||||||
|
}[];
|
||||||
}[];
|
}[];
|
||||||
|
secretToDelete: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> = ({
|
export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> = ({
|
||||||
importedBy = []
|
importedBy = [],
|
||||||
|
secretToDelete
|
||||||
}) => {
|
}) => {
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
|
||||||
@@ -43,7 +52,7 @@ export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> =
|
|||||||
|
|
||||||
const handlePathClick = (item: FlatItem) => {
|
const handlePathClick = (item: FlatItem) => {
|
||||||
let pathToNavigate;
|
let pathToNavigate;
|
||||||
if (item.type === "folder") {
|
if (item.type === ItemType.Folder) {
|
||||||
pathToNavigate = item.path;
|
pathToNavigate = item.path;
|
||||||
} else {
|
} else {
|
||||||
const lastSlashIndex = item.path.lastIndexOf("/");
|
const lastSlashIndex = item.path.lastIndexOf("/");
|
||||||
@@ -51,7 +60,7 @@ export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> =
|
|||||||
}
|
}
|
||||||
const encodedPath = encodeURIComponent(pathToNavigate);
|
const encodedPath = encodeURIComponent(pathToNavigate);
|
||||||
window.open(
|
window.open(
|
||||||
`/secret-manager/${currentWorkspace.id}/secrets/${item.envSlug}?secretPath=${encodedPath}`,
|
`/secret-manager/${currentWorkspace.id}/secrets/${item.environment.slug}?secretPath=${encodedPath}`,
|
||||||
"_blank"
|
"_blank"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -61,38 +70,36 @@ export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> =
|
|||||||
|
|
||||||
importedBy.forEach((env) => {
|
importedBy.forEach((env) => {
|
||||||
env.folders.forEach((folder) => {
|
env.folders.forEach((folder) => {
|
||||||
if (folder.folderImported) {
|
if (folder.isImported) {
|
||||||
items.push({
|
items.push({
|
||||||
type: "folder",
|
type: ItemType.Folder,
|
||||||
path: folder.folderName,
|
path: folder.name,
|
||||||
id: `folder-${env.envName}-${folder.folderName}`,
|
id: `folder-${env.environment.name}-${folder.name}`,
|
||||||
reference: "Imported",
|
reference: "Imported",
|
||||||
envName: env.envName,
|
environment: env.environment
|
||||||
envSlug: env.envSlug
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folder.secrets?.length) {
|
if (folder.secrets?.length) {
|
||||||
folder.secrets.forEach((secret) => {
|
folder.secrets.forEach(({ secretId: secret, referencedSecretKey }) => {
|
||||||
const secretPath =
|
const secretPath = folder.name === "/" ? `/${secret}` : `${folder.name}/${secret}`;
|
||||||
folder.folderName === "/" ? `/${secret}` : `${folder.folderName}/${secret}`;
|
if (referencedSecretKey === secretToDelete) {
|
||||||
|
items.push({
|
||||||
items.push({
|
type: ItemType.Secret,
|
||||||
type: "secret",
|
path: secretPath,
|
||||||
path: secretPath,
|
secretKey: referencedSecretKey,
|
||||||
secretKey: secret,
|
id: `secret-${env.environment.name}-${secretPath}`,
|
||||||
id: `secret-${env.envName}-${secretPath}`,
|
reference: "Referenced",
|
||||||
reference: "Referenced",
|
environment: env.environment
|
||||||
envName: env.envName,
|
});
|
||||||
envSlug: env.envSlug
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return items.sort((a, b) => {
|
return items.sort((a, b) => {
|
||||||
const envCompare = a.envName.localeCompare(b.envName);
|
const envCompare = a.environment.name.localeCompare(b.environment.name);
|
||||||
if (envCompare !== 0) return envCompare;
|
if (envCompare !== 0) return envCompare;
|
||||||
|
|
||||||
const aPath = a.path.startsWith("/") ? a.path : `/${a.path}`;
|
const aPath = a.path.startsWith("/") ? a.path : `/${a.path}`;
|
||||||
@@ -142,12 +149,12 @@ export const CollapsibleSecretImports: React.FC<CollapsibleSecretImportsProps> =
|
|||||||
>
|
>
|
||||||
<Td>
|
<Td>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={item.type === "secret" ? faKey : faFileImport}
|
icon={item.type === ItemType.Secret ? faKey : faFileImport}
|
||||||
className={`h-4 w-4 ${item.type === "secret" ? "text-gray-400" : "text-green-700"}`}
|
className={`h-4 w-4 ${item.type === ItemType.Secret ? "text-gray-400" : "text-green-700"}`}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</Td>
|
</Td>
|
||||||
<Td className="px-4">{item.envName}</Td>
|
<Td className="px-4">{item.environment.name}</Td>
|
||||||
<Td className="truncate px-4">{truncatePath(item.path)}</Td>
|
<Td className="truncate px-4">{truncatePath(item.path)}</Td>
|
||||||
<Td className="px-4">{item.reference}</Td>
|
<Td className="px-4">{item.reference}</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
|
|||||||
+13
-5
@@ -30,9 +30,12 @@ type Props = {
|
|||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
isProtectedBranch?: boolean;
|
isProtectedBranch?: boolean;
|
||||||
importedBy?: {
|
importedBy?: {
|
||||||
envName: string;
|
environment: { name: string; slug: string };
|
||||||
envSlug: string;
|
folders: {
|
||||||
folders: { folderName: string; secrets?: string[]; folderImported: boolean }[];
|
name: string;
|
||||||
|
secrets?: { secretId: string; referencedSecretKey: string }[];
|
||||||
|
isImported: boolean;
|
||||||
|
}[];
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -366,7 +369,12 @@ export const SecretListView = ({
|
|||||||
buttonText="Delete Secret"
|
buttonText="Delete Secret"
|
||||||
formContent={
|
formContent={
|
||||||
importedBy &&
|
importedBy &&
|
||||||
importedBy.length > 0 && <CollapsibleSecretImports importedBy={importedBy} />
|
importedBy.length > 0 && (
|
||||||
|
<CollapsibleSecretImports
|
||||||
|
importedBy={importedBy}
|
||||||
|
secretToDelete={(popUp.deleteSecret?.data as SecretV3RawSanitized)?.key}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
deletionMessage={
|
deletionMessage={
|
||||||
<>
|
<>
|
||||||
@@ -374,7 +382,7 @@ export const SecretListView = ({
|
|||||||
<span className="font-bold">
|
<span className="font-bold">
|
||||||
"{(popUp.deleteSecret?.data as SecretV3RawSanitized)?.key}"
|
"{(popUp.deleteSecret?.data as SecretV3RawSanitized)?.key}"
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
below to perform this action
|
to perform this action
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user