smaller ui improvements

This commit is contained in:
Daniel Hougaard
2025-05-01 19:50:50 +04:00
parent 75cb259c51
commit 550cb2b5ec
4 changed files with 146 additions and 114 deletions

View File

@@ -93,8 +93,6 @@ export const WorkflowIntegrationTab = () => {
<THead>
<Tr>
<Td>Provider</Td>
<Td>Access Request Notifications</Td>
<Td>Secret Request Notifications</Td>
<Td>Access Request Notifications Destination</Td>
<Td>Secret Request Notifications Destination</Td>
<Td />

View File

@@ -1,5 +1,6 @@
/* eslint-disable no-nested-ternary */
import { BsMicrosoftTeams } from "react-icons/bs";
import { faCheck, faEllipsis, faXmark } from "@fortawesome/free-solid-svg-icons";
import { faEllipsis } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { twMerge } from "tailwind-merge";
@@ -34,10 +35,11 @@ type Props = {
export const MicrosoftTeamsConfigRow = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace } = useWorkspace();
const { data: microsoftTeamsConfig } = useGetWorkspaceWorkflowIntegrationConfig({
workspaceId: currentWorkspace?.id ?? "",
integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS
});
const { data: microsoftTeamsConfig, isPending: isMicrosoftTeamsConfigLoading } =
useGetWorkspaceWorkflowIntegrationConfig({
workspaceId: currentWorkspace?.id ?? "",
integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS
});
const { data: microsoftTeamsChannels, isPending: isMicrosoftTeamsChannelsLoading } =
useGetMicrosoftTeamsIntegrationTeams(microsoftTeamsConfig?.integrationId);
@@ -51,6 +53,8 @@ export const MicrosoftTeamsConfigRow = ({ handlePopUpOpen }: Props) => {
return null;
}
const isLoadingConfig = isMicrosoftTeamsChannelsLoading || isMicrosoftTeamsConfigLoading;
return (
<Tr>
<Td className="flex max-w-xs items-center overflow-hidden text-ellipsis">
@@ -60,39 +64,33 @@ export const MicrosoftTeamsConfigRow = ({ handlePopUpOpen }: Props) => {
</div>
</Td>
<Td>
{microsoftTeamsConfig.isAccessRequestNotificationEnabled ? (
<FontAwesomeIcon icon={faCheck} className="text-green-500" />
) : (
<FontAwesomeIcon icon={faXmark} className="text-red-500" />
)}
</Td>
<Td>
{microsoftTeamsConfig.isSecretRequestNotificationEnabled ? (
<FontAwesomeIcon icon={faCheck} className="text-green-500" />
) : (
<FontAwesomeIcon icon={faXmark} className="text-red-500" />
)}
</Td>
<Td>
{isMicrosoftTeamsChannelsLoading ? (
<Spinner size="xs" />
) : (
{microsoftTeamsConfig.isAccessRequestNotificationEnabled &&
!isLoadingConfig &&
microsoftTeamsConfig.accessRequestChannels?.channelIds?.length > 0 ? (
<Badge>
{(microsoftTeamsConfig.accessRequestChannels?.channelIds || [])
?.map((channel) => microsoftTeamsChannelIdToName[channel])
{microsoftTeamsConfig.accessRequestChannels.channelIds
.map((channel) => microsoftTeamsChannelIdToName[channel])
.join(", ")}
</Badge>
) : isLoadingConfig ? (
<Spinner size="xs" />
) : (
<Badge variant="danger">Disabled</Badge>
)}
</Td>
<Td>
{isMicrosoftTeamsChannelsLoading ? (
<Spinner size="xs" />
) : (
{microsoftTeamsConfig.isSecretRequestNotificationEnabled &&
!isLoadingConfig &&
microsoftTeamsConfig.secretRequestChannels?.channelIds?.length > 0 ? (
<Badge>
{(microsoftTeamsConfig.secretRequestChannels?.channelIds || [])
?.map((channel) => microsoftTeamsChannelIdToName[channel])
{microsoftTeamsConfig.secretRequestChannels.channelIds
.map((channel) => microsoftTeamsChannelIdToName[channel])
.join(", ")}
</Badge>
) : isLoadingConfig ? (
<Spinner size="xs" />
) : (
<Badge variant="danger">Disabled</Badge>
)}
</Td>
@@ -104,6 +102,25 @@ export const MicrosoftTeamsConfigRow = ({ handlePopUpOpen }: Props) => {
</div>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-1">
<OrgPermissionCan I={OrgPermissionActions.Edit} an={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<DropdownMenuItem
disabled={!isAllowed}
className={twMerge(
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
)}
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("editIntegration", {
integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS
});
}}
>
Edit
</DropdownMenuItem>
)}
</OrgPermissionCan>
<OrgPermissionCan I={OrgPermissionActions.Delete} an={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<DropdownMenuItem
@@ -124,25 +141,6 @@ export const MicrosoftTeamsConfigRow = ({ handlePopUpOpen }: Props) => {
</DropdownMenuItem>
)}
</OrgPermissionCan>
<OrgPermissionCan I={OrgPermissionActions.Edit} an={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<DropdownMenuItem
disabled={!isAllowed}
className={twMerge(
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
)}
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("editIntegration", {
integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS
});
}}
>
Edit
</DropdownMenuItem>
)}
</OrgPermissionCan>
</DropdownMenuContent>
</DropdownMenu>
</Td>

View File

@@ -17,7 +17,8 @@ import {
Input,
Select,
SelectItem,
Switch
Switch,
Tooltip
} from "@app/components/v2";
import { useWorkspace } from "@app/context";
import {
@@ -37,18 +38,22 @@ const formSchema = z
microsoftTeamsIntegrationId: z.string(),
isSecretRequestNotificationEnabled: z.boolean(),
isAccessRequestNotificationEnabled: z.boolean(),
secretRequestChannels: z.object({
teamId: z.string(),
channelIds: z.string().array()
}),
accessRequestChannels: z.object({
teamId: z.string(),
channelIds: z.string().array()
})
secretRequestChannels: z
.object({
teamId: z.string(),
channelIds: z.string().array()
})
.optional(),
accessRequestChannels: z
.object({
teamId: z.string(),
channelIds: z.string().array()
})
.optional()
})
.superRefine((data, ctx) => {
if (data.isSecretRequestNotificationEnabled) {
if (!data.secretRequestChannels.teamId) {
if (!data?.secretRequestChannels?.teamId) {
ctx.addIssue({
path: ["secretRequestChannels", "teamId"],
code: z.ZodIssueCode.custom,
@@ -56,7 +61,7 @@ const formSchema = z
});
}
if (!data.secretRequestChannels.channelIds.length) {
if (!data?.secretRequestChannels?.channelIds?.length) {
ctx.addIssue({
path: ["secretRequestChannels", "channelIds"],
code: z.ZodIssueCode.custom,
@@ -66,7 +71,7 @@ const formSchema = z
}
if (data.isAccessRequestNotificationEnabled) {
if (!data.accessRequestChannels.teamId) {
if (!data?.accessRequestChannels?.teamId) {
ctx.addIssue({
path: ["accessRequestChannels", "teamId"],
code: z.ZodIssueCode.custom,
@@ -74,7 +79,7 @@ const formSchema = z
});
}
if (!data.accessRequestChannels.channelIds.length) {
if (!data?.accessRequestChannels?.channelIds?.length) {
ctx.addIssue({
path: ["accessRequestChannels", "channelIds"],
code: z.ZodIssueCode.custom,
@@ -108,7 +113,8 @@ export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => {
watch,
handleSubmit,
setValue,
formState: { isDirty, isSubmitting }
getValues,
formState: { isDirty, isSubmitting, errors }
} = useForm<TMicrosoftTeamsConfigForm>({
resolver: zodResolver(formSchema),
defaultValues: {
@@ -210,13 +216,20 @@ export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => {
if (microsoftTeamsConfig.integration === WorkflowIntegrationPlatform.MICROSOFT_TEAMS) {
if (microsoftTeamsConfig.secretRequestChannels) {
setValue("secretRequestChannels", microsoftTeamsConfig.secretRequestChannels);
setValue("accessRequestChannels", microsoftTeamsConfig.accessRequestChannels);
if (Object.entries(microsoftTeamsConfig.accessRequestChannels).length) {
setValue("accessRequestChannels", microsoftTeamsConfig.accessRequestChannels);
}
if (Object.entries(microsoftTeamsConfig.secretRequestChannels).length) {
setValue("secretRequestChannels", microsoftTeamsConfig.secretRequestChannels);
}
}
}
}
}, [microsoftTeamsConfig]);
console.log("values", getValues());
console.log("errors", errors);
return (
<form onSubmit={handleSubmit(handleIntegrationSave)}>
<div className="flex w-full flex-col justify-start">
@@ -235,7 +248,20 @@ export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => {
{...field}
isDisabled={!isAllowed}
placeholder="None"
onValueChange={onChange}
onValueChange={(v) => {
onChange(v);
setValue("isAccessRequestNotificationEnabled", false);
setValue("isSecretRequestNotificationEnabled", false);
setValue("accessRequestChannels", {
teamId: "",
channelIds: []
});
setValue("secretRequestChannels", {
teamId: "",
channelIds: []
});
}}
className="w-full"
defaultValue={microsoftTeamsConfig?.integrationId}
>
@@ -522,6 +548,7 @@ export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => {
colorSchema="secondary"
className="mt-4"
type="submit"
disabled={!isDirty}
isDisabled={!isDirty}
isLoading={isSubmitting}
>

View File

@@ -1,5 +1,6 @@
/* eslint-disable no-nested-ternary */
import { BsSlack } from "react-icons/bs";
import { faCheck, faEllipsis, faXmark } from "@fortawesome/free-solid-svg-icons";
import { faEllipsis } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { twMerge } from "tailwind-merge";
@@ -10,6 +11,7 @@ import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
Spinner,
Td,
Tr
} from "@app/components/v2";
@@ -33,12 +35,15 @@ type Props = {
export const SlackConfigRow = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace } = useWorkspace();
const { data: slackConfig } = useGetWorkspaceWorkflowIntegrationConfig({
workspaceId: currentWorkspace?.id ?? "",
integration: WorkflowIntegrationPlatform.SLACK
});
const { data: slackConfig, isPending: isSlackConfigLoading } =
useGetWorkspaceWorkflowIntegrationConfig({
workspaceId: currentWorkspace?.id ?? "",
integration: WorkflowIntegrationPlatform.SLACK
});
const { data: slackChannels } = useGetSlackIntegrationChannels(slackConfig?.integrationId);
const { data: slackChannels, isPending: isSlackChannelsLoading } = useGetSlackIntegrationChannels(
slackConfig?.integrationId
);
const slackChannelIdToName = Object.fromEntries(
(slackChannels || []).map((channel) => [channel.id, channel.name])
);
@@ -47,6 +52,8 @@ export const SlackConfigRow = ({ handlePopUpOpen }: Props) => {
return null;
}
const isLoadingConfig = isSlackChannelsLoading || isSlackConfigLoading;
return (
<Tr>
<Td className="flex max-w-xs items-center overflow-hidden text-ellipsis">
@@ -56,35 +63,37 @@ export const SlackConfigRow = ({ handlePopUpOpen }: Props) => {
</div>
</Td>
<Td>
{slackConfig.isAccessRequestNotificationEnabled ? (
<FontAwesomeIcon icon={faCheck} className="text-green-500" />
{slackConfig.isAccessRequestNotificationEnabled &&
!isLoadingConfig &&
slackConfig.accessRequestChannels.length > 0 ? (
<Badge>
{slackConfig.accessRequestChannels
.split(", ")
.map((channel) => slackChannelIdToName[channel])
.join(", ")}
</Badge>
) : isLoadingConfig ? (
<Spinner size="xs" />
) : (
<FontAwesomeIcon icon={faXmark} className="text-red-500" />
<Badge variant="danger">Disabled</Badge>
)}
</Td>
<Td>
{slackConfig.isSecretRequestNotificationEnabled ? (
<FontAwesomeIcon icon={faCheck} className="text-green-500" />
{slackConfig.isSecretRequestNotificationEnabled &&
!isLoadingConfig &&
slackConfig.secretRequestChannels.length > 0 ? (
<Badge>
{slackConfig.secretRequestChannels
.split(", ")
.map((channel) => slackChannelIdToName[channel])
.join(", ")}
</Badge>
) : isLoadingConfig ? (
<Spinner size="xs" />
) : (
<FontAwesomeIcon icon={faXmark} className="text-red-500" />
<Badge variant="danger">Disabled</Badge>
)}
</Td>
<Td>
<Badge>
{slackConfig.accessRequestChannels
.split(", ")
.map((channel) => slackChannelIdToName[channel])
.join(", ")}
</Badge>
</Td>
<Td>
<Badge>
{slackConfig.secretRequestChannels
.split(", ")
.map((channel) => slackChannelIdToName[channel])
.join(", ")}
</Badge>
</Td>
<Td>
<DropdownMenu>
@@ -94,6 +103,25 @@ export const SlackConfigRow = ({ handlePopUpOpen }: Props) => {
</div>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-1">
<OrgPermissionCan I={OrgPermissionActions.Edit} an={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<DropdownMenuItem
disabled={!isAllowed}
className={twMerge(
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
)}
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("editIntegration", {
integration: WorkflowIntegrationPlatform.SLACK
});
}}
>
Edit
</DropdownMenuItem>
)}
</OrgPermissionCan>
<OrgPermissionCan I={OrgPermissionActions.Delete} an={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<DropdownMenuItem
@@ -114,25 +142,6 @@ export const SlackConfigRow = ({ handlePopUpOpen }: Props) => {
</DropdownMenuItem>
)}
</OrgPermissionCan>
<OrgPermissionCan I={OrgPermissionActions.Edit} an={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<DropdownMenuItem
disabled={!isAllowed}
className={twMerge(
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
)}
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("editIntegration", {
integration: WorkflowIntegrationPlatform.SLACK
});
}}
>
Edit
</DropdownMenuItem>
)}
</OrgPermissionCan>
</DropdownMenuContent>
</DropdownMenu>
</Td>