-
- Group sync field
-
-
- Regex filter
-
-
{
- void form.setFieldValue("field", event.target.value);
- onSyncFieldChange(event.target.value);
- }}
- className="w-72"
- />
-
-
-
- {
- void form.setFieldValue("auto_create_missing_groups", checked);
- form.handleSubmit();
- }}
- />
-
-
-
- Auto create missing groups
-
-
-
-
-
-
-
- IdP group name
-
- {claimFieldValues ? (
- setIdpGroupName(value ?? "")}
- >
-
-
-
-
-
-
- {claimFieldValues
- .filter((value) =>
- value
- .toLowerCase()
- .includes(comboInputValue.toLowerCase()),
- )
- .map((value) => (
- setComboInputValue("")}
- >
- {value}
-
- ))}
-
-
-
- ) : (
- {
- setIdpGroupName(event.target.value);
- }}
- />
)}
+
+ {groupSyncSettings?.mapping &&
+ Object.entries(groupSyncSettings.mapping)
+ .sort(([a], [b]) =>
+ a.toLowerCase().localeCompare(b.toLowerCase()),
+ )
+ .map(([idpGroup, groups]) => (
+ setMappingToDelete(idpGroup)}
+ />
+ ))}
+
-
-
- Coder group
-
-
!isEveryoneGroup(group))
- .map((group) => ({
- label: group.display_name || group.name,
- value: group.id,
- }))}
- hidePlaceholderWhenSelected
- placeholder="Select group"
- emptyIndicator={
-
- No more groups to select
-
- }
- />
-
-
-
-
{
- const newSyncSettings = {
- ...form.values,
- mapping: {
- ...form.values.mapping,
- [idpGroupName]: coderGroups.map((group) => group.value),
- },
- };
- void form.setFieldValue("mapping", newSyncSettings.mapping);
- form.handleSubmit();
- setIdpGroupName("");
- setCoderGroups([]);
- }}
- >
-
-
-
- Add IdP group
-
-
-
- {form.errors.mapping && (
-
- {Object.values(form.errors.mapping || {})}
-
- )}
-
-
- {groupSyncSettings?.mapping &&
- Object.entries(groupSyncSettings.mapping)
- .sort(([a], [b]) =>
- a.toLowerCase().localeCompare(b.toLowerCase()),
- )
- .map(([idpGroup, groups]) => (
-
- ))}
-
-
{groupSyncSettings?.legacy_group_name_mapping && (
-
+
+
+ Legacy group sync
+
+
+ These settings were configured using environment variables,
+ and only apply to the default organization. Configure IdP sync
+ in the UI or CLI so it can apply to any organization.{" "}
+
+
+
{Object.entries(groupSyncSettings.legacy_group_name_mapping)
.sort(([a], [b]) =>
@@ -375,15 +391,31 @@ export const IdpGroupSyncForm: FC = ({
idpGroup={idpGroup}
exists={claimFieldValues?.includes(idpGroup)}
coderGroup={getGroupNames([groupId])}
- onDelete={handleDelete}
+ onDelete={() => setMappingToDelete(idpGroup)}
/>
))}
)}
-
-
-
+
+
+
setMappingToDelete(undefined)}
+ onConfirm={() => {
+ if (!mappingToDelete) {
+ return;
+ }
+ void handleDelete(mappingToDelete);
+ setMappingToDelete(undefined);
+ }}
+ />
+ >
);
};
@@ -405,23 +437,7 @@ const GroupRow: FC = ({
{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.
-
-
- )}
+ {!exists && }
@@ -431,56 +447,14 @@ const GroupRow: FC = ({
onDelete(idpGroup)}
>
- Delete IdP mapping
);
};
-
-const AutoCreateMissingGroupsHelpPopover: FC = () => {
- return (
-
-
-
-
- Enabling auto create missing groups will automatically create groups
- returned by the OIDC provider if they do not exist in Coder.
-
-
-
- );
-};
-
-const LegacyGroupSyncHeader: FC = () => {
- return (
-
-
- Legacy group sync settings
-
-
-
- Legacy group sync settings
-
- These settings were configured using environment variables, and
- only apply to the default organization. It is now recommended to
- configure IdP sync via the CLI or the UI, which enables sync to be
- configured for any organization, and for those settings to be
- persisted without manually setting environment variables.{" "}
-
- Learn more…
-
-
-
-
-
-
- );
-};
diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx
index 403c9256afb..021c6529a28 100644
--- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx
+++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx
@@ -1,12 +1,8 @@
import { useFormik } from "formik";
-import { PlusIcon, TrashIcon, TriangleAlertIcon } from "lucide-react";
+import { PlusIcon, TrashIcon } from "lucide-react";
import { type FC, type KeyboardEventHandler, useId, useState } from "react";
import * as Yup from "yup";
-import type {
- Organization,
- Role,
- RoleSyncSettings,
-} from "#/api/typesGenerated";
+import type { Role, RoleSyncSettings } from "#/api/typesGenerated";
import { Button } from "#/components/Button/Button";
import {
Combobox,
@@ -23,14 +19,14 @@ import {
MultiSelectCombobox,
type Option,
} from "#/components/MultiSelectCombobox/MultiSelectCombobox";
+import {
+ SettingsHeader,
+ SettingsHeaderDescription,
+ SettingsHeaderTitle,
+} from "#/components/SettingsHeader/SettingsHeader";
import { Spinner } from "#/components/Spinner/Spinner";
import { TableCell, TableRow } from "#/components/Table/Table";
-import {
- Tooltip,
- TooltipContent,
- TooltipTrigger,
-} from "#/components/Tooltip/Tooltip";
-import { ExportPolicyButton } from "./ExportPolicyButton";
+import { IdpUnseenClaimWarning } from "#/modules/idpSync/IdpUnseenClaimWarning";
import { IdpMappingTable } from "./IdpMappingTable";
import { IdpPillList } from "./IdpPillList";
@@ -61,7 +57,6 @@ interface IdpRoleSyncFormProps {
roleSyncSettings: RoleSyncSettings;
claimFieldValues: readonly string[] | undefined;
roleMappingCount: number;
- organization: Organization;
roles: Role[];
onSubmit: (data: RoleSyncSettings) => void;
onSyncFieldChange: (value: string) => void;
@@ -71,7 +66,6 @@ export const IdpRoleSyncForm: FC = ({
roleSyncSettings,
claimFieldValues,
roleMappingCount,
- organization,
roles,
onSubmit,
onSyncFieldChange,
@@ -121,35 +115,35 @@ export const IdpRoleSyncForm: FC = ({
};
return (
-