aea12169f4
* initial version of the role mapping create form [marvel](https://marvelapp.com/prototype/f0e8fih/screen/72042619) * fixed format * changed to typeahead * format * group by * review fixes * added group and divider * change name to realm name
297 lines
9.2 KiB
TypeScript
297 lines
9.2 KiB
TypeScript
import React, { useContext, useEffect, useState } from "react";
|
|
import { useHistory } from "react-router-dom";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Controller, useForm } from "react-hook-form";
|
|
import {
|
|
Form,
|
|
FormGroup,
|
|
PageSection,
|
|
Select,
|
|
SelectVariant,
|
|
TextInput,
|
|
SelectOption,
|
|
ActionGroup,
|
|
Button,
|
|
SelectGroup,
|
|
Split,
|
|
SplitItem,
|
|
Divider,
|
|
} from "@patternfly/react-core";
|
|
|
|
import { useAlerts } from "../../components/alert/Alerts";
|
|
import { RealmContext } from "../../context/realm-context/RealmContext";
|
|
import { HttpClientContext } from "../../context/http-service/HttpClientContext";
|
|
|
|
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
|
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
|
import {
|
|
ClientRepresentation,
|
|
RoleRepresentation,
|
|
} from "../../realm/models/Realm";
|
|
import { ProtocolMapperRepresentation } from "../models/client-scope";
|
|
|
|
export type RoleMappingFormProps = {
|
|
clientScopeId: string;
|
|
};
|
|
|
|
export const RoleMappingForm = ({ clientScopeId }: RoleMappingFormProps) => {
|
|
const httpClient = useContext(HttpClientContext)!;
|
|
const { realm } = useContext(RealmContext);
|
|
const history = useHistory();
|
|
const { addAlert } = useAlerts();
|
|
|
|
const { t } = useTranslation("client-scopes");
|
|
const { register, handleSubmit, control, errors } = useForm();
|
|
|
|
const [roleOpen, setRoleOpen] = useState(false);
|
|
const [roles, setRoles] = useState<RoleRepresentation[]>([]);
|
|
|
|
const [clientsOpen, setClientsOpen] = useState(false);
|
|
const [clients, setClients] = useState<ClientRepresentation[]>([]);
|
|
const [selectedClient, setSelectedClient] = useState<ClientRepresentation>();
|
|
const [clientRoles, setClientRoles] = useState<RoleRepresentation[]>();
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
const response = await httpClient.doGet<RoleRepresentation[]>(
|
|
`/admin/realms/${realm}/roles`
|
|
);
|
|
setRoles(response.data!);
|
|
const clientResponse = await httpClient.doGet<ClientRepresentation[]>(
|
|
`/admin/realms/${realm}/clients`
|
|
);
|
|
const clients = clientResponse.data!;
|
|
clients.map(
|
|
(client) =>
|
|
(client.toString = function () {
|
|
return this.name;
|
|
})
|
|
);
|
|
setClients(clients);
|
|
})();
|
|
});
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
const client = selectedClient as ClientRepresentation;
|
|
if (client && client.name !== "realmRoles") {
|
|
const response = await httpClient.doGet<RoleRepresentation[]>(
|
|
`/admin/realms/master/clients/${client.id}/roles`
|
|
);
|
|
|
|
setClientRoles(response.data!);
|
|
}
|
|
})();
|
|
}, [selectedClient]);
|
|
|
|
const save = async (mapping: ProtocolMapperRepresentation) => {
|
|
try {
|
|
await httpClient.doPost(
|
|
`/admin/realms/${realm}/client-scopes/${clientScopeId}/protocol-mappers/models`,
|
|
mapping
|
|
);
|
|
addAlert(t("mapperCreateSuccess"));
|
|
} catch (error) {
|
|
addAlert(t("mapperCreateError", error));
|
|
}
|
|
};
|
|
|
|
const createSelectGroup = (clients: ClientRepresentation[]) => {
|
|
return [
|
|
<SelectGroup key="role" label={t("roleGroup")}>
|
|
<SelectOption
|
|
key="realmRoles"
|
|
value={
|
|
{
|
|
name: "realmRoles",
|
|
toString: () => t("realmRoles"),
|
|
} as ClientRepresentation
|
|
}
|
|
>
|
|
{realm}
|
|
</SelectOption>
|
|
</SelectGroup>,
|
|
<Divider key="divider" />,
|
|
<SelectGroup key="group" label={t("clientGroup")}>
|
|
{clients.map((client) => (
|
|
<SelectOption key={client.id} value={client}>
|
|
{client.name}
|
|
</SelectOption>
|
|
))}
|
|
</SelectGroup>,
|
|
];
|
|
};
|
|
|
|
const roleSelectOptions = () => {
|
|
const createItem = (role: RoleRepresentation) => (
|
|
<SelectOption key={role.id} value={role}>
|
|
{role.name}
|
|
</SelectOption>
|
|
);
|
|
if (clientRoles) {
|
|
return clientRoles.map((role) => createItem(role));
|
|
} else {
|
|
return roles.map((role) => createItem(role));
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<ViewHeader
|
|
titleKey="client-scopes:addMapper"
|
|
subKey="client-scopes:addMapperExplain"
|
|
/>
|
|
<PageSection variant="light">
|
|
<Form isHorizontal onSubmit={handleSubmit(save)}>
|
|
<FormGroup
|
|
label={t("protocolMapper")}
|
|
labelIcon={
|
|
<HelpItem
|
|
helpText="client-scopes-help:protocolMapper"
|
|
forLabel={t("protocolMapper")}
|
|
forID="protocolMapper"
|
|
/>
|
|
}
|
|
fieldId="protocolMapper"
|
|
>
|
|
<TextInput
|
|
ref={register()}
|
|
type="text"
|
|
id="protocolMapper"
|
|
name="protocolMapper"
|
|
isReadOnly
|
|
/>
|
|
</FormGroup>
|
|
<FormGroup
|
|
label={t("name")}
|
|
labelIcon={
|
|
<HelpItem
|
|
helpText="client-scopes-help:mapperName"
|
|
forLabel={t("name")}
|
|
forID="name"
|
|
/>
|
|
}
|
|
fieldId="name"
|
|
isRequired
|
|
validated={errors.name ? "error" : "default"}
|
|
helperTextInvalid={t("common:required")}
|
|
>
|
|
<TextInput
|
|
ref={register({ required: true })}
|
|
type="text"
|
|
id="name"
|
|
name="name"
|
|
/>
|
|
</FormGroup>
|
|
<FormGroup
|
|
label={t("role")}
|
|
labelIcon={
|
|
<HelpItem
|
|
helpText="client-scopes-help:role"
|
|
forLabel={t("role")}
|
|
forID="role"
|
|
/>
|
|
}
|
|
validated={errors["config.role"] ? "error" : "default"}
|
|
helperTextInvalid={t("common:required")}
|
|
fieldId="role"
|
|
>
|
|
<Split hasGutter>
|
|
<SplitItem>
|
|
<Select
|
|
toggleId="role"
|
|
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}
|
|
onClear={() => setSelectedClient(undefined)}
|
|
onSelect={(_, value) => {
|
|
if (value) {
|
|
setSelectedClient(value as ClientRepresentation);
|
|
setClientsOpen(false);
|
|
}
|
|
}}
|
|
>
|
|
{createSelectGroup(clients)}
|
|
</Select>
|
|
</SplitItem>
|
|
<SplitItem>
|
|
<Controller
|
|
name="config.role"
|
|
defaultValue=""
|
|
control={control}
|
|
rules={{ required: true }}
|
|
render={({ onChange, value }) => (
|
|
<Select
|
|
onToggle={() => setRoleOpen(!roleOpen)}
|
|
isOpen={roleOpen}
|
|
variant={SelectVariant.typeahead}
|
|
placeholderText={
|
|
selectedClient && selectedClient.name !== "realmRoles"
|
|
? t("clientRoles")
|
|
: t("selectARole")
|
|
}
|
|
isDisabled={!selectedClient}
|
|
typeAheadAriaLabel={t("selectARole")}
|
|
selections={value.name}
|
|
onSelect={(_, value) => {
|
|
onChange(value);
|
|
setRoleOpen(false);
|
|
}}
|
|
onClear={() => onChange("")}
|
|
>
|
|
{roleSelectOptions()}
|
|
</Select>
|
|
)}
|
|
/>
|
|
</SplitItem>
|
|
</Split>
|
|
</FormGroup>
|
|
<FormGroup
|
|
label={t("newRoleName")}
|
|
labelIcon={
|
|
<HelpItem
|
|
helpText="client-scopes-help:newRoleName"
|
|
forLabel={t("newRoleName")}
|
|
forID="newRoleName"
|
|
/>
|
|
}
|
|
fieldId="newRoleName"
|
|
>
|
|
<TextInput
|
|
ref={register()}
|
|
type="text"
|
|
id="newRoleName"
|
|
name="config.new_role_name"
|
|
/>
|
|
</FormGroup>
|
|
<ActionGroup>
|
|
<Button variant="primary" type="submit">
|
|
{t("common:save")}
|
|
</Button>
|
|
<Button variant="link" onClick={() => history.push("..")}>
|
|
{t("common:cancel")}
|
|
</Button>
|
|
</ActionGroup>
|
|
</Form>
|
|
</PageSection>
|
|
</>
|
|
);
|
|
};
|