From 66e7b44fef0eef0baf16580809a171d2b472d70c Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Mon, 27 Oct 2025 10:20:07 -0300 Subject: [PATCH] feat(secret-sync): add support for secret sync error notifications in project router and Slack integration, including channel selection enhancements --- .../routes/v1/deprecated-project-router.ts | 8 +- .../src/services/project/project-service.ts | 4 +- .../components/SlackIntegrationForm.tsx | 123 +++++++++--------- 3 files changed, 71 insertions(+), 64 deletions(-) diff --git a/backend/src/server/routes/v1/deprecated-project-router.ts b/backend/src/server/routes/v1/deprecated-project-router.ts index 687d95b9b..f6efdb78a 100644 --- a/backend/src/server/routes/v1/deprecated-project-router.ts +++ b/backend/src/server/routes/v1/deprecated-project-router.ts @@ -614,8 +614,10 @@ export const registerDeprecatedProjectRouter = async (server: FastifyZodProvider integrationId: z.string(), accessRequestChannels: validateSlackChannelsField, secretRequestChannels: validateSlackChannelsField, + secretSyncErrorChannels: validateSlackChannelsField, isAccessRequestNotificationEnabled: z.boolean(), - isSecretRequestNotificationEnabled: z.boolean() + isSecretRequestNotificationEnabled: z.boolean(), + isSecretSyncErrorNotificationEnabled: z.boolean() }), z.object({ integration: z.literal(WorkflowIntegration.MICROSOFT_TEAMS), @@ -633,7 +635,9 @@ export const registerDeprecatedProjectRouter = async (server: FastifyZodProvider isAccessRequestNotificationEnabled: true, accessRequestChannels: true, isSecretRequestNotificationEnabled: true, - secretRequestChannels: true + secretRequestChannels: true, + isSecretSyncErrorNotificationEnabled: true, + secretSyncErrorChannels: true }).merge( z.object({ integration: z.literal(WorkflowIntegration.SLACK), diff --git a/backend/src/services/project/project-service.ts b/backend/src/services/project/project-service.ts index 3c6d541ce..19a13f45b 100644 --- a/backend/src/services/project/project-service.ts +++ b/backend/src/services/project/project-service.ts @@ -1573,8 +1573,8 @@ export const projectServiceFactory = ({ isSecretSyncErrorNotificationEnabled }: TUpdateProjectWorkflowIntegration & { // workaround intersection type while we don't have the microsoft teams integration for failed secret syncs - isSecretSyncErrorNotificationEnabled: boolean; - secretSyncErrorChannels: string; + isSecretSyncErrorNotificationEnabled?: boolean; + secretSyncErrorChannels?: string; }) => { const project = await projectDAL.findById(projectId); if (!project) { diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx index 6092a465e..cf5113fad 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx @@ -44,6 +44,69 @@ const formSchema = z.object({ type TSlackConfigForm = z.infer; +type TChannelSelectorProps = { + value: string[]; + onChange: (value: string[]) => void; + error?: { message?: string }; + slackChannelIdToName: Record; + sortedSlackChannels?: { id: string; name: string }[]; + keyPrefix: string; +}; + +const ChannelSelector = ({ + value, + onChange, + error, + slackChannelIdToName, + sortedSlackChannels, + keyPrefix +}: TChannelSelectorProps) => ( + + + + slackChannelIdToName[entry]) + .join(", ")} + className="text-left" + /> + + + {sortedSlackChannels?.map((slackChannel) => { + const isChecked = value?.includes(slackChannel.id); + return ( + { + evt.preventDefault(); + onChange( + isChecked + ? value?.filter((el: string) => el !== slackChannel.id) + : [...(value || []), slackChannel.id] + ); + }} + key={`${keyPrefix}-slack-channel-${slackChannel.id}`} + iconPos="right" + icon={isChecked && } + > + {slackChannel.name} + + ); + })} + + + +); + type Props = { onClose: () => void; }; @@ -320,63 +383,3 @@ export const SlackIntegrationForm = ({ onClose }: Props) => { ); }; - -type TChannelSelectorProps = { - value: string[]; - onChange: (value: string[]) => void; - error?: { message?: string }; - slackChannelIdToName: Record; - sortedSlackChannels?: { id: string; name: string }[]; - keyPrefix: string; -}; - -const ChannelSelector = ({ - value, - onChange, - error, - slackChannelIdToName, - sortedSlackChannels, - keyPrefix -}: TChannelSelectorProps) => ( - - - - slackChannelIdToName[entry]).join(", ")} - className="text-left" - /> - - - {sortedSlackChannels?.map((slackChannel) => { - const isChecked = value?.includes(slackChannel.id); - return ( - { - evt.preventDefault(); - onChange( - isChecked - ? value?.filter((el: string) => el !== slackChannel.id) - : [...(value || []), slackChannel.id] - ); - }} - key={`${keyPrefix}-slack-channel-${slackChannel.id}`} - iconPos="right" - icon={isChecked && } - > - {slackChannel.name} - - ); - })} - - - -); \ No newline at end of file