From b4906ec9ba893c52d6a5d59829184110558da652 Mon Sep 17 00:00:00 2001 From: Fred KISSIE Date: Thu, 30 Apr 2026 22:01:46 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20replace=20roles=20tag?= =?UTF-8?q?=20with=20roles=20selector=20in=20role=20config=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(private)/idp/[idpId]/general/page.tsx | 5 + src/components/RoleMappingConfigFields.tsx | 195 ++++++++++-------- src/components/roles-selector.tsx | 18 +- 3 files changed, 129 insertions(+), 89 deletions(-) diff --git a/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx b/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx index 90b89f76f..538079b8f 100644 --- a/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx +++ b/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx @@ -212,6 +212,11 @@ export default function GeneralPage() { const detectedRoleMappingConfig = detectRoleMappingConfig(roleMapping); + console.log({ + detectedRoleMappingConfig, + roleMapping + }); + // Extract tenant ID from Azure URLs if present let tenantId = ""; if (idpVariant === "azure" && data.idpOidcConfig?.authUrl) { diff --git a/src/components/RoleMappingConfigFields.tsx b/src/components/RoleMappingConfigFields.tsx index d62b7f9e8..4c3054b2a 100644 --- a/src/components/RoleMappingConfigFields.tsx +++ b/src/components/RoleMappingConfigFields.tsx @@ -16,6 +16,9 @@ import { usePaidStatus } from "@app/hooks/usePaidStatus"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { tierMatrix } from "@server/lib/billing/tierMatrix"; import { build } from "@server/build"; +import { RolesSelector } from "./roles-selector"; +import { useOrgContext } from "@app/hooks/useOrgContext"; +import { useParams } from "next/navigation"; export type RoleMappingRoleOption = { roleId: number; @@ -58,9 +61,8 @@ export default function RoleMappingConfigFields({ const t = useTranslations(); const { env } = useEnvContext(); const { isPaidUser } = usePaidStatus(); - const [activeFixedRoleTagIndex, setActiveFixedRoleTagIndex] = useState< - number | null - >(null); + + const { orgId } = useParams(); const supportsMultipleRolesPerUser = isPaidUser(tierMatrix.fullRbac); const showSingleRoleDisclaimer = @@ -160,23 +162,16 @@ export default function RoleMappingConfigFields({ {roleMappingMode === "fixedRoles" && (
- ({ + ({ id: name, text: name }))} - setTags={(nextTags) => { - const prevTags = fixedRoleNames.map((name) => ({ - id: name, - text: name - })); - const next = - typeof nextTags === "function" - ? nextTags(prevTags) - : nextTags; - + mapRolesByName + orgId={orgId as string} + onSelectRoles={(nextTags) => { let names = [ - ...new Set(next.map((tag) => tag.text)) + ...new Set(nextTags.map((tag) => tag.text)) ]; if (!supportsMultipleRolesPerUser) { @@ -198,19 +193,6 @@ export default function RoleMappingConfigFields({ onFixedRoleNamesChange(names); }} - activeTagIndex={activeFixedRoleTagIndex} - setActiveTagIndex={setActiveFixedRoleTagIndex} - placeholder={ - restrictToOrgRoles - ? t("roleMappingFixedRolesPlaceholderSelect") - : t("roleMappingFixedRolesPlaceholderFreeform") - } - enableAutocomplete={restrictToOrgRoles} - autocompleteOptions={roleOptions} - restrictTagsToAutocompleteOptions={restrictToOrgRoles} - allowDuplicates={false} - sortTags={true} - size="sm" /> {showFreeformRoleNamesHint @@ -352,6 +334,7 @@ function BuilderRuleRow({ }) { const t = useTranslations(); const [activeTagIndex, setActiveTagIndex] = useState(null); + const { orgId } = useParams(); return (
- ({ - id: name, - text: name - }))} - setTags={(nextTags) => { - const prevRoleTags = rule.roleNames.map((name) => ({ + {restrictToOrgRoles ? ( + ({ id: name, text: name - })); - const next = - typeof nextTags === "function" - ? nextTags(prevRoleTags) - : nextTags; + }))} + buttonText={t("roleMappingAssignRoles")} + mapRolesByName + orgId={orgId as string} + onSelectRoles={(nextTags) => { + let names = [ + ...new Set(nextTags.map((tag) => tag.text)) + ]; - let names = [ - ...new Set(next.map((tag) => tag.text)) - ]; - - if (!supportsMultipleRolesPerUser) { - if ( - names.length === 0 && - rule.roleNames.length > 0 - ) { - onChange({ - ...rule, - roleNames: [ - rule.roleNames[ - rule.roleNames.length - 1 - ]! - ] - }); - return; + if (!supportsMultipleRolesPerUser) { + if ( + names.length === 0 && + rule.roleNames.length > 0 + ) { + onChange({ + ...rule, + roleNames: [ + rule.roleNames[ + rule.roleNames.length - 1 + ]! + ] + }); + return; + } + if (names.length > 1) { + names = [names[names.length - 1]!]; + } } - if (names.length > 1) { - names = [names[names.length - 1]!]; - } - } - onChange({ - ...rule, - roleNames: names - }); - }} - activeTagIndex={activeTagIndex} - setActiveTagIndex={setActiveTagIndex} - placeholder={ - restrictToOrgRoles - ? t("roleMappingAssignRoles") - : t("roleMappingAssignRolesPlaceholderFreeform") - } - enableAutocomplete={restrictToOrgRoles} - autocompleteOptions={roleOptions} - restrictTagsToAutocompleteOptions={restrictToOrgRoles} - allowDuplicates={false} - sortTags={true} - size="sm" - styleClasses={{ - inlineTagsContainer: "min-w-0 max-w-full" - }} - /> + onChange({ + ...rule, + roleNames: names + }); + }} + /> + ) : ( + ({ + id: name, + text: name + }))} + setTags={(nextTags) => { + const prevRoleTags = rule.roleNames.map( + (name) => ({ + id: name, + text: name + }) + ); + const next = + typeof nextTags === "function" + ? nextTags(prevRoleTags) + : nextTags; + + let names = [ + ...new Set(next.map((tag) => tag.text)) + ]; + + if (!supportsMultipleRolesPerUser) { + if ( + names.length === 0 && + rule.roleNames.length > 0 + ) { + onChange({ + ...rule, + roleNames: [ + rule.roleNames[ + rule.roleNames.length - 1 + ]! + ] + }); + return; + } + if (names.length > 1) { + names = [names[names.length - 1]!]; + } + } + + onChange({ + ...rule, + roleNames: names + }); + }} + activeTagIndex={activeTagIndex} + setActiveTagIndex={setActiveTagIndex} + placeholder={t( + "roleMappingAssignRolesPlaceholderFreeform" + )} + enableAutocomplete={false} + autocompleteOptions={roleOptions} + restrictTagsToAutocompleteOptions={false} + allowDuplicates={false} + sortTags={true} + size="sm" + styleClasses={{ + inlineTagsContainer: "min-w-0 max-w-full" + }} + /> + )}
{showFreeformRoleNamesHint && (

diff --git a/src/components/roles-selector.tsx b/src/components/roles-selector.tsx index 412d6a8e4..f69ff4a98 100644 --- a/src/components/roles-selector.tsx +++ b/src/components/roles-selector.tsx @@ -14,6 +14,8 @@ export type RolesSelectorProps = { onSelectRoles: (roles: SelectedRole[]) => void; disabled?: boolean; restrictAdminRole?: boolean; + mapRolesByName?: boolean; + buttonText?: string; }; export function RolesSelector({ @@ -21,7 +23,9 @@ export function RolesSelector({ selectedRoles = [], onSelectRoles, disabled, - restrictAdminRole + restrictAdminRole, + mapRolesByName, + buttonText }: RolesSelectorProps) { const t = useTranslations(); const [roleSearchQuery, setRoleSearchQuery] = useState(""); @@ -36,7 +40,7 @@ export function RolesSelector({ const rolesShown = useMemo(() => { let allRoles: Array = roles.map( (r) => ({ - id: r.roleId.toString(), + id: mapRolesByName ? r.name : r.roleId.toString(), text: r.name, isAdmin: Boolean(r.isAdmin) }) @@ -55,11 +59,17 @@ export function RolesSelector({ } return allRoles; - }, [roles, selectedRoles, debouncedValue, restrictAdminRole]); + }, [ + roles, + selectedRoles, + debouncedValue, + restrictAdminRole, + mapRolesByName + ]); return (