diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 5a314ddde151a..43051961fa7e7 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -804,7 +804,7 @@ class ApiMethods { ) => { const params = new URLSearchParams(); params.set("claimField", field); - const response = await this.axios.get( + const response = await this.axios.get( `/api/v2/organizations/${organization}/settings/idpsync/field-values?${params}`, ); return response.data; diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx index 78842737e5baf..430fce3a2ee05 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { userEvent, within } from "@storybook/test"; +import { expect, userEvent, within } from "@storybook/test"; import { MockOrganization, MockOrganization2, @@ -45,10 +45,16 @@ export const MissingGroups: Story = { }, }; -export const MissingClaim: Story = { +export const MissingClaims: Story = { args: { claimFieldValues: [], }, + play: async ({ canvasElement }) => { + const user = userEvent.setup(); + const warning = canvasElement.querySelector(".lucide-triangle-alert")!; + expect(warning).not.toBe(null); + await user.hover(warning); + }, }; export const AssignDefaultOrgWarningDialog: Story = { diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index f6822ba0a60ef..bdcc65b89aaba 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -1,4 +1,3 @@ -import { TooltipProvider } from "@radix-ui/react-tooltip"; import type { Organization, OrganizationSyncSettings, @@ -30,7 +29,6 @@ import { type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { Spinner } from "components/Spinner/Spinner"; -import { Stack } from "components/Stack/Stack"; import { Switch } from "components/Switch/Switch"; import { Table, @@ -42,6 +40,7 @@ import { import { Tooltip, TooltipContent, + TooltipProvider, TooltipTrigger, } from "components/Tooltip/Tooltip"; import { useFormik } from "formik"; diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 2f1c0be7fa602..9d63baf180fbc 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -22,8 +22,14 @@ import { } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { Spinner } from "components/Spinner/Spinner"; import { Switch } from "components/Switch/Switch"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { useFormik } from "formik"; -import { Plus, Trash } from "lucide-react"; +import { Plus, Trash, TriangleAlert } from "lucide-react"; import { type FC, useId, useState } from "react"; import { docs } from "utils/docs"; import { isUUID } from "utils/uuid"; @@ -32,16 +38,6 @@ import { ExportPolicyButton } from "./ExportPolicyButton"; import { IdpMappingTable } from "./IdpMappingTable"; import { IdpPillList } from "./IdpPillList"; -interface IdpGroupSyncFormProps { - groupSyncSettings: GroupSyncSettings; - groupsMap: Map; - groups: Group[]; - groupMappingCount: number; - legacyGroupMappingCount: number; - organization: Organization; - onSubmit: (data: GroupSyncSettings) => void; -} - const groupSyncValidationSchema = Yup.object({ field: Yup.string().trim(), regex_filter: Yup.string().trim(), @@ -65,15 +61,27 @@ const groupSyncValidationSchema = Yup.object({ .default({}), }); -export const IdpGroupSyncForm = ({ +interface IdpGroupSyncFormProps { + groupSyncSettings: GroupSyncSettings; + claimFieldValues: readonly string[] | undefined; + groupsMap: Map; + groups: Group[]; + groupMappingCount: number; + legacyGroupMappingCount: number; + organization: Organization; + onSubmit: (data: GroupSyncSettings) => void; +} + +export const IdpGroupSyncForm: FC = ({ groupSyncSettings, + claimFieldValues, groupMappingCount, legacyGroupMappingCount, groups, groupsMap, organization, onSubmit, -}: IdpGroupSyncFormProps) => { +}) => { const form = useFormik({ initialValues: { field: groupSyncSettings?.field ?? "", @@ -270,6 +278,7 @@ export const IdpGroupSyncForm = ({ @@ -288,6 +297,7 @@ export const IdpGroupSyncForm = ({ @@ -303,17 +313,48 @@ export const IdpGroupSyncForm = ({ interface GroupRowProps { idpGroup: string; + exists: boolean | undefined; coderGroup: readonly string[]; onDelete: (idpOrg: string) => void; } -const GroupRow: FC = ({ idpGroup, coderGroup, onDelete }) => { +const GroupRow: FC = ({ + idpGroup, + exists = true, + coderGroup, + onDelete, +}) => { return ( - {idpGroup} + +
+ {idpGroup} + {!exists && ( + + + + + + + This value has not be seen in the specified claim field + before. You might want to check your IdP configuration and + ensure that this value is not misspelled. + + + + )} +
+
+ +