mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 13:28:27 +00:00
feat: secret approval and replication
This commit is contained in:
@@ -19,8 +19,22 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
tb.timestamps(true, true, true);
|
tb.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasSecretMetadataField = await knex.schema.hasColumn(TableName.SecretApprovalRequestSecretV2, "secretMetadata");
|
||||||
|
if (!hasSecretMetadataField) {
|
||||||
|
await knex.schema.alterTable(TableName.SecretApprovalRequestSecretV2, (t) => {
|
||||||
|
t.jsonb("secretMetadata");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
await knex.schema.dropTableIfExists(TableName.ResourceMetadata);
|
await knex.schema.dropTableIfExists(TableName.ResourceMetadata);
|
||||||
|
|
||||||
|
const hasSecretMetadataField = await knex.schema.hasColumn(TableName.SecretApprovalRequestSecretV2, "secretMetadata");
|
||||||
|
if (hasSecretMetadataField) {
|
||||||
|
await knex.schema.alterTable(TableName.SecretApprovalRequestSecretV2, (t) => {
|
||||||
|
t.dropColumn("secretMetadata");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export const SecretApprovalRequestsSecretsV2Schema = z.object({
|
|||||||
requestId: z.string().uuid(),
|
requestId: z.string().uuid(),
|
||||||
op: z.string(),
|
op: z.string(),
|
||||||
secretId: z.string().uuid().nullable().optional(),
|
secretId: z.string().uuid().nullable().optional(),
|
||||||
secretVersion: z.string().uuid().nullable().optional()
|
secretVersion: z.string().uuid().nullable().optional(),
|
||||||
|
secretMetadata: z.unknown().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretApprovalRequestsSecretsV2 = z.infer<typeof SecretApprovalRequestsSecretsV2Schema>;
|
export type TSecretApprovalRequestsSecretsV2 = z.infer<typeof SecretApprovalRequestsSecretsV2Schema>;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
|||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { secretRawSchema } from "@app/server/routes/sanitizedSchemas";
|
import { secretRawSchema } from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
|
|
||||||
const approvalRequestUser = z.object({ userId: z.string().nullable().optional() }).merge(
|
const approvalRequestUser = z.object({ userId: z.string().nullable().optional() }).merge(
|
||||||
UsersSchema.pick({
|
UsersSchema.pick({
|
||||||
@@ -274,6 +275,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
.extend({
|
.extend({
|
||||||
op: z.string(),
|
op: z.string(),
|
||||||
tags: tagSchema,
|
tags: tagSchema,
|
||||||
|
secretMetadata: ResourceMetadataSchema.nullish(),
|
||||||
secret: z
|
secret: z
|
||||||
.object({
|
.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
@@ -291,7 +293,8 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
secretKey: z.string(),
|
secretKey: z.string(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
secretComment: z.string().optional(),
|
secretComment: z.string().optional(),
|
||||||
tags: tagSchema
|
tags: tagSchema,
|
||||||
|
secretMetadata: ResourceMetadataSchema.nullish()
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SecretVersionV2Tag}.${TableName.SecretTag}Id`,
|
`${TableName.SecretVersionV2Tag}.${TableName.SecretTag}Id`,
|
||||||
db.ref("id").withSchema("secVerTag")
|
db.ref("id").withSchema("secVerTag")
|
||||||
)
|
)
|
||||||
|
.leftJoin(TableName.ResourceMetadata, `${TableName.SecretV2}.id`, `${TableName.ResourceMetadata}.secretId`)
|
||||||
.select(selectAllTableCols(TableName.SecretApprovalRequestSecretV2))
|
.select(selectAllTableCols(TableName.SecretApprovalRequestSecretV2))
|
||||||
.select({
|
.select({
|
||||||
secVerTagId: "secVerTag.id",
|
secVerTagId: "secVerTag.id",
|
||||||
@@ -279,6 +280,11 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("key").withSchema(TableName.SecretVersionV2).as("secVerKey"),
|
db.ref("key").withSchema(TableName.SecretVersionV2).as("secVerKey"),
|
||||||
db.ref("encryptedValue").withSchema(TableName.SecretVersionV2).as("secVerValue"),
|
db.ref("encryptedValue").withSchema(TableName.SecretVersionV2).as("secVerValue"),
|
||||||
db.ref("encryptedComment").withSchema(TableName.SecretVersionV2).as("secVerComment")
|
db.ref("encryptedComment").withSchema(TableName.SecretVersionV2).as("secVerComment")
|
||||||
|
)
|
||||||
|
.select(
|
||||||
|
db.ref("id").withSchema(TableName.ResourceMetadata).as("metadataId"),
|
||||||
|
db.ref("key").withSchema(TableName.ResourceMetadata).as("metadataKey"),
|
||||||
|
db.ref("value").withSchema(TableName.ResourceMetadata).as("metadataValue")
|
||||||
);
|
);
|
||||||
const formatedDoc = sqlNestRelationships({
|
const formatedDoc = sqlNestRelationships({
|
||||||
data: doc,
|
data: doc,
|
||||||
@@ -338,9 +344,19 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "metadataId",
|
||||||
|
label: "oldSecretMetadata" as const,
|
||||||
|
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
||||||
|
id: metadataId,
|
||||||
|
key: metadataKey,
|
||||||
|
value: metadataValue
|
||||||
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
return formatedDoc?.map(({ secret, secretVersion, ...el }) => ({
|
return formatedDoc?.map(({ secret, secretVersion, ...el }) => ({
|
||||||
...el,
|
...el,
|
||||||
secret: secret?.[0],
|
secret: secret?.[0],
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
|
|||||||
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||||
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
||||||
import { TResourceMetadataDALFactory } from "@app/services/resource-metadata/resource-metadata-dal";
|
import { TResourceMetadataDALFactory } from "@app/services/resource-metadata/resource-metadata-dal";
|
||||||
|
import { ResourceMetadataDTO } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
import { TSecretDALFactory } from "@app/services/secret/secret-dal";
|
import { TSecretDALFactory } from "@app/services/secret/secret-dal";
|
||||||
import {
|
import {
|
||||||
decryptSecretWithBot,
|
decryptSecretWithBot,
|
||||||
@@ -244,6 +245,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretKey: el.key,
|
secretKey: el.key,
|
||||||
id: el.id,
|
id: el.id,
|
||||||
version: el.version,
|
version: el.version,
|
||||||
|
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
||||||
secretValue: el.encryptedValue ? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString() : "",
|
secretValue: el.encryptedValue ? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString() : "",
|
||||||
secretComment: el.encryptedComment
|
secretComment: el.encryptedComment
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
||||||
@@ -272,7 +274,8 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretComment: el.secretVersion.encryptedComment
|
secretComment: el.secretVersion.encryptedComment
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.secretVersion.encryptedComment }).toString()
|
? secretManagerDecryptor({ cipherTextBlob: el.secretVersion.encryptedComment }).toString()
|
||||||
: "",
|
: "",
|
||||||
tags: el.secretVersion.tags
|
tags: el.secretVersion.tags,
|
||||||
|
secretMetadata: el.oldSecretMetadata as ResourceMetadataDTO
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}));
|
}));
|
||||||
@@ -554,6 +557,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
encryptedValue: el.encryptedValue,
|
encryptedValue: el.encryptedValue,
|
||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
key: el.key,
|
key: el.key,
|
||||||
|
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
||||||
references: el.encryptedValue
|
references: el.encryptedValue
|
||||||
? getAllSecretReferencesV2Bridge(
|
? getAllSecretReferencesV2Bridge(
|
||||||
secretManagerDecryptor({
|
secretManagerDecryptor({
|
||||||
@@ -598,6 +602,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
key: el.key,
|
key: el.key,
|
||||||
tags: el?.tags.map(({ id }) => id),
|
tags: el?.tags.map(({ id }) => id),
|
||||||
|
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
||||||
...encryptedValue
|
...encryptedValue
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1216,6 +1221,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
),
|
),
|
||||||
skipMultilineEncoding: createdSecret.skipMultilineEncoding,
|
skipMultilineEncoding: createdSecret.skipMultilineEncoding,
|
||||||
key: createdSecret.secretKey,
|
key: createdSecret.secretKey,
|
||||||
|
secretMetadata: createdSecret.secretMetadata,
|
||||||
type: SecretType.Shared
|
type: SecretType.Shared
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
@@ -1271,12 +1277,14 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
reminderNote,
|
reminderNote,
|
||||||
secretComment,
|
secretComment,
|
||||||
metadata,
|
metadata,
|
||||||
skipMultilineEncoding
|
skipMultilineEncoding,
|
||||||
|
secretMetadata
|
||||||
}) => {
|
}) => {
|
||||||
const secretId = updatingSecretsGroupByKey[secretKey][0].id;
|
const secretId = updatingSecretsGroupByKey[secretKey][0].id;
|
||||||
if (tagIds?.length) commitTagIds[secretKey] = tagIds;
|
if (tagIds?.length) commitTagIds[secretKey] = tagIds;
|
||||||
return {
|
return {
|
||||||
...latestSecretVersions[secretId],
|
...latestSecretVersions[secretId],
|
||||||
|
secretMetadata,
|
||||||
key: newSecretName || secretKey,
|
key: newSecretName || secretKey,
|
||||||
encryptedComment: setKnexStringValue(
|
encryptedComment: setKnexStringValue(
|
||||||
secretComment,
|
secretComment,
|
||||||
@@ -1378,7 +1386,8 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
reminderRepeatDays,
|
reminderRepeatDays,
|
||||||
encryptedValue,
|
encryptedValue,
|
||||||
secretId,
|
secretId,
|
||||||
secretVersion
|
secretVersion,
|
||||||
|
secretMetadata
|
||||||
}) => ({
|
}) => ({
|
||||||
version,
|
version,
|
||||||
requestId: doc.id,
|
requestId: doc.id,
|
||||||
@@ -1391,7 +1400,8 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
reminderRepeatDays,
|
reminderRepeatDays,
|
||||||
reminderNote,
|
reminderNote,
|
||||||
encryptedComment,
|
encryptedComment,
|
||||||
key
|
key,
|
||||||
|
secretMetadata: JSON.stringify(secretMetadata)
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
tx
|
tx
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { TImmutableDBKeys, TSecretApprovalPolicies, TSecretApprovalRequestsSecrets } from "@app/db/schemas";
|
import { TImmutableDBKeys, TSecretApprovalPolicies, TSecretApprovalRequestsSecrets } from "@app/db/schemas";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
import { ResourceMetadataDTO } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
import { SecretOperations } from "@app/services/secret/secret-types";
|
import { SecretOperations } from "@app/services/secret/secret-types";
|
||||||
|
|
||||||
export enum RequestState {
|
export enum RequestState {
|
||||||
@@ -34,6 +35,7 @@ export type TApprovalCreateSecretV2Bridge = {
|
|||||||
reminderRepeatDays?: number | null;
|
reminderRepeatDays?: number | null;
|
||||||
skipMultilineEncoding?: boolean;
|
skipMultilineEncoding?: boolean;
|
||||||
metadata?: Record<string, string>;
|
metadata?: Record<string, string>;
|
||||||
|
secretMetadata?: ResourceMetadataDTO;
|
||||||
tagIds?: string[];
|
tagIds?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -396,6 +396,7 @@ export const secretReplicationServiceFactory = ({
|
|||||||
op: operation,
|
op: operation,
|
||||||
requestId: approvalRequestDoc.id,
|
requestId: approvalRequestDoc.id,
|
||||||
metadata: doc.metadata,
|
metadata: doc.metadata,
|
||||||
|
secretMetadata: JSON.stringify(doc.secretMetadata),
|
||||||
key: doc.key,
|
key: doc.key,
|
||||||
encryptedValue: doc.encryptedValue,
|
encryptedValue: doc.encryptedValue,
|
||||||
encryptedComment: doc.encryptedComment,
|
encryptedComment: doc.encryptedComment,
|
||||||
|
|||||||
@@ -1419,7 +1419,8 @@ export const secretServiceFactory = ({
|
|||||||
secretValue,
|
secretValue,
|
||||||
tagIds,
|
tagIds,
|
||||||
reminderNote: secretReminderNote,
|
reminderNote: secretReminderNote,
|
||||||
reminderRepeatDays: secretReminderRepeatDays
|
reminderRepeatDays: secretReminderRepeatDays,
|
||||||
|
secretMetadata
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1562,7 +1563,8 @@ export const secretServiceFactory = ({
|
|||||||
secretValue,
|
secretValue,
|
||||||
tagIds,
|
tagIds,
|
||||||
reminderNote: secretReminderNote,
|
reminderNote: secretReminderNote,
|
||||||
reminderRepeatDays: secretReminderRepeatDays
|
reminderRepeatDays: secretReminderRepeatDays,
|
||||||
|
secretMetadata
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1803,7 +1805,8 @@ export const secretServiceFactory = ({
|
|||||||
secretComment: el.secretComment,
|
secretComment: el.secretComment,
|
||||||
metadata: el.metadata,
|
metadata: el.metadata,
|
||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
secretKey: el.secretKey
|
secretKey: el.secretKey,
|
||||||
|
secretMetadata: el.secretMetadata
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ export type TCreateManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
|
|||||||
secretComment?: string;
|
secretComment?: string;
|
||||||
skipMultilineEncoding?: boolean;
|
skipMultilineEncoding?: boolean;
|
||||||
tagIds?: string[];
|
tagIds?: string[];
|
||||||
|
secretMetadata?: ResourceMetadataDTO;
|
||||||
metadata?: {
|
metadata?: {
|
||||||
source?: string;
|
source?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ export type TSecretApprovalRequest = {
|
|||||||
conflicts: Array<{ secretId: string; op: CommitType.UPDATE }>;
|
conflicts: Array<{ secretId: string; op: CommitType.UPDATE }>;
|
||||||
commits: ({
|
commits: ({
|
||||||
// if there is no secret means it was creation
|
// if there is no secret means it was creation
|
||||||
|
secretMetadata?: { key: string; value: string }[];
|
||||||
secret?: { version: number };
|
secret?: { version: number };
|
||||||
secretVersion: SecretV3Raw;
|
secretVersion: SecretV3Raw;
|
||||||
// if there is no new version its for Delete
|
// if there is no new version its for Delete
|
||||||
|
|||||||
+92
-7
@@ -1,4 +1,4 @@
|
|||||||
import { faExclamationTriangle, faInfo } from "@fortawesome/free-solid-svg-icons";
|
import { faExclamationTriangle, faInfo, faKey } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -18,7 +18,10 @@ import { CommitType, SecretV3Raw, TSecretApprovalSecChange, WsTag } from "@app/h
|
|||||||
export type Props = {
|
export type Props = {
|
||||||
op: CommitType;
|
op: CommitType;
|
||||||
secretVersion?: SecretV3Raw;
|
secretVersion?: SecretV3Raw;
|
||||||
newVersion?: Omit<TSecretApprovalSecChange, "tags"> & { tags?: WsTag[] };
|
newVersion?: Omit<TSecretApprovalSecChange, "tags"> & {
|
||||||
|
tags?: WsTag[];
|
||||||
|
secretMetadata?: { key: string; value: string }[];
|
||||||
|
};
|
||||||
presentSecretVersionNumber: number;
|
presentSecretVersionNumber: number;
|
||||||
hasMerged?: Boolean;
|
hasMerged?: Boolean;
|
||||||
conflicts: Array<{ secretId: string; op: CommitType }>;
|
conflicts: Array<{ secretId: string; op: CommitType }>;
|
||||||
@@ -80,11 +83,12 @@ export const SecretApprovalRequestChangeItem = ({
|
|||||||
<Table>
|
<Table>
|
||||||
<THead>
|
<THead>
|
||||||
<Tr>
|
<Tr>
|
||||||
{op === CommitType.UPDATE && <Th className="w-12" />}
|
{op === CommitType.UPDATE && <Th className="w-12 shrink-0" />}
|
||||||
<Th className="min-table-row">Secret</Th>
|
<Th className="w-48 shrink-0">Secret</Th>
|
||||||
<Th>Value</Th>
|
<Th className="min-w-0 flex-1">Value</Th>
|
||||||
<Th className="min-table-row">Comment</Th>
|
<Th className="w-24 shrink-0">Comment</Th>
|
||||||
<Th className="min-table-row">Tags</Th>
|
<Th className="w-24 shrink-0">Tags</Th>
|
||||||
|
<Th className="w-40 shrink-0">Metadata</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</THead>
|
</THead>
|
||||||
{op === CommitType.UPDATE ? (
|
{op === CommitType.UPDATE ? (
|
||||||
@@ -110,6 +114,33 @@ export const SecretApprovalRequestChangeItem = ({
|
|||||||
</Tag>
|
</Tag>
|
||||||
))}
|
))}
|
||||||
</Td>
|
</Td>
|
||||||
|
<Td>
|
||||||
|
{secretVersion?.secretMetadata?.length ? (
|
||||||
|
<div className="mt-1 flex flex-wrap gap-2 text-sm text-mineshaft-300">
|
||||||
|
{secretVersion.secretMetadata?.map((el) => (
|
||||||
|
<div key={el.key} className="flex items-center">
|
||||||
|
<Tag
|
||||||
|
size="xs"
|
||||||
|
className="mr-0 flex items-center rounded-r-none border border-mineshaft-500"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faKey} size="xs" className="mr-1" />
|
||||||
|
<div>{el.key}</div>
|
||||||
|
</Tag>
|
||||||
|
<Tag
|
||||||
|
size="xs"
|
||||||
|
className="flex items-center rounded-l-none border border-mineshaft-500 bg-mineshaft-900 pl-1"
|
||||||
|
>
|
||||||
|
<div className="max-w-[150px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||||
|
{el.value}
|
||||||
|
</div>
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-mineshaft-300">-</p>
|
||||||
|
)}
|
||||||
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Td className="text-green-600">NEW</Td>
|
<Td className="text-green-600">NEW</Td>
|
||||||
@@ -132,6 +163,33 @@ export const SecretApprovalRequestChangeItem = ({
|
|||||||
</Tag>
|
</Tag>
|
||||||
))}
|
))}
|
||||||
</Td>
|
</Td>
|
||||||
|
<Td>
|
||||||
|
{newVersion?.secretMetadata?.length ? (
|
||||||
|
<div className="mt-1 flex flex-wrap gap-2 text-sm text-mineshaft-300">
|
||||||
|
{newVersion.secretMetadata?.map((el) => (
|
||||||
|
<div key={el.key} className="flex items-center">
|
||||||
|
<Tag
|
||||||
|
size="xs"
|
||||||
|
className="mr-0 flex items-center rounded-r-none border border-mineshaft-500"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faKey} size="xs" className="mr-1" />
|
||||||
|
<div>{el.key}</div>
|
||||||
|
</Tag>
|
||||||
|
<Tag
|
||||||
|
size="xs"
|
||||||
|
className="flex items-center rounded-l-none border border-mineshaft-500 bg-mineshaft-900 pl-1"
|
||||||
|
>
|
||||||
|
<div className="max-w-[150px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||||
|
{el.value}
|
||||||
|
</div>
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-mineshaft-300">-</p>
|
||||||
|
)}
|
||||||
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
</TBody>
|
</TBody>
|
||||||
) : (
|
) : (
|
||||||
@@ -173,6 +231,33 @@ export const SecretApprovalRequestChangeItem = ({
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
|
<Td>
|
||||||
|
{newVersion?.secretMetadata?.length ? (
|
||||||
|
<div className="mt-1 flex flex-wrap gap-2 text-sm text-mineshaft-300">
|
||||||
|
{newVersion.secretMetadata?.map((el) => (
|
||||||
|
<div key={el.key} className="flex items-center">
|
||||||
|
<Tag
|
||||||
|
size="xs"
|
||||||
|
className="mr-0 flex items-center rounded-r-none border border-mineshaft-500"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faKey} size="xs" className="mr-1" />
|
||||||
|
<div>{el.key}</div>
|
||||||
|
</Tag>
|
||||||
|
<Tag
|
||||||
|
size="xs"
|
||||||
|
className="flex items-center rounded-l-none border border-mineshaft-500 bg-mineshaft-900 pl-1"
|
||||||
|
>
|
||||||
|
<div className="max-w-[150px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||||
|
{el.value}
|
||||||
|
</div>
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-mineshaft-300">-</p>
|
||||||
|
)}
|
||||||
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
</TBody>
|
</TBody>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user