Merge pull request #4312 from Infisical/secret-sidebar-details-refactor

improvement(frontend): improve UX and design of secret sidebar/table row
This commit is contained in:
Scott Wilson
2025-08-07 17:53:30 -07:00
committed by GitHub
11 changed files with 861 additions and 893 deletions
@@ -2,6 +2,7 @@ import { ForbiddenError } from "@casl/ability";
import { z } from "zod";
import { SecretFoldersSchema, SecretImportsSchema, UsersSchema } from "@app/db/schemas";
import { RemindersSchema } from "@app/db/schemas/reminders";
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
import { ProjectPermissionSecretActions } from "@app/ee/services/permission/project-permission";
import { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema";
@@ -628,7 +629,10 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
secretValueHidden: z.boolean(),
secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(),
tags: SanitizedTagSchema.array().optional()
tags: SanitizedTagSchema.array().optional(),
reminder: RemindersSchema.extend({
recipients: z.string().array().optional()
}).nullish()
})
.array()
.optional(),
@@ -706,7 +710,11 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
let imports: Awaited<ReturnType<typeof server.services.secretImport.getImports>> | undefined;
let folders: Awaited<ReturnType<typeof server.services.folder.getFolders>> | undefined;
let secrets: Awaited<ReturnType<typeof server.services.secret.getSecretsRaw>>["secrets"] | undefined;
let secrets:
| (Awaited<ReturnType<typeof server.services.secret.getSecretsRaw>>["secrets"][number] & {
reminder: Awaited<ReturnType<typeof server.services.reminder.getRemindersForDashboard>>[string] | null;
})[]
| undefined;
let dynamicSecrets: Awaited<ReturnType<typeof server.services.dynamicSecret.listDynamicSecretsByEnv>> | undefined;
let secretRotations:
| Awaited<ReturnType<typeof server.services.secretRotationV2.getDashboardSecretRotations>>
@@ -904,7 +912,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
});
if (remainingLimit > 0 && totalSecretCount > adjustedOffset) {
secrets = (
const rawSecrets = (
await server.services.secret.getSecretsRaw({
actorId: req.permission.id,
actor: req.permission.type,
@@ -925,6 +933,15 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
includeMetadataInSearch: true
})
).secrets;
const reminders = await server.services.reminder.getRemindersForDashboard(
rawSecrets.map((secret) => secret.id)
);
secrets = rawSecrets.map((secret) => ({
...secret,
reminder: reminders[secret.id] ?? null
}));
}
}
} catch (error) {
+26 -1
View File
@@ -124,10 +124,35 @@ export const reminderDALFactory = (db: TDbClient) => {
return reminders[0] || null;
};
const findSecretReminders = async (secretIds: string[], tx?: Knex) => {
const rawReminders = await (tx || db)(TableName.Reminder)
.whereIn(`${TableName.Reminder}.secretId`, secretIds)
.leftJoin(TableName.ReminderRecipient, `${TableName.Reminder}.id`, `${TableName.ReminderRecipient}.reminderId`)
.select(selectAllTableCols(TableName.Reminder))
.select(db.ref("userId").withSchema(TableName.ReminderRecipient));
const reminders = sqlNestRelationships({
data: rawReminders,
key: "id",
parentMapper: (el) => ({
_id: el.id,
...RemindersSchema.parse(el)
}),
childrenMapper: [
{
key: "userId",
label: "recipients" as const,
mapper: ({ userId }) => userId
}
]
});
return reminders;
};
return {
...reminderOrm,
findSecretDailyReminders,
findUpcomingReminders,
findSecretReminder
findSecretReminder,
findSecretReminders
};
};
@@ -372,6 +372,21 @@ export const reminderServiceFactory = ({
};
};
const getRemindersForDashboard: TReminderServiceFactory["getRemindersForDashboard"] = async (secretIds) => {
// scott we don't need to check permissions/secret existence because these are the
// secrets from the dashboard that have already gone through these checks
const reminders = await reminderDAL.findSecretReminders(secretIds);
const reminderMap: Record<string, (typeof reminders)[number]> = {};
reminders.forEach((reminder) => {
if (reminder.secretId) reminderMap[reminder.secretId] = reminder;
});
return reminderMap;
};
return {
createReminder,
getReminder,
@@ -379,6 +394,7 @@ export const reminderServiceFactory = ({
deleteReminder,
deleteReminderBySecretId,
batchCreateReminders,
createReminderInternal
createReminderInternal,
getRemindersForDashboard
};
};
@@ -103,4 +103,6 @@ export interface TReminderServiceFactory {
id: string;
created: boolean;
}>;
getRemindersForDashboard: (secretIds: string[]) => Promise<Record<string, TReminder & { recipients: string[] }>>;
}