From 5c09338f7e8166fc07db3686d7ecef9fe2ab13ae Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Wed, 5 Feb 2025 00:24:50 +0000 Subject: [PATCH 01/22] hoot --- .../IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx | 7 +++++++ .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 14 ++++++++++++-- site/tailwind.config.js | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx index 8d02e1f248833..ff65a634ec61b 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx @@ -50,6 +50,13 @@ export const MissingGroups: Story = { }, }; +export const MissingClaim: Story = { + args: { + ...Default.args, + organizationSyncSettings: MockOrganizationSyncSettings, + }, +}; + export const AssignDefaultOrgWarningDialog: Story = { args: { organizationSyncSettings: MockOrganizationSyncSettings, diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 7ed1b85e8c9dd..9b7528dfc1250 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -36,12 +36,13 @@ import { import { Spinner } from "components/Spinner/Spinner"; import { Switch } from "components/Switch/Switch"; 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"; import * as Yup from "yup"; import { OrganizationPills } from "./OrganizationPills"; +import { Stack } from "components/Stack/Stack"; interface IdpSyncPageViewProps { organizationSyncSettings: OrganizationSyncSettings | undefined; @@ -354,18 +355,27 @@ const IdpMappingTable: FC = ({ isEmpty, children }) => { interface OrganizationRowProps { idpOrg: string; + doesIdpOrgEvenExistLol: boolean; coderOrgs: readonly string[]; onDelete: (idpOrg: string) => void; } const OrganizationRow: FC = ({ idpOrg, + doesIdpOrgEvenExistLol, coderOrgs, onDelete, }) => { return ( - {idpOrg} + + + {idpOrg}{" "} + {!doesIdpOrgEvenExistLol && ( + + )} + + diff --git a/site/tailwind.config.js b/site/tailwind.config.js index 7c07eed4bd3a2..0eb7e5176f8d8 100644 --- a/site/tailwind.config.js +++ b/site/tailwind.config.js @@ -33,6 +33,7 @@ module.exports = { success: "hsl(var(--content-success))", danger: "hsl(var(--content-danger))", link: "hsl(var(--content-link))", + warning: "hsl(var(--content-warning))", }, surface: { primary: "hsl(var(--surface-primary))", From c52982e3bf2d7fc48a41160ac5fd811a61c068d2 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 18:36:41 +0000 Subject: [PATCH 02/22] feat: show warning on unrecognized idp org mapping claims --- site/src/api/api.ts | 11 +++++++ site/src/api/queries/deployment.ts | 7 +++++ .../IdpOrgSyncPage/IdpOrgSyncPage.tsx | 25 ++++++++++------ .../IdpOrgSyncPageView.stories.tsx | 30 ++++++++----------- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 9 ++++-- site/src/testHelpers/entities.ts | 7 +++++ 6 files changed, 59 insertions(+), 30 deletions(-) diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 26491efb10565..7b29313e08118 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -787,6 +787,17 @@ class ApiMethods { return response.data; }; + getDeploymentIdpSyncFieldValues = async ( + field: string, + ): Promise => { + const params = new URLSearchParams(); + params.set("claimField", field); + const response = await this.axios.get( + `/api/v2/settings/idpsync/field-values?${params.toString}`, + ); + return response.data; + }; + getTemplate = async (templateId: string): Promise => { const response = await this.axios.get( `/api/v2/templates/${templateId}`, diff --git a/site/src/api/queries/deployment.ts b/site/src/api/queries/deployment.ts index 62449af12fccf..69668c6fd04e3 100644 --- a/site/src/api/queries/deployment.ts +++ b/site/src/api/queries/deployment.ts @@ -29,3 +29,10 @@ export const deploymentSSHConfig = () => { queryFn: API.getDeploymentSSHConfig, }; }; + +export const deploymentIdpSyncFieldValues = (field: string) => { + return { + queryKey: ["deployment", "idpSync", "fieldValues"], + queryFn: () => API.getDeploymentIdpSyncFieldValues(field), + }; +}; diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx index d08b3aac4ab1a..fcce79e031de1 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx @@ -18,17 +18,20 @@ import { docs } from "utils/docs"; import { pageTitle } from "utils/page"; import { ExportPolicyButton } from "./ExportPolicyButton"; import IdpOrgSyncPageView from "./IdpOrgSyncPageView"; +import { deploymentIdpSyncFieldValues } from "api/queries/deployment"; export const IdpOrgSyncPage: FC = () => { const queryClient = useQueryClient(); // IdP sync does not have its own entitlement and is based on templace_rbac const { template_rbac: isIdpSyncEnabled } = useFeatureVisibility(); const { organizations } = useDashboard(); - const { - data: orgSyncSettingsData, - isLoading, - error, - } = useQuery(organizationIdpSyncSettings(isIdpSyncEnabled)); + const settingsQuery = useQuery(organizationIdpSyncSettings(isIdpSyncEnabled)); + + const fieldValuesQuery = useQuery( + settingsQuery.data + ? deploymentIdpSyncFieldValues(settingsQuery.data.field) + : { enabled: false }, + ); const patchOrganizationSyncSettingsMutation = useMutation( patchOrganizationSyncSettings(queryClient), @@ -45,7 +48,7 @@ export const IdpOrgSyncPage: FC = () => { } }, [patchOrganizationSyncSettingsMutation.error]); - if (isLoading) { + if (settingsQuery.isLoading || fieldValuesQuery.isLoading) { return ; } @@ -67,7 +70,7 @@ export const IdpOrgSyncPage: FC = () => {

- + @@ -79,7 +82,8 @@ export const IdpOrgSyncPage: FC = () => { { try { @@ -94,7 +98,10 @@ export const IdpOrgSyncPage: FC = () => { ); } }} - error={error || patchOrganizationSyncSettingsMutation.error} + error={ + settingsQuery.error || + patchOrganizationSyncSettingsMutation.error + } /> diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx index ff65a634ec61b..576c887a1a3bc 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx @@ -5,12 +5,19 @@ import { MockOrganization2, MockOrganizationSyncSettings, MockOrganizationSyncSettings2, + MockOrganizationSyncSettingsEmpty, } from "testHelpers/entities"; import { IdpOrgSyncPageView } from "./IdpOrgSyncPageView"; const meta: Meta = { title: "pages/IdpOrgSyncPageView", component: IdpOrgSyncPageView, + args: { + organizationSyncSettings: MockOrganizationSyncSettings2, + fieldValues: Object.keys(MockOrganizationSyncSettings2.mapping), + organizations: [MockOrganization, MockOrganization2], + error: undefined, + }, }; export default meta; @@ -18,42 +25,29 @@ type Story = StoryObj; export const Empty: Story = { args: { - organizationSyncSettings: { - field: "", - mapping: {}, - organization_assign_default: true, - }, - organizations: [MockOrganization, MockOrganization2], - error: undefined, + organizationSyncSettings: MockOrganizationSyncSettingsEmpty, }, }; -export const Default: Story = { - args: { - organizationSyncSettings: MockOrganizationSyncSettings2, - organizations: [MockOrganization, MockOrganization2], - error: undefined, - }, -}; +export const Default: Story = {}; export const HasError: Story = { args: { - ...Default.args, error: "This is a test error", }, }; export const MissingGroups: Story = { args: { - ...Default.args, organizationSyncSettings: MockOrganizationSyncSettings, + fieldValues: Object.keys(MockOrganizationSyncSettings.mapping), + organizations: [], }, }; export const MissingClaim: Story = { args: { - ...Default.args, - organizationSyncSettings: MockOrganizationSyncSettings, + fieldValues: [], }, }; diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 9b7528dfc1250..ee5a2399faaff 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -46,6 +46,7 @@ import { Stack } from "components/Stack/Stack"; interface IdpSyncPageViewProps { organizationSyncSettings: OrganizationSyncSettings | undefined; + fieldValues: readonly string[] | undefined; organizations: readonly Organization[]; onSubmit: (data: OrganizationSyncSettings) => void; error?: unknown; @@ -75,6 +76,7 @@ const validationSchema = Yup.object({ export const IdpOrgSyncPageView: FC = ({ organizationSyncSettings, + fieldValues, organizations, onSubmit, error, @@ -268,6 +270,7 @@ export const IdpOrgSyncPageView: FC = ({ idpOrg={idpOrg} coderOrgs={getOrgNames(organizations)} onDelete={handleDelete} + exists={fieldValues?.includes(idpOrg)} /> ))} @@ -355,14 +358,14 @@ const IdpMappingTable: FC = ({ isEmpty, children }) => { interface OrganizationRowProps { idpOrg: string; - doesIdpOrgEvenExistLol: boolean; + exists: boolean | undefined; coderOrgs: readonly string[]; onDelete: (idpOrg: string) => void; } const OrganizationRow: FC = ({ idpOrg, - doesIdpOrgEvenExistLol, + exists = true, coderOrgs, onDelete, }) => { @@ -371,7 +374,7 @@ const OrganizationRow: FC = ({ {idpOrg}{" "} - {!doesIdpOrgEvenExistLol && ( + {!exists && ( )} diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index c522457a63c1d..d8ce878bdef6e 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -2720,6 +2720,13 @@ export const MockOrganizationSyncSettings2: TypesGen.OrganizationSyncSettings = organization_assign_default: true, }; +export const MockOrganizationSyncSettingsEmpty: TypesGen.OrganizationSyncSettings = + { + field: "", + mapping: {}, + organization_assign_default: true, + }; + export const MockGroup: TypesGen.Group = { id: "fbd2116a-8961-4954-87ae-e4575bd29ce0", name: "Front-End", From 63ca7630cbc5c949485c2b68d2bf89851d990d65 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 19:14:51 +0000 Subject: [PATCH 03/22] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/src/api/api.ts | 15 +++++---------- site/src/api/queries/organizations.ts | 13 +++++-------- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 2 +- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 310e4e6b3798f..cbde6cd022924 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -798,19 +798,14 @@ class ApiMethods { return response.data; }; - getIdpSyncClaimFieldValues = async (claimField: string) => { - const response = await this.axios.get( - `/api/v2/settings/idpsync/field-values?claimField=${claimField}`, - ); - return response.data; - }; - - getIdpSyncClaimFieldValuesByOrganization = async ( + getOrganizationIdpSyncClaimFieldValues = async ( organization: string, - claimField: string, + field: string, ) => { + const params = new URLSearchParams(); + params.set("claimField", field); const response = await this.axios.get( - `/api/v2/organizations/${organization}/settings/idpsync/field-values?claimField=${claimField}`, + `/api/v2/organizations/${organization}/settings/idpsync/field-values?${params.toString()}`, ); return response.data; }; diff --git a/site/src/api/queries/organizations.ts b/site/src/api/queries/organizations.ts index 4dad5d2af51e6..6246664e6ecf0 100644 --- a/site/src/api/queries/organizations.ts +++ b/site/src/api/queries/organizations.ts @@ -341,19 +341,16 @@ export const organizationsPermissions = ( export const getOrganizationIdpSyncClaimFieldValuesKey = ( organization: string, - claimField: string, -) => [organization, claimField, "organizationIdpSyncClaimFieldValues"]; + field: string, +) => [organization, "idpSync", "fieldValues", field]; export const organizationIdpSyncClaimFieldValues = ( organization: string, - claimField: string, + field: string, ) => { return { - queryKey: getOrganizationIdpSyncClaimFieldValuesKey( - organization, - claimField, - ), + queryKey: getOrganizationIdpSyncClaimFieldValuesKey(organization, field), queryFn: () => - API.getIdpSyncClaimFieldValuesByOrganization(organization, claimField), + API.getOrganizationIdpSyncClaimFieldValues(organization, field), }; }; diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 144beb7501bf6..a08395985b938 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -414,7 +414,7 @@ const OrganizationRow: FC = ({ - {idpOrg}{" "} + {idpOrg} {!exists && ( )} From e55e0a8446e8323b993306678f4b09177be61c60 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 19:23:44 +0000 Subject: [PATCH 04/22] add warning description --- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index a08395985b938..061a4ad4b1ba6 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -416,7 +416,16 @@ const OrganizationRow: FC = ({ {idpOrg} {!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. + + )} From 72a7986188cd139a9bc1c916c30f5c2fa92c27ab Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 20:07:31 +0000 Subject: [PATCH 05/22] toolptipp --- .../components/Tooltip/Tooltip.stories.tsx | 16 ++++------ .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 31 ++++++++++--------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/site/src/components/Tooltip/Tooltip.stories.tsx b/site/src/components/Tooltip/Tooltip.stories.tsx index 68561b6a189e3..9af79ca76c099 100644 --- a/site/src/components/Tooltip/Tooltip.stories.tsx +++ b/site/src/components/Tooltip/Tooltip.stories.tsx @@ -12,16 +12,12 @@ const meta: Meta = { component: TooltipProvider, args: { children: ( - <> - - - - - - Add to library - - - + + + + + Add to library + ), }, }; diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 061a4ad4b1ba6..ebd9742f94688 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -29,10 +29,10 @@ import { type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { - Popover, - PopoverContent, - PopoverTrigger, -} from "components/Popover/Popover"; + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { Spinner } from "components/Spinner/Spinner"; import { Switch } from "components/Switch/Switch"; import { @@ -50,6 +50,7 @@ import { isUUID } from "utils/uuid"; import * as Yup from "yup"; import { OrganizationPills } from "./OrganizationPills"; import { Stack } from "components/Stack/Stack"; +import { TooltipProvider } from "@radix-ui/react-tooltip"; interface IdpSyncPageViewProps { organizationSyncSettings: OrganizationSyncSettings | undefined; @@ -416,16 +417,18 @@ const OrganizationRow: FC = ({ {idpOrg} {!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. - - + + + + + + + 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. + + + )} From eedf797b1c32729e0993fca8126e20a7dcd9c741 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 20:10:26 +0000 Subject: [PATCH 06/22] tweak text colors --- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index ebd9742f94688..979b1830d7d38 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -414,7 +414,12 @@ const OrganizationRow: FC = ({ return ( - + {idpOrg} {!exists && ( From 06ba32deefe1e4ff24ef16df32b3394e67b0206d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=B1=E3=82=A4=E3=83=A9?= Date: Thu, 6 Feb 2025 15:17:32 -0700 Subject: [PATCH 07/22] Update site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx Co-authored-by: Jaayden Halko --- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 979b1830d7d38..fb64dbde04955 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -425,7 +425,7 @@ const OrganizationRow: FC = ({ - + This value has not be seen in the specified claim field From 96006242cfca1f22a89f880edef8a468b447731f Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 22:19:56 +0000 Subject: [PATCH 08/22] this is something --- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 2 +- .../IdpSyncPage/IdpGroupSyncForm.tsx | 4 +- .../IdpSyncPage/IdpRoleSyncForm.tsx | 65 +++++++++++++++---- .../IdpSyncPage/IdpSyncPage.tsx | 20 +++++- .../IdpSyncPage/IdpSyncPageView.tsx | 8 ++- 5 files changed, 78 insertions(+), 21 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 979b1830d7d38..d28bd78a279d2 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -32,6 +32,7 @@ import { Tooltip, TooltipContent, TooltipTrigger, + TooltipProvider, } from "components/Tooltip/Tooltip"; import { Spinner } from "components/Spinner/Spinner"; import { Switch } from "components/Switch/Switch"; @@ -50,7 +51,6 @@ import { isUUID } from "utils/uuid"; import * as Yup from "yup"; import { OrganizationPills } from "./OrganizationPills"; import { Stack } from "components/Stack/Stack"; -import { TooltipProvider } from "@radix-ui/react-tooltip"; interface IdpSyncPageViewProps { organizationSyncSettings: OrganizationSyncSettings | undefined; diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 2f1c0be7fa602..2776b3531bc52 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -65,7 +65,7 @@ const groupSyncValidationSchema = Yup.object({ .default({}), }); -export const IdpGroupSyncForm = ({ +export const IdpGroupSyncForm: FC = ({ groupSyncSettings, groupMappingCount, legacyGroupMappingCount, @@ -73,7 +73,7 @@ export const IdpGroupSyncForm = ({ groupsMap, organization, onSubmit, -}: IdpGroupSyncFormProps) => { +}) => { const form = useFormik({ initialValues: { field: groupSyncSettings?.field ?? "", diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx index ffe68e33e2ecc..b6780b1ce589f 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx @@ -10,20 +10,19 @@ import { } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { Spinner } from "components/Spinner/Spinner"; 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 * as Yup from "yup"; import { ExportPolicyButton } from "./ExportPolicyButton"; import { IdpMappingTable } from "./IdpMappingTable"; import { IdpPillList } from "./IdpPillList"; - -interface IdpRoleSyncFormProps { - roleSyncSettings: RoleSyncSettings; - roleMappingCount: number; - organization: Organization; - roles: Role[]; - onSubmit: (data: RoleSyncSettings) => void; -} +import { Stack } from "components/Stack/Stack"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, + TooltipProvider, +} from "components/Tooltip/Tooltip"; const roleSyncValidationSchema = Yup.object({ field: Yup.string().trim(), @@ -48,13 +47,23 @@ const roleSyncValidationSchema = Yup.object({ .default({}), }); -export const IdpRoleSyncForm = ({ +interface IdpRoleSyncFormProps { + roleSyncSettings: RoleSyncSettings; + fieldValues: string[] | undefined; + roleMappingCount: number; + organization: Organization; + roles: Role[]; + onSubmit: (data: RoleSyncSettings) => void; +} + +export const IdpRoleSyncForm: FC = ({ roleSyncSettings, + fieldValues, roleMappingCount, organization, roles, onSubmit, -}: IdpRoleSyncFormProps) => { +}) => { const form = useFormik({ initialValues: { field: roleSyncSettings?.field ?? "", @@ -210,6 +219,7 @@ export const IdpRoleSyncForm = ({ @@ -222,14 +232,43 @@ export const IdpRoleSyncForm = ({ interface RoleRowProps { idpRole: string; + exists: boolean | undefined; coderRoles: readonly string[]; onDelete: (idpOrg: string) => void; } -const RoleRow: FC = ({ idpRole, coderRoles, onDelete }) => { +const RoleRow: FC = ({ + idpRole, + exists = true, + coderRoles, + onDelete, +}) => { return ( - {idpRole} + + + {idpRole} + {!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. + + + + )} + + diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx index 1164558ef6586..9c6b76674af2c 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx @@ -2,6 +2,7 @@ import { getErrorMessage } from "api/errors"; import { groupsByOrganization } from "api/queries/groups"; import { groupIdpSyncSettings, + organizationIdpSyncClaimFieldValues, patchGroupSyncSettings, patchRoleSyncSettings, roleIdpSyncSettings, @@ -17,8 +18,8 @@ import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout"; import type { FC } from "react"; import { Helmet } from "react-helmet-async"; -import { useMutation, useQueries, useQueryClient } from "react-query"; -import { useParams } from "react-router-dom"; +import { useMutation, useQueries, useQuery, useQueryClient } from "react-query"; +import { useParams, useSearchParams } from "react-router-dom"; import { docs } from "utils/docs"; import { pageTitle } from "utils/page"; import IdpSyncPageView from "./IdpSyncPageView"; @@ -47,6 +48,19 @@ export const IdpSyncPage: FC = () => { ], }); + const [searchParams] = useSearchParams(); + const tab = searchParams.get("tab") || "groups"; + const field = + tab === "groups" + ? groupIdpSyncSettingsQuery.data?.field + : roleIdpSyncSettingsQuery.data?.field; + + const fieldValuesQuery = useQuery( + field + ? organizationIdpSyncClaimFieldValues(organizationName, field) + : { enabled: false }, + ); + if (!organization) { return ; } @@ -99,8 +113,10 @@ export const IdpSyncPage: FC = () => { ; roles: Role[] | undefined; @@ -26,8 +27,10 @@ interface IdpSyncPageViewProps { } export const IdpSyncPageView: FC = ({ + tab groupSyncSettings, roleSyncSettings, + fieldValues, groups, groupsMap, roles, @@ -36,8 +39,6 @@ export const IdpSyncPageView: FC = ({ onSubmitGroupSyncSettings, onSubmitRoleSyncSettings, }) => { - const [searchParams] = useSearchParams(); - const tab = searchParams.get("tab") || "groups"; const groupMappingCount = groupSyncSettings?.mapping ? Object.entries(groupSyncSettings.mapping).length : 0; @@ -78,6 +79,7 @@ export const IdpSyncPageView: FC = ({ ) : ( Date: Thu, 6 Feb 2025 22:23:48 +0000 Subject: [PATCH 09/22] - `toString()` --- site/src/api/api.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/api/api.ts b/site/src/api/api.ts index cbde6cd022924..5a314ddde151a 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -698,7 +698,7 @@ class ApiMethods { } const response = await this.axios.get( - `/api/v2/organizations/${organization}/provisionerdaemons?${params.toString()}`, + `/api/v2/organizations/${organization}/provisionerdaemons?${params}`, ); return response.data; }; @@ -793,7 +793,7 @@ class ApiMethods { const params = new URLSearchParams(); params.set("claimField", field); const response = await this.axios.get( - `/api/v2/settings/idpsync/field-values?${params.toString}`, + `/api/v2/settings/idpsync/field-values?${params}`, ); return response.data; }; @@ -805,7 +805,7 @@ class ApiMethods { const params = new URLSearchParams(); params.set("claimField", field); const response = await this.axios.get( - `/api/v2/organizations/${organization}/settings/idpsync/field-values?${params.toString()}`, + `/api/v2/organizations/${organization}/settings/idpsync/field-values?${params}`, ); return response.data; }; From 506cca107cdde33dc90da80de45f854c19670641 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 22:35:56 +0000 Subject: [PATCH 10/22] polish --- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index fb64dbde04955..e0ce569b36592 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -414,12 +414,7 @@ const OrganizationRow: FC = ({ return ( - +
{idpOrg} {!exists && ( @@ -427,7 +422,12 @@ const OrganizationRow: FC = ({ - + 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. @@ -435,7 +435,7 @@ const OrganizationRow: FC = ({ )} - +
From c91cd1adc91f9d23b974f648c7f21ddd70fd418a Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 22:38:07 +0000 Subject: [PATCH 11/22] =?UTF-8?q?=F0=9F=A7=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IdpOrgSyncPage/IdpOrgSyncPage.tsx | 2 +- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx index faf5e8dd3450e..5149e4f6d9792 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx @@ -1,4 +1,5 @@ import { getErrorMessage } from "api/errors"; +import { deploymentIdpSyncFieldValues } from "api/queries/deployment"; import { organizationIdpSyncSettings, patchOrganizationSyncSettings, @@ -18,7 +19,6 @@ import { docs } from "utils/docs"; import { pageTitle } from "utils/page"; import { ExportPolicyButton } from "./ExportPolicyButton"; import IdpOrgSyncPageView from "./IdpOrgSyncPageView"; -import { deploymentIdpSyncFieldValues } from "api/queries/deployment"; export const IdpOrgSyncPage: FC = () => { const queryClient = useQueryClient(); diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index e0ce569b36592..394909656dec8 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -1,3 +1,4 @@ +import { TooltipProvider } from "@radix-ui/react-tooltip"; import type { Organization, OrganizationSyncSettings, @@ -28,12 +29,8 @@ import { MultiSelectCombobox, type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "components/Tooltip/Tooltip"; import { Spinner } from "components/Spinner/Spinner"; +import { Stack } from "components/Stack/Stack"; import { Switch } from "components/Switch/Switch"; import { Table, @@ -42,6 +39,11 @@ import { TableHeader, TableRow, } from "components/Table/Table"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; import { useFormik } from "formik"; import { Plus, Trash, TriangleAlert } from "lucide-react"; import { type FC, type KeyboardEventHandler, useId, useState } from "react"; @@ -49,8 +51,6 @@ import { docs } from "utils/docs"; import { isUUID } from "utils/uuid"; import * as Yup from "yup"; import { OrganizationPills } from "./OrganizationPills"; -import { Stack } from "components/Stack/Stack"; -import { TooltipProvider } from "@radix-ui/react-tooltip"; interface IdpSyncPageViewProps { organizationSyncSettings: OrganizationSyncSettings | undefined; From 97de7f4b72fb31b96de2ad0352eabaf5515d1d40 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 22:40:01 +0000 Subject: [PATCH 12/22] rename --- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 394909656dec8..f6822ba0a60ef 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -54,7 +54,7 @@ import { OrganizationPills } from "./OrganizationPills"; interface IdpSyncPageViewProps { organizationSyncSettings: OrganizationSyncSettings | undefined; - fieldValues: readonly string[] | undefined; + claimFieldValues: readonly string[] | undefined; organizations: readonly Organization[]; onSubmit: (data: OrganizationSyncSettings) => void; onSyncFieldChange: (value: string) => void; @@ -85,7 +85,7 @@ const validationSchema = Yup.object({ export const IdpOrgSyncPageView: FC = ({ organizationSyncSettings, - fieldValues, + claimFieldValues, organizations, onSubmit, onSyncFieldChange, @@ -137,7 +137,7 @@ export const IdpOrgSyncPageView: FC = ({ if ( event.key === "Enter" && inputValue && - !fieldValues?.some((value) => value === inputValue.toLowerCase()) + !claimFieldValues?.some((value) => value === inputValue.toLowerCase()) ) { event.preventDefault(); setIdpOrgName(inputValue); @@ -220,10 +220,10 @@ export const IdpOrgSyncPageView: FC = ({ IdP organization name - {fieldValues ? ( + {claimFieldValues ? ( = ({ idpOrg={idpOrg} coderOrgs={getOrgNames(organizations)} onDelete={handleDelete} - exists={fieldValues?.includes(idpOrg)} + exists={claimFieldValues?.includes(idpOrg)} /> ))} From 06715fab96991811ae2f4d5128cadbe21bf479bb Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 22:46:16 +0000 Subject: [PATCH 13/22] sad moment --- .../DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx index 5149e4f6d9792..4d8ae28e81eee 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx @@ -90,7 +90,7 @@ export const IdpOrgSyncPage: FC = () => { setField(field)} onSubmit={async (data) => { From 42ceb1b50dc672325c4d3ea701577a99777dfeb0 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 22:47:15 +0000 Subject: [PATCH 14/22] cntnd. --- .../IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx index 576c887a1a3bc..78842737e5baf 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx @@ -14,7 +14,7 @@ const meta: Meta = { component: IdpOrgSyncPageView, args: { organizationSyncSettings: MockOrganizationSyncSettings2, - fieldValues: Object.keys(MockOrganizationSyncSettings2.mapping), + claimFieldValues: Object.keys(MockOrganizationSyncSettings2.mapping), organizations: [MockOrganization, MockOrganization2], error: undefined, }, @@ -40,14 +40,14 @@ export const HasError: Story = { export const MissingGroups: Story = { args: { organizationSyncSettings: MockOrganizationSyncSettings, - fieldValues: Object.keys(MockOrganizationSyncSettings.mapping), + claimFieldValues: Object.keys(MockOrganizationSyncSettings.mapping), organizations: [], }, }; export const MissingClaim: Story = { args: { - fieldValues: [], + claimFieldValues: [], }, }; From 820cca33ef7535a3e11aba47b717ebec0406fc87 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 23:32:59 +0000 Subject: [PATCH 15/22] huh --- .../DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx index 4d8ae28e81eee..295b482f94286 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx @@ -55,7 +55,7 @@ export const IdpOrgSyncPage: FC = () => { } }, [patchOrganizationSyncSettingsMutation.error]); - if (settingsQuery.isLoading || fieldValuesQuery.isLoading) { + if (settingsQuery.isLoading) { return ; } @@ -92,7 +92,7 @@ export const IdpOrgSyncPage: FC = () => { organizationSyncSettings={settingsQuery.data} claimFieldValues={fieldValuesQuery.data} organizations={organizations} - onSyncFieldChange={(field) => setField(field)} + onSyncFieldChange={setField} onSubmit={async (data) => { try { await patchOrganizationSyncSettingsMutation.mutateAsync(data); @@ -106,6 +106,7 @@ export const IdpOrgSyncPage: FC = () => { ); } }} + error={settingsQuery.error || fieldValuesQuery.error} /> From b955e4baf4f67893234f7e78f027f9f4b4d00076 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 6 Feb 2025 23:49:05 +0000 Subject: [PATCH 16/22] yet again --- .../DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index f3c58e488de9c..bdcc65b89aaba 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -29,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, From d3873abf1fb310d767c3bce0563a817202b400a3 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 7 Feb 2025 01:01:07 +0000 Subject: [PATCH 17/22] group tooltip thing too --- .../IdpOrgSyncPageView.stories.tsx | 2 +- .../IdpSyncPage/IdpGroupSyncForm.tsx | 62 +++++++++++++++---- .../IdpSyncPage/IdpRoleSyncForm.tsx | 14 ++--- .../IdpSyncPage/IdpSyncPageView.stories.tsx | 61 ++++++++++-------- .../IdpSyncPage/IdpSyncPageView.tsx | 3 +- site/src/testHelpers/entities.ts | 4 +- 6 files changed, 94 insertions(+), 52 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx index 78842737e5baf..8365c591af3d2 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx @@ -45,7 +45,7 @@ export const MissingGroups: Story = { }, }; -export const MissingClaim: Story = { +export const MissingClaims: Story = { args: { claimFieldValues: [], }, diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 2776b3531bc52..83bcec61bd4c0 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -23,7 +23,7 @@ import { import { Spinner } from "components/Spinner/Spinner"; import { Switch } from "components/Switch/Switch"; 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"; @@ -31,16 +31,12 @@ import * as Yup from "yup"; 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; -} +import { + Tooltip, + TooltipContent, + TooltipTrigger, + TooltipProvider, +} from "components/Tooltip/Tooltip"; const groupSyncValidationSchema = Yup.object({ field: Yup.string().trim(), @@ -65,8 +61,20 @@ const groupSyncValidationSchema = Yup.object({ .default({}), }); +interface IdpGroupSyncFormProps { + groupSyncSettings: GroupSyncSettings; + fieldValues: string[] | undefined; + groupsMap: Map; + groups: Group[]; + groupMappingCount: number; + legacyGroupMappingCount: number; + organization: Organization; + onSubmit: (data: GroupSyncSettings) => void; +} + export const IdpGroupSyncForm: FC = ({ groupSyncSettings, + fieldValues, groupMappingCount, legacyGroupMappingCount, groups, @@ -270,6 +278,7 @@ export const IdpGroupSyncForm: FC = ({ @@ -288,6 +297,7 @@ export const IdpGroupSyncForm: FC = ({ @@ -303,17 +313,43 @@ export const IdpGroupSyncForm: FC = ({ 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. + + + + )} +
+
+ +