Merge branch 'main' into feature/secret-reference-shortcut

This commit is contained in:
Victor Santos
2025-11-10 14:20:23 -03:00
241 changed files with 13145 additions and 897 deletions
@@ -160,14 +160,18 @@ export const SecretApprovalRequestChanges = ({ approvalRequestId, onGoBack }: Pr
secretApprovalRequestDetails.policy.bypassers.some(({ userId }) => userId === userSession.id);
const reviewedUsers = secretApprovalRequestDetails?.reviewers?.reduce<
Record<string, { status: ApprovalStatus; comment: string; isOrgMembershipActive: boolean }>
Record<
string,
{ status: ApprovalStatus; comment: string; isOrgMembershipActive: boolean; createdAt: Date }
>
>(
(prev, curr) => ({
...prev,
[curr.userId]: {
status: curr.status,
comment: curr.comment,
isOrgMembershipActive: curr.isOrgMembershipActive
isOrgMembershipActive: curr.isOrgMembershipActive,
createdAt: curr.createdAt
}
}),
{}
@@ -488,7 +492,7 @@ export const SecretApprovalRequestChanges = ({ approvalRequestId, onGoBack }: Pr
</span>{" "}
the request on{" "}
{format(
new Date(secretApprovalRequestDetails.createdAt),
new Date(reviewer ? reviewer.createdAt : new Date()),
"MM/dd/yyyy h:mm:ss aa"
)}
.
@@ -111,7 +111,7 @@ export const WorkflowIntegrationTab = () => {
<Td>Provider</Td>
<Td>Access Request Notifications Destination</Td>
<Td>Secret Request Notifications Destination</Td>
<Td />
<Td>Secret Sync Error Notifications Destination</Td>
</Tr>
</THead>
<TBody>
@@ -99,7 +99,9 @@ export const MicrosoftTeamsConfigRow = ({
</Badge>
)}
</Td>
<Td>
<Badge variant="danger">Disabled</Badge>
</Td>
<Td>
<DropdownMenu>
<DropdownMenuTrigger asChild className="rounded-lg">
@@ -96,7 +96,25 @@ export const SlackConfigRow = ({ handlePopUpOpen, isSlackConfigLoading, slackCon
</Badge>
)}
</Td>
<Td>
{slackConfig.isSecretSyncErrorNotificationEnabled &&
!isLoadingConfig &&
slackConfig.secretSyncErrorChannels.length > 0 ? (
<p>
{slackConfig.secretSyncErrorChannels
.split(", ")
.map((channel) => slackChannelIdToName[channel])
.join(", ")}
</p>
) : isLoadingConfig ? (
<Spinner size="xs" />
) : (
<Badge variant="neutral">
<BanIcon />
Disabled
</Badge>
)}
</Td>
<Td>
<DropdownMenu>
<DropdownMenuTrigger asChild className="rounded-lg">
@@ -37,11 +37,76 @@ const formSchema = z.object({
isSecretRequestNotificationEnabled: z.boolean(),
secretRequestChannels: z.string().array(),
isAccessRequestNotificationEnabled: z.boolean(),
accessRequestChannels: z.string().array()
accessRequestChannels: z.string().array(),
isSecretSyncErrorNotificationEnabled: z.boolean(),
secretSyncErrorChannels: z.string().array()
});
type TSlackConfigForm = z.infer<typeof formSchema>;
type TChannelSelectorProps = {
value: string[];
onChange: (value: string[]) => void;
error?: { message?: string };
slackChannelIdToName: Record<string, string>;
sortedSlackChannels?: { id: string; name: string }[];
keyPrefix: string;
};
const ChannelSelector = ({
value,
onChange,
error,
slackChannelIdToName,
sortedSlackChannels,
keyPrefix
}: TChannelSelectorProps) => (
<FormControl label="Slack channels" isError={Boolean(error)} errorText={error?.message}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Input
isReadOnly
value={value
?.filter(Boolean)
.map((entry) => slackChannelIdToName[entry])
.join(", ")}
className="text-left"
/>
</DropdownMenuTrigger>
<DropdownMenuContent
style={{
width: "var(--radix-dropdown-menu-trigger-width)",
maxHeight: "350px",
overflowY: "auto"
}}
side="bottom"
align="start"
>
{sortedSlackChannels?.map((slackChannel) => {
const isChecked = value?.includes(slackChannel.id);
return (
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
onChange(
isChecked
? value?.filter((el: string) => el !== slackChannel.id)
: [...(value || []), slackChannel.id]
);
}}
key={`${keyPrefix}-slack-channel-${slackChannel.id}`}
iconPos="right"
icon={isChecked && <FontAwesomeIcon icon={faCheckCircle} />}
>
{slackChannel.name}
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
</FormControl>
);
type Props = {
onClose: () => void;
};
@@ -71,7 +136,9 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
isAccessRequestNotificationEnabled: false,
accessRequestChannels: [],
isSecretRequestNotificationEnabled: false,
secretRequestChannels: []
secretRequestChannels: [],
isSecretSyncErrorNotificationEnabled: false,
secretSyncErrorChannels: []
}
});
@@ -86,7 +153,8 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
integration: WorkflowIntegrationPlatform.SLACK,
integrationId: data.slackIntegrationId,
accessRequestChannels: data.accessRequestChannels.filter(Boolean).join(", "),
secretRequestChannels: data.secretRequestChannels.filter(Boolean).join(", ")
secretRequestChannels: data.secretRequestChannels.filter(Boolean).join(", "),
secretSyncErrorChannels: data.secretSyncErrorChannels.filter(Boolean).join(", ")
});
createNotification({
@@ -100,6 +168,7 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
const secretRequestNotifState = watch("isSecretRequestNotificationEnabled");
const selectedSlackIntegrationId = watch("slackIntegrationId");
const accessRequestNotifState = watch("isAccessRequestNotificationEnabled");
const secretSyncErrorNotifState = watch("isSecretSyncErrorNotificationEnabled");
const { data: slackChannels } = useGetSlackIntegrationChannels(selectedSlackIntegrationId);
const slackChannelIdToName = Object.fromEntries(
@@ -110,7 +179,7 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
);
useEffect(() => {
if (slackConfig) {
if (slackConfig && slackConfig.integration === WorkflowIntegrationPlatform.SLACK) {
setValue("slackIntegrationId", slackConfig.integrationId);
setValue(
"isSecretRequestNotificationEnabled",
@@ -120,22 +189,30 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
"isAccessRequestNotificationEnabled",
slackConfig.isAccessRequestNotificationEnabled
);
setValue(
"isSecretSyncErrorNotificationEnabled",
slackConfig.isSecretSyncErrorNotificationEnabled
);
if (slackConfig.integration === WorkflowIntegrationPlatform.SLACK) {
if (slackChannels) {
setValue(
"secretRequestChannels",
slackConfig.secretRequestChannels
.split(", ")
.filter((channel) => channel in slackChannelIdToName)
);
setValue(
"accessRequestChannels",
slackConfig.accessRequestChannels
.split(", ")
.filter((channel) => channel in slackChannelIdToName)
);
}
if (slackChannels) {
setValue(
"secretRequestChannels",
(slackConfig.secretRequestChannels || "")
.split(", ")
.filter((channel) => channel in slackChannelIdToName)
);
setValue(
"accessRequestChannels",
(slackConfig.accessRequestChannels || "")
.split(", ")
.filter((channel) => channel in slackChannelIdToName)
);
setValue(
"secretSyncErrorChannels",
(slackConfig.secretSyncErrorChannels || "")
.split(", ")
.filter((channel) => channel in slackChannelIdToName)
);
}
}
}, [slackConfig, slackChannels]);
@@ -208,54 +285,14 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
control={control}
name="secretRequestChannels"
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
label="Slack channels"
isError={Boolean(error)}
errorText={error?.message}
>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Input
isReadOnly
value={value
?.filter(Boolean)
.map((entry) => slackChannelIdToName[entry])
.join(", ")}
className="text-left"
/>
</DropdownMenuTrigger>
<DropdownMenuContent
style={{
width: "var(--radix-dropdown-menu-trigger-width)",
maxHeight: "350px",
overflowY: "auto"
}}
side="bottom"
align="start"
>
{sortedSlackChannels?.map((slackChannel) => {
const isChecked = value?.includes(slackChannel.id);
return (
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
onChange(
isChecked
? value?.filter((el: string) => el !== slackChannel.id)
: [...(value || []), slackChannel.id]
);
}}
key={`secret-requests-slack-channel-${slackChannel.id}`}
iconPos="right"
icon={isChecked && <FontAwesomeIcon icon={faCheckCircle} />}
>
{slackChannel.name}
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
</FormControl>
<ChannelSelector
value={value}
onChange={onChange}
error={error}
slackChannelIdToName={slackChannelIdToName}
sortedSlackChannels={sortedSlackChannels}
keyPrefix="secret-requests"
/>
)}
/>
)}
@@ -281,54 +318,47 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
control={control}
name="accessRequestChannels"
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
label="Slack channels"
isError={Boolean(error)}
errorText={error?.message}
>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Input
isReadOnly
value={value
?.filter(Boolean)
.map((entry) => slackChannelIdToName[entry])
.join(", ")}
className="text-left"
/>
</DropdownMenuTrigger>
<DropdownMenuContent
style={{
width: "var(--radix-dropdown-menu-trigger-width)",
maxHeight: "350px",
overflowY: "auto"
}}
side="bottom"
align="start"
>
{sortedSlackChannels?.map((slackChannel) => {
const isChecked = value?.includes(slackChannel.id);
return (
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
onChange(
isChecked
? value?.filter((el: string) => el !== slackChannel.id)
: [...(value || []), slackChannel.id]
);
}}
key={`access-requests-slack-channel-${slackChannel.id}`}
iconPos="right"
icon={isChecked && <FontAwesomeIcon icon={faCheckCircle} />}
>
{slackChannel.name}
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
<ChannelSelector
value={value}
onChange={onChange}
error={error}
slackChannelIdToName={slackChannelIdToName}
sortedSlackChannels={sortedSlackChannels}
keyPrefix="access-requests"
/>
)}
/>
)}
<Controller
control={control}
name="isSecretSyncErrorNotificationEnabled"
render={({ field, fieldState: { error } }) => {
return (
<FormControl isError={Boolean(error)} errorText={error?.message} className="mb-2">
<Switch
id="secret-sync-error-notification"
onCheckedChange={(value) => field.onChange(value)}
isChecked={field.value}
>
<p className="w-full">Secret Sync Errors</p>
</Switch>
</FormControl>
);
}}
/>
{secretSyncErrorNotifState && (
<Controller
control={control}
name="secretSyncErrorChannels"
render={({ field: { value, onChange }, fieldState: { error } }) => (
<ChannelSelector
value={value}
onChange={onChange}
error={error}
slackChannelIdToName={slackChannelIdToName}
sortedSlackChannels={sortedSlackChannels}
keyPrefix="secret-sync-errors"
/>
)}
/>
)}