Changed the idP mapper form to use the new Dynamic forms (#1641)

This commit is contained in:
Erik Jan de Wit 2021-12-14 23:46:19 +01:00 committed by GitHub
parent 920ac1dfe3
commit 67d2c8617f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 300 additions and 829 deletions

View file

@ -128,7 +128,7 @@ describe("Identity provider test", () => {
masthead.checkNotificationMessage(createMapperSuccessMsg, true); masthead.checkNotificationMessage(createMapperSuccessMsg, true);
}); });
it.skip("should edit Username Template Importer mapper", () => { it("should edit Username Template Importer mapper", () => {
sidebarPage.goToIdentityProviders(); sidebarPage.goToIdentityProviders();
listingPage.goToItemDetails(samlProviderName); listingPage.goToItemDetails(samlProviderName);
addMapperPage.goToMappersTab(); addMapperPage.goToMappersTab();

View file

@ -7,28 +7,26 @@ export default class AddMapperPage {
private mapperNameInput = "#kc-name"; private mapperNameInput = "#kc-name";
private mapperRoleInput = "mapper-role-input"; private mapperRoleInput = "mapper-role-input";
private attributeName = "attribute-name"; private attribute = "user.attribute";
private attributeFriendlyName = "attribute-friendly-name"; private attributeName = "attribute.name";
private attributeFriendlyName = "attribute.friendly.name";
private attributeValue = "attribute-value"; private attributeValue = "attribute-value";
private claimInput = "claim"; private claimInput = "claim";
private claimValueInput = "claim-value-input"; private claimValueInput = "claim-value-input";
private socialProfileJSONfieldPath = "social-profile-JSON-field-path"; private socialProfileJSONfieldPath = "jsonField";
private userAttribute = "user-attribute"; private userAttribute = "attribute";
private userAttributeName = "user-attribute-name"; private userAttributeName = "userAttribute";
private userAttributeValue = "user-attribute-value"; private userAttributeValue = "attribute.value";
private userSessionAttribute = "user-session-attribute"; private userSessionAttribute = "attribute";
private userSessionAttributeValue = "user-session-attribute-value"; private userSessionAttributeValue = "attribute.value";
private newMapperSaveButton = "new-mapper-save-button"; private newMapperSaveButton = "new-mapper-save-button";
private regexAttributeValuesSwitch = "regex-values-switch"; private regexAttributeValuesSwitch = "are.attribute.values.regex";
private syncmodeSelectToggle = "#syncMode"; private syncmodeSelectToggle = "#syncMode";
private attributesKeyInput = 'input[name="config.attributes[0].key"]'; private attributesKeyInput = 'input[name="config.attributes[0].key"]';
private attributesValueInput = 'input[name="config.attributes[0].value"]'; private attributesValueInput = 'input[name="config.attributes[0].value"]';
private template = "template"; private template = "template";
private target = "#target"; private target = "#target";
private targetDropdown = "#target-dropdown"; private targetDropdown = "#target-dropdown";
private selectRoleButton = "select-role-button";
private radio = "[type=radio]";
private addAssociatedRolesModalButton = "add-associated-roles-button";
goToMappersTab() { goToMappersTab() {
cy.findByTestId(this.mappersTab).click(); cy.findByTestId(this.mappersTab).click();
@ -91,14 +89,16 @@ export default class AddMapperPage {
} }
addRoleToMapperForm() { addRoleToMapperForm() {
const load = "/auth/admin/realms/master/roles"; cy.get("#group-role-select-typeahead")
cy.intercept(load).as("load"); .click()
.get(".pf-c-select__menu-item")
cy.get(this.radio).eq(0).check(); .first()
.click();
cy.findByTestId(this.addAssociatedRolesModalButton).contains("Add").click(); cy.get("#role-role-select-typeahead")
.click()
cy.findByTestId(this.mapperRoleInput).should("have.value", "admin"); .get(".pf-c-select__menu-item")
.first()
.click();
return this; return this;
} }
@ -115,7 +115,7 @@ export default class AddMapperPage {
cy.get(this.idpMapperSelectToggle).click(); cy.get(this.idpMapperSelectToggle).click();
cy.findByTestId(this.idpMapperSelect) cy.findByTestId(this.idpMapperSelect)
.contains("Advanced Attribute To Role") .contains("Advanced Attribute to Role")
.click(); .click();
cy.get(this.attributesKeyInput).clear(); cy.get(this.attributesKeyInput).clear();
@ -126,8 +126,6 @@ export default class AddMapperPage {
this.toggleSwitch(this.regexAttributeValuesSwitch); this.toggleSwitch(this.regexAttributeValuesSwitch);
cy.findByTestId(this.selectRoleButton).click();
this.addRoleToMapperForm(); this.addRoleToMapperForm();
this.saveNewMapper(); this.saveNewMapper();
@ -153,9 +151,7 @@ export default class AddMapperPage {
cy.findByTestId(this.template).clear(); cy.findByTestId(this.template).clear();
cy.findByTestId(this.template).type("Template"); cy.findByTestId(this.template).type("Template");
cy.get(this.target).click(); cy.get(this.target).click().parent().contains("BROKER_ID").click();
cy.get(this.targetDropdown).contains("LOCAL").click();
this.saveNewMapper(); this.saveNewMapper();
@ -211,8 +207,7 @@ export default class AddMapperPage {
cy.findByTestId(this.attributeFriendlyName).clear(); cy.findByTestId(this.attributeFriendlyName).clear();
cy.findByTestId(this.attributeFriendlyName).type("attribute friendly name"); cy.findByTestId(this.attributeFriendlyName).type("attribute friendly name");
cy.findByTestId(this.userAttributeName).clear(); cy.findByTestId(this.attribute).clear().type("user attribute name");
cy.findByTestId(this.userAttributeName).type("user attribute name");
this.saveNewMapper(); this.saveNewMapper();
@ -234,11 +229,8 @@ export default class AddMapperPage {
.contains("Attribute Importer") .contains("Attribute Importer")
.click(); .click();
cy.findByTestId(this.claimInput).clear(); cy.findByTestId(this.claimInput).clear().type("claim");
cy.findByTestId(this.claimInput).type("claim"); cy.findByTestId(this.attribute).clear().type("user attribute name");
cy.findByTestId(this.userAttributeName).clear();
cy.findByTestId(this.userAttributeName).type("user attribute name");
this.saveNewMapper(); this.saveNewMapper();
@ -258,9 +250,7 @@ export default class AddMapperPage {
cy.findByTestId(this.idpMapperSelect).contains("Hardcoded Role").click(); cy.findByTestId(this.idpMapperSelect).contains("Hardcoded Role").click();
cy.findByTestId(this.mapperRoleInput).clear(); this.addRoleToMapperForm();
cy.findByTestId(this.mapperRoleInput).type("admin");
this.saveNewMapper(); this.saveNewMapper();
return this; return this;
@ -281,13 +271,11 @@ export default class AddMapperPage {
.contains("Hardcoded Attribute") .contains("Hardcoded Attribute")
.click(); .click();
cy.findByTestId(this.userAttribute).clear(); cy.findByTestId(this.userAttribute).clear().type("user session attribute");
cy.findByTestId(this.userAttribute).type("user session attribute");
cy.findByTestId(this.userAttributeValue).clear(); cy.findByTestId(this.userAttributeValue)
cy.findByTestId(this.userAttributeValue).type( .clear()
"user session attribute value" .type("user session attribute value");
);
this.saveNewMapper(); this.saveNewMapper();
@ -306,11 +294,10 @@ export default class AddMapperPage {
cy.get(this.idpMapperSelectToggle).click(); cy.get(this.idpMapperSelectToggle).click();
cy.findByTestId(this.idpMapperSelect) cy.findByTestId(this.idpMapperSelect)
.contains("SAML Attribute To Role") .contains("SAML Attribute to Role")
.click(); .click();
cy.findByTestId(this.mapperRoleInput).clear(); this.addRoleToMapperForm();
cy.findByTestId(this.mapperRoleInput).type("admin");
this.saveNewMapper(); this.saveNewMapper();
@ -324,9 +311,7 @@ export default class AddMapperPage {
cy.findByTestId(this.template).type("_edited"); cy.findByTestId(this.template).type("_edited");
cy.get(this.target).click(); cy.get(this.target).click().parent().contains("BROKER_USERNAME").click();
cy.get(this.targetDropdown).contains("BROKER_ID").click();
this.saveNewMapper(); this.saveNewMapper();
@ -408,19 +393,14 @@ export default class AddMapperPage {
cy.get(this.idpMapperSelectToggle).click(); cy.get(this.idpMapperSelectToggle).click();
cy.findByTestId(this.idpMapperSelect).contains("Claim To Role").click(); cy.findByTestId(this.idpMapperSelect).contains("Claim to Role").click();
cy.get(this.attributesKeyInput).clear(); cy.findByTestId("attribute-key-input").clear().type("key");
cy.get(this.attributesKeyInput).type("key"); cy.findByTestId("attribute-value-input").clear().type("value");
cy.get(this.attributesValueInput).clear(); this.toggleSwitch("are.claim.values.regex");
cy.get(this.attributesValueInput).type("value");
this.toggleSwitch(this.regexAttributeValuesSwitch);
cy.findByTestId(this.mapperRoleInput).clear();
cy.findByTestId(this.mapperRoleInput).type("admin");
this.addRoleToMapperForm();
this.saveNewMapper(); this.saveNewMapper();
return this; return this;

View file

@ -30,8 +30,6 @@ export default {
addMapperExplain: addMapperExplain:
"If you want more fine-grain control, you can create protocol mapper on this client", "If you want more fine-grain control, you can create protocol mapper on this client",
realmRoles: "Realm roles", realmRoles: "Realm roles",
clientRoles: "Client roles",
selectASourceOfRoles: "Select a source of roles",
newRoleName: "New role name", newRoleName: "New role name",
searchClientByName: "Search client by name", searchClientByName: "Search client by name",
clients: "Clients", clients: "Clients",
@ -50,8 +48,6 @@ export default {
predefinedMappingDescription: predefinedMappingDescription:
"Choose one of the predefined mappings from this table", "Choose one of the predefined mappings from this table",
mappingTable: "Table with predefined mapping", mappingTable: "Table with predefined mapping",
roleGroup: "Use a realm role from:",
clientGroup: "Use a client role from:",
scope: "Scope", scope: "Scope",
roleMappingUpdatedSuccess: "Role mapping updated", roleMappingUpdatedSuccess: "Role mapping updated",
roleMappingUpdatedError: "Could not update role mapping {{error}}", roleMappingUpdatedError: "Could not update role mapping {{error}}",

View file

@ -27,7 +27,7 @@ export const BooleanComponent = ({
<Controller <Controller
name={`config.${name}`} name={`config.${name}`}
data-testid={name} data-testid={name}
defaultValue={defaultValue} defaultValue={defaultValue || false}
control={control} control={control}
render={({ onChange, value }) => ( render={({ onChange, value }) => (
<Switch <Switch
@ -36,6 +36,7 @@ export const BooleanComponent = ({
labelOff={t("common:off")} labelOff={t("common:off")}
isChecked={value === "true" || value === true} isChecked={value === "true" || value === true}
onChange={(value) => onChange("" + value)} onChange={(value) => onChange("" + value)}
data-testid={name}
/> />
)} )}
/> />

View file

@ -0,0 +1,75 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import {
Button,
Chip,
ChipGroup,
FormGroup,
InputGroup,
} from "@patternfly/react-core";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import { GroupPickerDialog } from "../group/GroupPickerDialog";
export const GroupComponent = ({ name, label, helpText }: ComponentProps) => {
const { t } = useTranslation("dynamic");
const [open, setOpen] = useState(false);
const { control } = useFormContext();
return (
<Controller
name={`config.${name}`}
defaultValue=""
typeAheadAriaLabel={t("selectGroup")}
control={control}
render={({ onChange, value }) => (
<>
{open && (
<GroupPickerDialog
type="selectOne"
text={{
title: "dynamic:selectGroup",
ok: "common:select",
}}
onConfirm={(groups) => {
onChange(groups[0].path);
setOpen(false);
}}
onClose={() => setOpen(false)}
filterGroups={value}
/>
)}
<FormGroup
label={t(label!)}
labelIcon={
<HelpItem
helpText={t(helpText!)}
fieldLabelId={`dynamic:${label}`}
/>
}
fieldId={name!}
>
<InputGroup>
<ChipGroup>
{value && (
<Chip onClick={() => onChange(undefined)}>{value}</Chip>
)}
</ChipGroup>
<Button
id="kc-join-groups-button"
onClick={() => setOpen(!open)}
variant="secondary"
data-testid="join-groups-button"
>
{t("selectGroup")}
</Button>
</InputGroup>
</FormGroup>
</>
)}
/>
);
};

View file

@ -0,0 +1,23 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { FormGroup } from "@patternfly/react-core";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import { AttributeInput } from "../attribute-input/AttributeInput";
export const MapComponent = ({ name, label, helpText }: ComponentProps) => {
const { t } = useTranslation("dynamic");
return (
<FormGroup
label={t(label!)}
labelIcon={
<HelpItem helpText={t(helpText!)} fieldLabelId={`dynamic:${label}`} />
}
fieldId={name!}
>
<AttributeInput name={`config.${name}`} />
</FormGroup>
);
};

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
@ -19,12 +19,17 @@ import { useRealm } from "../../context/realm-context/RealmContext";
import { HelpItem } from "../help-enabler/HelpItem"; import { HelpItem } from "../help-enabler/HelpItem";
import type { ComponentProps } from "./components"; import type { ComponentProps } from "./components";
const RealmClient = (realm: string): ClientRepresentation => ({
name: "realmRoles",
clientId: realm,
});
export const RoleComponent = ({ name, label, helpText }: ComponentProps) => { export const RoleComponent = ({ name, label, helpText }: ComponentProps) => {
const { t } = useTranslation("dynamic"); const { t } = useTranslation("dynamic");
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { realm } = useRealm(); const { realm } = useRealm();
const { control, errors } = useFormContext(); const { control, errors, getValues } = useFormContext();
const [roleOpen, setRoleOpen] = useState(false); const [roleOpen, setRoleOpen] = useState(false);
const [clientsOpen, setClientsOpen] = useState(false); const [clientsOpen, setClientsOpen] = useState(false);
@ -51,30 +56,29 @@ export const RoleComponent = ({ name, label, helpText }: ComponentProps) => {
(await adminClient.clients.listRoles({ id: client.id! })).length > 0 (await adminClient.clients.listRoles({ id: client.id! })).length > 0
); );
filteredClients.map(
(client) =>
(client.toString = function () {
return this.clientId!;
})
);
return filteredClients; return filteredClients;
}, },
(filteredClients) => setClients(filteredClients), (filteredClients) => setClients(filteredClients),
[] []
); );
useEffect(() => {
const value = getValues(fieldName);
const [client, role] = value?.includes(".")
? value.split(".")
: ["", value || ""];
if (client) {
setSelectedClient(clients?.find((c) => c.clientId === client));
} else {
setSelectedClient(RealmClient(realm));
}
setSelectedRole({ name: role });
}, [clients, getValues]);
const createSelectGroup = (clients: ClientRepresentation[]) => { const createSelectGroup = (clients: ClientRepresentation[]) => {
return [ return [
<SelectGroup key="role" label={t("roleGroup")}> <SelectGroup key="role" label={t("roleGroup")}>
<SelectOption <SelectOption key="realmRoles" value={RealmClient(realm)}>
key="realmRoles"
value={
{
name: "realmRoles",
toString: () => t("realmRoles"),
} as ClientRepresentation
}
>
{realm} {realm}
</SelectOption> </SelectOption>
</SelectGroup>, </SelectGroup>,
@ -133,75 +137,76 @@ export const RoleComponent = ({ name, label, helpText }: ComponentProps) => {
name={fieldName} name={fieldName}
defaultValue="" defaultValue=""
control={control} control={control}
rules={{ required: true }} render={({ onChange }) => (
render={({ onChange, value }) => { <Split hasGutter>
const [client, role] = value?.split(".") || ["", ""]; <SplitItem>
return ( {clients && (
<Split hasGutter>
<SplitItem>
{clients && (
<Select
toggleId={name!}
data-testid={name}
onToggle={() => setClientsOpen(!clientsOpen)}
isOpen={clientsOpen}
variant={SelectVariant.typeahead}
typeAheadAriaLabel={t("selectASourceOfRoles")}
placeholderText={t("selectASourceOfRoles")}
isGrouped
onFilter={(evt) => {
const textInput = evt?.target.value || "";
if (textInput === "") {
return createSelectGroup(clients);
} else {
return createSelectGroup(
clients.filter((client) =>
client
.name!.toLowerCase()
.includes(textInput.toLowerCase())
)
);
}
}}
selections={selectedClient || client}
onClear={() => onClear(onChange)}
onSelect={(_, value) => {
setSelectedClient(value as ClientRepresentation);
setClientsOpen(false);
}}
>
{createSelectGroup(clients)}
</Select>
)}
</SplitItem>
<SplitItem>
<Select <Select
onToggle={(isExpanded) => setRoleOpen(isExpanded)} toggleId={`group-${name}`}
isOpen={roleOpen} onToggle={() => setClientsOpen(!clientsOpen)}
isOpen={clientsOpen}
variant={SelectVariant.typeahead} variant={SelectVariant.typeahead}
placeholderText={ typeAheadAriaLabel={t("selectASourceOfRoles")}
selectedClient?.name !== "realmRoles" placeholderText={t("selectASourceOfRoles")}
? t("clientRoles") isGrouped
: t("selectARole") onFilter={(evt) => {
} const textInput = evt?.target.value || "";
isDisabled={!selectedClient && !role} if (textInput === "") {
typeAheadAriaLabel={t("selectARole")} return createSelectGroup(clients);
selections={selectedRole?.name || role} } else {
onSelect={(_, value) => { return createSelectGroup(
const role = value as RoleRepresentation; clients.filter((client) =>
setSelectedRole(role); client
onChange(`${selectedClient?.clientId}.${role.name}`); .name!.toLowerCase()
setRoleOpen(false); .includes(textInput.toLowerCase())
)
);
}
}} }}
maxHeight={200} selections={selectedClient?.clientId}
onClear={() => onClear(onChange)} onClear={() => onClear(onChange)}
onSelect={(_, value) => {
onClear(onChange);
setSelectedClient(value as ClientRepresentation);
setClientsOpen(false);
}}
> >
{roleSelectOptions()} {createSelectGroup(clients)}
</Select> </Select>
</SplitItem> )}
</Split> </SplitItem>
); <SplitItem>
}} <Select
toggleId={`role-${name}`}
onToggle={(isExpanded) => setRoleOpen(isExpanded)}
isOpen={roleOpen}
variant={SelectVariant.typeahead}
placeholderText={
selectedClient?.name !== "realmRoles"
? t("clientRoles")
: t("selectARole")
}
isDisabled={!selectedClient}
typeAheadAriaLabel={t("selectARole")}
selections={selectedRole?.name}
onSelect={(_, value) => {
const role = value as RoleRepresentation;
setSelectedRole(role);
onChange(
selectedClient?.name === "realmRoles"
? role.name
: `${selectedClient?.clientId}.${role.name}`
);
setRoleOpen(false);
}}
maxHeight={200}
onClear={() => onClear(onChange)}
>
{roleSelectOptions()}
</Select>
</SplitItem>
</Split>
)}
/> />
</FormGroup> </FormGroup>
); );

View file

@ -5,10 +5,12 @@ import { StringComponent } from "./StringComponent";
import { BooleanComponent } from "./BooleanComponent"; import { BooleanComponent } from "./BooleanComponent";
import { ListComponent } from "./ListComponent"; import { ListComponent } from "./ListComponent";
import { RoleComponent } from "./RoleComponent"; import { RoleComponent } from "./RoleComponent";
import { MapComponent } from "./MapComponent";
import { ScriptComponent } from "./ScriptComponent"; import { ScriptComponent } from "./ScriptComponent";
import { ClientSelectComponent } from "./ClientSelectComponent"; import { ClientSelectComponent } from "./ClientSelectComponent";
import { MultiValuedStringComponent } from "./MultivaluedStringComponent"; import { MultiValuedStringComponent } from "./MultivaluedStringComponent";
import { MultiValuedListComponent } from "./MultivaluedListComponent"; import { MultiValuedListComponent } from "./MultivaluedListComponent";
import { GroupComponent } from "./GroupComponent";
export type ComponentProps = Omit<ConfigPropertyRepresentation, "type">; export type ComponentProps = Omit<ConfigPropertyRepresentation, "type">;
const ComponentTypes = [ const ComponentTypes = [
@ -17,6 +19,8 @@ const ComponentTypes = [
"List", "List",
"Role", "Role",
"Script", "Script",
"Map",
"Group",
"MultivaluedList", "MultivaluedList",
"ClientList", "ClientList",
"MultivaluedString", "MultivaluedString",
@ -32,6 +36,8 @@ export const COMPONENTS: {
List: ListComponent, List: ListComponent,
Role: RoleComponent, Role: RoleComponent,
Script: ScriptComponent, Script: ScriptComponent,
Map: MapComponent,
Group: GroupComponent,
ClientList: ClientSelectComponent, ClientList: ClientSelectComponent,
MultivaluedList: MultiValuedListComponent, MultivaluedList: MultiValuedListComponent,
MultivaluedString: MultiValuedStringComponent, MultivaluedString: MultiValuedStringComponent,

View file

@ -2,6 +2,11 @@ export default {
dynamic: { dynamic: {
addMultivaluedLabel: "Add {{fieldLabel}}", addMultivaluedLabel: "Add {{fieldLabel}}",
selectARole: "Select a role", selectARole: "Select a role",
selectASourceOfRoles: "Select a source of roles",
clientRoles: "Client roles",
roleGroup: "Use a realm role from:",
clientGroup: "Use a client role from:",
selectGroup: "Select group",
usermodel: { usermodel: {
prop: { prop: {
label: "Property", label: "Property",

View file

@ -1,31 +1,23 @@
import React, { useMemo, useState } from "react"; import React, { useState } from "react";
import { Link, useHistory, useParams } from "react-router-dom"; import { Link, useHistory, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Controller, FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
Button, Button,
FormGroup, FormGroup,
PageSection, PageSection,
Select,
SelectOption,
SelectVariant,
Switch,
TextInput, TextInput,
ValidatedOptions, ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
import { AttributeInput } from "../../components/attribute-input/AttributeInput";
import type { AttributeForm } from "../../components/attribute-form/AttributeForm";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import type { IdentityProviderAddMapperParams } from "../routes/AddMapper"; import type { IdentityProviderAddMapperParams } from "../routes/AddMapper";
import { AssociatedRolesModal } from "../../realm-roles/AssociatedRolesModal";
import type { RoleRepresentation } from "../../model/role-model"; import type { RoleRepresentation } from "../../model/role-model";
import { useAlerts } from "../../components/alert/Alerts"; import { useAlerts } from "../../components/alert/Alerts";
import { import {
@ -35,9 +27,11 @@ import {
import { convertFormValuesToObject, convertToFormValues } from "../../util"; import { convertFormValuesToObject, convertToFormValues } from "../../util";
import { toIdentityProvider } from "../routes/IdentityProvider"; import { toIdentityProvider } from "../routes/IdentityProvider";
import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation"; import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation";
import type { IdentityProviderMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperTypeRepresentation";
import { AddMapperForm } from "./AddMapperForm"; import { AddMapperForm } from "./AddMapperForm";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; import { DynamicComponents } from "../../components/dynamic/DynamicComponents";
import { groupBy } from "lodash"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import type { AttributeForm } from "../../components/attribute-form/AttributeForm";
export type IdPMapperRepresentationWithAttributes = export type IdPMapperRepresentationWithAttributes =
IdentityProviderMapperRepresentation & AttributeForm; IdentityProviderMapperRepresentation & AttributeForm;
@ -49,8 +43,10 @@ export type Role = RoleRepresentation & {
export default function AddMapper() { export default function AddMapper() {
const { t } = useTranslation("identity-providers"); const { t } = useTranslation("identity-providers");
const form = useForm<IdPMapperRepresentationWithAttributes>(); const form = useForm<IdPMapperRepresentationWithAttributes>({
const { handleSubmit, control, register, errors } = form; shouldUnregister: false,
});
const { handleSubmit, register, errors } = form;
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const history = useHistory(); const history = useHistory();
@ -60,56 +56,38 @@ export default function AddMapper() {
const { providerId, alias } = useParams<IdentityProviderAddMapperParams>(); const { providerId, alias } = useParams<IdentityProviderAddMapperParams>();
const { id } = useParams<IdentityProviderEditMapperParams>(); const { id } = useParams<IdentityProviderEditMapperParams>();
const serverInfo = useServerInfo();
const identityProviders = useMemo(
() => groupBy(serverInfo.identityProviders, "groupName"),
[serverInfo]
);
const isSocialIdP = useMemo(
() =>
identityProviders["Social"]
.map((item) => item.id)
.includes(providerId.toLowerCase()),
[identityProviders, providerId]
);
const [mapperTypes, setMapperTypes] = const [mapperTypes, setMapperTypes] =
useState<Record<string, IdentityProviderMapperRepresentation>>(); useState<Record<string, IdentityProviderMapperTypeRepresentation>>();
const [mapperType, setMapperType] = useState( const [mapperType, setMapperType] = useState<string>();
isSocialIdP
? "attributeImporter"
: providerId === "saml"
? "advancedAttributeToRole"
: "hardcodedUserSessionAttribute"
);
const [currentMapper, setCurrentMapper] = const [currentMapper, setCurrentMapper] =
useState<IdentityProviderMapperRepresentation>(); useState<IdentityProviderMapperRepresentation>();
const [rolesModalOpen, setRolesModalOpen] = useState(false);
const save = async (idpMapper: IdentityProviderMapperRepresentation) => { const save = async (idpMapper: IdentityProviderMapperRepresentation) => {
const attributes = JSON.stringify(idpMapper.config?.attributes ?? []); const mapper = convertFormValuesToObject(
const mapper = convertFormValuesToObject(idpMapper); idpMapper
) as IdentityProviderMapperRepresentation;
const attributes = JSON.stringify(idpMapper.config.attributes ?? []);
const claims = JSON.stringify(idpMapper.config.claims ?? []);
const identityProviderMapper = {
...mapper,
config: {
...mapper.config,
attributes,
claims,
},
identityProviderAlias: alias!,
};
if (id) { if (id) {
const updatedMapper = {
...mapper,
config: {
attributes,
},
identityProviderAlias: alias!,
id: id,
name: currentMapper?.name!,
};
try { try {
await adminClient.identityProviders.updateMapper( await adminClient.identityProviders.updateMapper(
{ {
id: id!, id: id!,
alias: alias!, alias: alias!,
}, },
updatedMapper { ...identityProviderMapper, name: currentMapper?.name! }
); );
addAlert(t("mapperSaveSuccess"), AlertVariant.success); addAlert(t("mapperSaveSuccess"), AlertVariant.success);
} catch (error) { } catch (error) {
@ -118,13 +96,7 @@ export default function AddMapper() {
} else { } else {
try { try {
const createdMapper = await adminClient.identityProviders.createMapper({ const createdMapper = await adminClient.identityProviders.createMapper({
identityProviderMapper: { identityProviderMapper,
...mapper,
identityProviderAlias: alias,
config: {
attributes,
},
},
alias: alias!, alias: alias!,
}); });
@ -153,6 +125,9 @@ export default function AddMapper() {
if (mapper) { if (mapper) {
setCurrentMapper(mapper); setCurrentMapper(mapper);
setupForm(mapper); setupForm(mapper);
setMapperType(mapper.identityProviderMapper!);
} else {
setMapperType(Object.keys(mapperTypes)[0]);
} }
setMapperTypes(mapperTypes); setMapperTypes(mapperTypes);
@ -161,58 +136,14 @@ export default function AddMapper() {
); );
const setupForm = (mapper: IdentityProviderMapperRepresentation) => { const setupForm = (mapper: IdentityProviderMapperRepresentation) => {
form.reset();
convertToFormValues(mapper, form.setValue); convertToFormValues(mapper, form.setValue);
form.setValue("config.attributes", JSON.parse(mapper.config.attributes)); form.setValue("config.attributes", JSON.parse(mapper.config.attributes));
form.setValue("config.claims", JSON.parse(mapper.config.claims));
}; };
const targetOptions = ["local", "brokerId", "brokerUsername"]; if (!mapperTypes) {
const [targetOptionsOpen, setTargetOptionsOpen] = useState(false); return <KeycloakSpinner />;
const [selectedRole, setSelectedRole] = useState<Role[]>([]); }
const formValues = form.getValues();
const isSAMLAdvancedAttrToRole =
formValues.identityProviderMapper === "saml-advanced-role-idp-mapper";
const isOIDCclaimToRole =
formValues.identityProviderMapper === "oidc-role-idp-mapper";
const isOIDCAdvancedClaimToRole =
formValues.identityProviderMapper === "oidc-advanced-role-idp-mapper";
const isSAMLAttributeImporter =
formValues.identityProviderMapper === "saml-user-attribute-idp-mapper";
const isOIDCAttributeImporter =
formValues.identityProviderMapper === "oidc-user-attribute-idp-mapper";
const isHardcodedAttribute =
formValues.identityProviderMapper === "hardcoded-attribute-idp-mapper";
const isHardcodedRole =
formValues.identityProviderMapper === "oidc-hardcoded-role-idp-mapper";
const isHardcodedUserSessionAttribute =
formValues.identityProviderMapper ===
"hardcoded-user-session-attribute-idp-mapper";
const isSAMLAttributeToRole =
formValues.identityProviderMapper === "saml-role-idp-mapper";
const isSAMLUsernameTemplateImporter =
formValues.identityProviderMapper === "saml-username-idp-mapper";
const isOIDCUsernameTemplateImporter =
formValues.identityProviderMapper === "oidc-username-idp-mapper";
const isSocialAttributeImporter = useMemo(
() => formValues.identityProviderMapper?.includes("user-attribute-mapper"),
[formValues.identityProviderMapper]
);
const toggleModal = () => {
setRolesModalOpen(!rolesModalOpen);
};
return ( return (
<PageSection variant="light"> <PageSection variant="light">
@ -231,16 +162,6 @@ export default function AddMapper() {
} }
divider divider
/> />
{rolesModalOpen && (
<AssociatedRolesModal
id={id}
onConfirm={(role) => setSelectedRole(role)}
omitComposites
isRadio
isMapperId
toggleDialog={toggleModal}
/>
)}
<FormAccess <FormAccess
role="manage-identity-providers" role="manage-identity-providers"
isHorizontal isHorizontal
@ -275,511 +196,15 @@ export default function AddMapper() {
id={id} id={id}
mapperTypes={mapperTypes} mapperTypes={mapperTypes}
updateMapperType={setMapperType} updateMapperType={setMapperType}
formValues={formValues} mapperType={mapperType!}
mapperType={mapperType}
isSocialIdP={isSocialIdP}
/> />
<> <FormProvider {...form}>
{(isSAMLAdvancedAttrToRole || isOIDCAdvancedClaimToRole) && ( {mapperType && mapperTypes[mapperType].properties && (
<> <DynamicComponents
<FormGroup properties={mapperTypes[mapperType].properties!}
label={ />
isSAMLAdvancedAttrToRole
? t("common:attributes")
: t("claims")
}
labelIcon={
<HelpItem
helpText={
isSAMLAdvancedAttrToRole
? "identity-providers-help:attributes"
: "identity-providers-help:claims"
}
fieldLabelId={
isSAMLAdvancedAttrToRole ? "attributes" : "claims"
}
/>
}
fieldId="kc-gui-order"
>
<FormProvider {...form}>
<AttributeInput name="config.attributes" />
</FormProvider>
</FormGroup>
<FormGroup
label={
isSAMLAdvancedAttrToRole
? t("regexAttributeValues")
: t("regexClaimValues")
}
labelIcon={
<HelpItem
helpText="identity-providers-help:regexAttributeValues"
fieldLabelId="identity-providers:regexAttributeValues"
/>
}
fieldId="regexAttributeValues"
>
<Controller
name={
isOIDCAdvancedClaimToRole
? "config.are.claim.values.regex"
: "config.are.attribute.values.regex"
}
control={control}
defaultValue="false"
render={({ onChange, value }) => (
<Switch
id="regexValues"
data-testid="regex-values-switch"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value === "true"}
onChange={(value) => onChange("" + value)}
/>
)}
/>
</FormGroup>
</>
)} )}
{(isSAMLUsernameTemplateImporter || </FormProvider>
isOIDCUsernameTemplateImporter) && (
<>
<FormGroup
label={t("template")}
labelIcon={
<HelpItem
helpText="identity-providers-help:template"
fieldLabelId="identity-providers:template"
/>
}
fieldId="kc-user-session-attribute"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
id="kc-template"
data-testid="template"
name="config.template"
defaultValue={currentMapper?.config.template}
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
<FormGroup
label={t("target")}
labelIcon={
<HelpItem
helpText="identity-providers-help:target"
fieldLabelId="identity-providers:target"
/>
}
fieldId="kc-target"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<Controller
name="config.target"
defaultValue={currentMapper?.config.target}
control={control}
render={({ onChange, value }) => (
<Select
toggleId="target"
datatest-id="target-select"
id="target-dropdown"
placeholderText={t("realm-settings:placeholderText")}
direction="down"
onToggle={() => setTargetOptionsOpen(!targetOptionsOpen)}
onSelect={(_, value) => {
onChange(t(`targetOptions.${value}`));
setTargetOptionsOpen(false);
}}
selections={value}
variant={SelectVariant.single}
aria-label={t("target")}
isOpen={targetOptionsOpen}
>
{targetOptions.map((option) => (
<SelectOption
selected={option === value}
key={option}
data-testid={option}
value={option}
>
{t(`targetOptions.${option}`)}
</SelectOption>
))}
</Select>
)}
/>
</FormGroup>
</>
)}
{(isHardcodedAttribute || isHardcodedUserSessionAttribute) && (
<>
<FormGroup
label={
isHardcodedUserSessionAttribute
? t("userSessionAttribute")
: t("userAttribute")
}
labelIcon={
<HelpItem
helpText="identity-providers-help:userSessionAttribute"
fieldLabelId="identity-providers:userSessionAttribute"
/>
}
fieldId="kc-user-session-attribute"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={currentMapper?.config.attribute}
id="kc-attribute"
data-testid={
isHardcodedUserSessionAttribute
? "user-session-attribute"
: "user-attribute"
}
name="config.attribute"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
<FormGroup
label={
isHardcodedUserSessionAttribute
? t("userSessionAttributeValue")
: t("userAttributeValue")
}
labelIcon={
<HelpItem
helpText="identity-providers-help:userAttributeValue"
fieldLabelId={
isHardcodedUserSessionAttribute
? "identity-providers:userSessionAttributeValue"
: "identity-providers:userAttributeValue"
}
/>
}
fieldId="kc-user-session-attribute-value"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={currentMapper?.config["attribute.value"]}
data-testid={
isHardcodedUserSessionAttribute
? "user-session-attribute-value"
: "user-attribute-value"
}
id="kc-user-session-attribute-value"
name="config.attribute.value"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
</>
)}
{(isSAMLAttributeImporter ||
isOIDCAttributeImporter ||
isOIDCclaimToRole) && (
<>
{isSAMLAttributeImporter ? (
<>
<FormGroup
label={t("mapperAttributeName")}
labelIcon={
<HelpItem
helpText="identity-providers-help:attributeName"
fieldLabelId="identity-providers:mapperAttributeName"
/>
}
fieldId="kc-attribute-name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={currentMapper?.config["attribute.name"]}
id="kc-attribute-name"
data-testid="attribute-name"
name="config.attribute.name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
<FormGroup
label={t("mapperAttributeFriendlyName")}
labelIcon={
<HelpItem
helpText="identity-providers-help:friendlyName"
fieldLabelId="identity-providers:mapperAttributeFriendlyName"
/>
}
fieldId="kc-friendly-name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={
currentMapper?.config["attribute.friendly.name"]
}
data-testid="attribute-friendly-name"
id="kc-attribute-friendly-name"
name="config.attribute.friendly.name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
</>
) : (
<FormGroup
label={t("claim")}
labelIcon={
<HelpItem
helpText="identity-providers-help:claim"
fieldLabelId="identity-providers:claim"
/>
}
fieldId="kc-friendly-name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={currentMapper?.config["claim"]}
data-testid="claim"
id="kc-claim"
name={"config.claim"}
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
)}
<FormGroup
label={
isOIDCclaimToRole
? t("claimValue")
: t("mapperUserAttributeName")
}
labelIcon={
<HelpItem
helpText={
isOIDCclaimToRole
? "identity-providers-help:claimValue"
: "identity-providers-help:userAttributeName"
}
fieldLabelId="identity-providers:mapperUserAttributeName"
/>
}
fieldId="kc-user-attribute-name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={
isOIDCclaimToRole
? currentMapper?.config["claim.value"]
: currentMapper?.config["attribute.value"]
}
data-testid={
isOIDCclaimToRole ? "claim.value" : "user-attribute-name"
}
id={
isOIDCclaimToRole
? "kc-claim-value"
: "kc-user-attribute-name"
}
name={
isOIDCclaimToRole ? "config.claim" : "config.user.attribute"
}
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
</>
)}
{isSocialAttributeImporter && (
<>
<FormGroup
label={t("socialProfileJSONFieldPath")}
labelIcon={
<HelpItem
helpText="identity-providers-help:socialProfileJSONFieldPath"
fieldLabelId="identity-providers:socialProfileJSONFieldPath"
/>
}
fieldId="kc-social-profile-JSON-field-path"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={currentMapper?.config.attribute}
id="kc-social-profile-JSON-field-path"
data-testid={"social-profile-JSON-field-path"}
name="config.jsonField"
validated={
errors.config?.role
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
<FormGroup
label={t("mapperUserAttributeName")}
labelIcon={
<HelpItem
helpText="identity-providers-help:socialUserAttributeName"
fieldLabelId="identity-providers:mapperUserAttributeName"
/>
}
fieldId="kc-user-session-attribute-value"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
defaultValue={currentMapper?.config.userAttribute}
data-testid={"user-attribute-name"}
id="kc-user-session-attribute-name"
name="config.userAttribute"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
</>
)}
{(isSAMLAdvancedAttrToRole ||
isHardcodedRole ||
isSAMLAttributeToRole ||
isOIDCAdvancedClaimToRole ||
isOIDCclaimToRole) && (
<FormGroup
label={t("common:role")}
labelIcon={
<HelpItem
helpText="identity-providers-help:role"
fieldLabelId="role"
/>
}
fieldId="kc-role"
validated={
errors.config?.role
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register()}
type="text"
id="kc-role"
data-testid="mapper-role-input"
name="config.role"
isDisabled={!!id}
value={
selectedRole[0]?.clientRole
? `${selectedRole[0].clientId}.${selectedRole[0]?.name}`
: selectedRole[0]?.name
}
validated={
errors.config?.role
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
<Button
data-testid="select-role-button"
onClick={() => toggleModal()}
isDisabled={!!id}
>
{t("selectRole")}
</Button>
</FormGroup>
)}
</>
<ActionGroup> <ActionGroup>
<Button <Button
data-testid="new-mapper-save-button" data-testid="new-mapper-save-button"

View file

@ -11,20 +11,16 @@ import {
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import _ from "lodash";
import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation"; import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation";
import type { IdentityProviderAddMapperParams } from "../routes/AddMapper";
import { useParams } from "react-router-dom";
import type { IdPMapperRepresentationWithAttributes } from "./AddMapper"; import type { IdPMapperRepresentationWithAttributes } from "./AddMapper";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
type AddMapperFormProps = { type AddMapperFormProps = {
mapperTypes?: Record<string, IdentityProviderMapperRepresentation>; mapperTypes: Record<string, IdentityProviderMapperRepresentation>;
mapperType: string; mapperType: string;
id: string; id: string;
updateMapperType: (mapperType: string) => void; updateMapperType: (mapperType: string) => void;
form: UseFormMethods<IdPMapperRepresentationWithAttributes>; form: UseFormMethods<IdPMapperRepresentationWithAttributes>;
formValues: IdPMapperRepresentationWithAttributes;
isSocialIdP: boolean;
}; };
export const AddMapperForm = ({ export const AddMapperForm = ({
@ -33,8 +29,6 @@ export const AddMapperForm = ({
form, form,
id, id,
updateMapperType, updateMapperType,
formValues,
isSocialIdP,
}: AddMapperFormProps) => { }: AddMapperFormProps) => {
const { t } = useTranslation("identity-providers"); const { t } = useTranslation("identity-providers");
@ -44,7 +38,10 @@ export const AddMapperForm = ({
const syncModes = ["inherit", "import", "legacy", "force"]; const syncModes = ["inherit", "import", "legacy", "force"];
const [syncModeOpen, setSyncModeOpen] = useState(false); const [syncModeOpen, setSyncModeOpen] = useState(false);
const { providerId } = useParams<IdentityProviderAddMapperParams>(); const serverInfo = useServerInfo();
const mapper = serverInfo.componentTypes?.[
"org.keycloak.broker.provider.IdentityProviderMapper"
].find((p) => p.id === mapperType);
return ( return (
<> <>
@ -124,15 +121,7 @@ export const AddMapperForm = ({
label={t("mapperType")} label={t("mapperType")}
labelIcon={ labelIcon={
<HelpItem <HelpItem
helpText={ helpText={mapper?.helpText}
formValues.identityProviderMapper ===
"saml-user-attribute-idp-mapper" &&
(providerId === "oidc" ||
providerId === "keycloak-oidc" ||
isSocialIdP)
? `identity-providers-help:oidcAttributeImporter`
: `identity-providers-help:${mapperType}`
}
fieldLabelId="identity-providers:mapperType" fieldLabelId="identity-providers:mapperType"
/> />
} }
@ -140,13 +129,7 @@ export const AddMapperForm = ({
> >
<Controller <Controller
name="identityProviderMapper" name="identityProviderMapper"
defaultValue={ defaultValue={Object.keys(mapperTypes)[0]}
isSocialIdP
? `${providerId.toLowerCase()}-user-attribute-mapper`
: providerId === "saml"
? "saml-advanced-role-idp-mapper"
: "hardcoded-user-session-attribute-idp-mapper"
}
control={control} control={control}
render={({ onChange, value }) => ( render={({ onChange, value }) => (
<Select <Select
@ -154,23 +137,13 @@ export const AddMapperForm = ({
data-testid="idp-mapper-select" data-testid="idp-mapper-select"
isDisabled={!!id} isDisabled={!!id}
required required
direction="down"
onToggle={() => setMapperTypeOpen(!mapperTypeOpen)} onToggle={() => setMapperTypeOpen(!mapperTypeOpen)}
onSelect={(e, value) => { onSelect={(_, value) => {
const theMapper = updateMapperType(value.toString());
mapperTypes && onChange(value.toString());
Object.values(mapperTypes).find(
(item) =>
item.name?.toLowerCase() ===
value.toString().toLowerCase()
);
updateMapperType(_.camelCase(value.toString()));
onChange(theMapper?.id);
setMapperTypeOpen(false); setMapperTypeOpen(false);
}} }}
selections={ selections={
mapperTypes &&
Object.values(mapperTypes).find( Object.values(mapperTypes).find(
(item) => item.id?.toLowerCase() === value (item) => item.id?.toLowerCase() === value
)?.name )?.name
@ -179,17 +152,16 @@ export const AddMapperForm = ({
aria-label={t("syncMode")} aria-label={t("syncMode")}
isOpen={mapperTypeOpen} isOpen={mapperTypeOpen}
> >
{mapperTypes && {Object.values(mapperTypes).map((option) => (
Object.values(mapperTypes).map((option) => ( <SelectOption
<SelectOption selected={option === value}
selected={option === value} datatest-id={option.id}
datatest-id={option.id} key={option.name}
key={option.name} value={option.id}
value={option.name?.toUpperCase()} >
> {option.name}
{t(`mapperTypes.${_.camelCase(option.name)}`)} </SelectOption>
</SelectOption> ))}
))}
</Select> </Select>
)} )}
/> />

View file

@ -157,18 +157,6 @@ export default {
legacy: "Legacy", legacy: "Legacy",
force: "Force", force: "Force",
}, },
mapperTypes: {
advancedAttributeToRole: "Advanced Attribute To Role",
advancedClaimToRole: "Advanced Claim To Role",
externalRoleToRole: "External Role To Role",
claimToRole: "Claim To Role",
usernameTemplateImporter: "Username Template Importer",
hardcodedUserSessionAttribute: "Hardcoded User Session Attribute",
attributeImporter: "Attribute Importer",
hardcodedRole: "Hardcoded Role",
hardcodedAttribute: "Hardcoded Attribute",
samlAttributeToRole: "SAML Attribute To Role",
},
syncModeOverride: "Sync mode override", syncModeOverride: "Sync mode override",
mapperType: "Mapper type", mapperType: "Mapper type",
regexAttributeValues: "Regex Attribute Values", regexAttributeValues: "Regex Attribute Values",

View file

@ -27,8 +27,6 @@ export type AssociatedRolesModalProps = {
toggleDialog: () => void; toggleDialog: () => void;
onConfirm: (newReps: RoleRepresentation[]) => void; onConfirm: (newReps: RoleRepresentation[]) => void;
omitComposites?: boolean; omitComposites?: boolean;
isRadio?: boolean;
isMapperId?: boolean;
}; };
type FilterType = "roles" | "clients"; type FilterType = "roles" | "clients";
@ -38,8 +36,6 @@ export const AssociatedRolesModal = ({
toggleDialog, toggleDialog,
onConfirm, onConfirm,
omitComposites, omitComposites,
isRadio,
isMapperId,
}: AssociatedRolesModalProps) => { }: AssociatedRolesModalProps) => {
const { t } = useTranslation("roles"); const { t } = useTranslation("roles");
const [name, setName] = useState(""); const [name, setName] = useState("");
@ -112,7 +108,7 @@ export const AssociatedRolesModal = ({
useFetch( useFetch(
async () => { async () => {
const [role, compositeRoles] = await Promise.all([ const [role, compositeRoles] = await Promise.all([
!isMapperId ? adminClient.roles.findOneById({ id }) : undefined, adminClient.roles.findOneById({ id }),
!omitComposites ? adminClient.roles.getCompositeRoles({ id }) : [], !omitComposites ? adminClient.roles.getCompositeRoles({ id }) : [],
]); ]);
@ -181,7 +177,6 @@ export const AssociatedRolesModal = ({
loader={filterType === "roles" ? loader : clientRolesLoader} loader={filterType === "roles" ? loader : clientRolesLoader}
ariaLabelKey="roles:roleList" ariaLabelKey="roles:roleList"
searchPlaceholderKey="roles:searchFor" searchPlaceholderKey="roles:searchFor"
isRadio={isRadio}
isPaginated={filterType === "roles"} isPaginated={filterType === "roles"}
isRowDisabled={(r) => compositeRoles.some((o) => o.name === r.name)} isRowDisabled={(r) => compositeRoles.some((o) => o.name === r.name)}
searchTypeComponent={ searchTypeComponent={