added by configuration dialog into the flow (#221)

* updated the detail screen to support new mapping

* fix merge error

* added by configuration dialog
This commit is contained in:
Erik Jan de Wit 2020-11-17 22:28:34 +01:00 committed by GitHub
parent 8e33519df1
commit ba761c0526
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 65 deletions

View file

@ -1,6 +1,6 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { Link, useHistory } from "react-router-dom";
import {
AlertVariant,
ButtonVariant,
@ -43,6 +43,7 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
const { t } = useTranslation("client-scopes");
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const history = useHistory();
const [filteredData, setFilteredData] = useState<
{ mapper: ProtocolMapperRepresentation; cells: Row }[]
@ -53,21 +54,34 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
clientScope.protocol!
];
const [builtInDialogOpen, setBuiltInDialogOpen] = useState(false);
const toggleBuiltInMapperDialog = () =>
setBuiltInDialogOpen(!builtInDialogOpen);
const [addMapperDialogOpen, setAddMapperDialogOpen] = useState(false);
const [filter, setFilter] = useState(clientScope.protocolMappers);
const toggleAddMapperDialog = (buildIn: boolean) => {
if (buildIn) {
setFilter(mapperList);
} else {
setFilter(undefined);
}
setAddMapperDialogOpen(!addMapperDialogOpen);
};
const addMappers = async (
mappers: ProtocolMapperTypeRepresentation | ProtocolMapperRepresentation[]
) => {
try {
await adminClient.clientScopes.addMultipleProtocolMappers(
{ id: clientScope.id! },
mappers as ProtocolMapperRepresentation[]
);
refresh();
addAlert(t("mappingCreatedSuccess"), AlertVariant.success);
} catch (error) {
addAlert(t("mappingCreatedError", { error }), AlertVariant.danger);
): Promise<void> => {
if (filter === undefined) {
const mapper = mappers as ProtocolMapperTypeRepresentation;
history.push(`/client-scopes/${clientScope.id}/${mapper.id}`);
} else {
try {
await adminClient.clientScopes.addMultipleProtocolMappers(
{ id: clientScope.id! },
mappers as ProtocolMapperRepresentation[]
);
refresh();
addAlert(t("mappingCreatedSuccess"), AlertVariant.success);
} catch (error) {
addAlert(t("mappingCreatedError", { error }), AlertVariant.danger);
}
}
};
@ -76,20 +90,20 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
<>
<AddMapperDialog
protocol={clientScope.protocol!}
filter={mapperList || []}
filter={filter}
onConfirm={addMappers}
open={builtInDialogOpen}
toggleDialog={toggleBuiltInMapperDialog}
open={addMapperDialogOpen}
toggleDialog={() => setAddMapperDialogOpen(!addMapperDialogOpen)}
/>
<ListEmptyState
message={t("emptyMappers")}
instructions={t("emptyMappersInstructions")}
primaryActionText={t("emptyPrimaryAction")}
onPrimaryAction={toggleBuiltInMapperDialog}
onPrimaryAction={() => toggleAddMapperDialog(true)}
secondaryActions={[
{
text: t("emptySecondaryAction"),
onClick: () => {},
onClick: () => toggleAddMapperDialog(false),
type: ButtonVariant.secondary,
},
]}
@ -149,10 +163,16 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
}
isOpen={mapperAction}
dropdownItems={[
<DropdownItem key="predefined" onClick={toggleBuiltInMapperDialog}>
<DropdownItem
key="predefined"
onClick={() => toggleAddMapperDialog(true)}
>
{t("fromPredefinedMapper")}
</DropdownItem>,
<DropdownItem key="byConfiguration">
<DropdownItem
key="byConfiguration"
onClick={() => toggleAddMapperDialog(false)}
>
{t("byConfiguration")}
</DropdownItem>,
]}
@ -161,10 +181,10 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
>
<AddMapperDialog
protocol={clientScope.protocol!}
filter={mapperList || []}
filter={filter}
onConfirm={addMappers}
open={builtInDialogOpen}
toggleDialog={toggleBuiltInMapperDialog}
open={addMapperDialogOpen}
toggleDialog={() => setAddMapperDialogOpen(!addMapperDialogOpen)}
/>
<Table
variant={TableVariant.compact}

View file

@ -18,6 +18,7 @@ import {
SelectVariant,
Switch,
TextInput,
ValidatedOptions,
} from "@patternfly/react-core";
import { ConfigPropertyRepresentation } from "keycloak-admin/lib/defs/configPropertyRepresentation";
@ -31,43 +32,54 @@ import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { convertFormValuesToObject, convertToFormValues } from "../../util";
type Params = {
scopeId: string;
id: string;
};
export const MappingDetails = () => {
const { t } = useTranslation("client-scopes");
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const { scopeId, id } = useParams<{ scopeId: string; id: string }>();
const { register, setValue, control, handleSubmit } = useForm();
const { scopeId, id } = useParams<Params>();
const { register, errors, setValue, control, handleSubmit } = useForm();
const [mapping, setMapping] = useState<ProtocolMapperRepresentation>();
const [typeOpen, setTypeOpen] = useState(false);
const [configProperties, setConfigProperties] = useState<
ConfigPropertyRepresentation[]
>();
const serverInfo = useServerInfo();
const history = useHistory();
const serverInfo = useServerInfo();
const isGuid = /^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$/;
useEffect(() => {
(async () => {
const data = await adminClient.clientScopes.findProtocolMapper({
id: scopeId,
mapperId: id,
});
if (data) {
Object.entries(data).map((entry) => {
if (entry[0] === "config") {
convertToFormValues(entry[1], "config", setValue);
}
setValue(entry[0], entry[1]);
if (id.match(isGuid)) {
(async () => {
const data = await adminClient.clientScopes.findProtocolMapper({
id: scopeId,
mapperId: id,
});
}
setMapping(data);
const mapperTypes = serverInfo.protocolMapperTypes![data!.protocol!];
const properties = mapperTypes.find(
(type) => type.id === data.protocolMapper
)?.properties!;
setConfigProperties(properties);
})();
if (data) {
Object.entries(data).map((entry) => {
convertToFormValues(entry[1], "config", setValue);
});
}
const mapperTypes = serverInfo.protocolMapperTypes![data!.protocol!];
const properties = mapperTypes.find(
(type) => type.id === data!.protocolMapper
)?.properties!;
setConfigProperties(properties);
setMapping(data);
})();
} else {
(async () => {
const scope = await adminClient.clientScopes.findOne({ id: scopeId });
setMapping({ protocol: scope.protocol, protocolMapper: id });
})();
}
}, []);
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
@ -91,15 +103,20 @@ export const MappingDetails = () => {
const save = async (formMapping: ProtocolMapperRepresentation) => {
const config = convertFormValuesToObject(formMapping.config);
const map = { ...mapping, config };
const map = { ...mapping, ...formMapping, config };
const key = id.match(isGuid) ? "Updated" : "Created";
try {
await adminClient.clientScopes.updateProtocolMapper(
{ id: scopeId, mapperId: id },
map
);
addAlert(t("mappingUpdatedSuccess"), AlertVariant.success);
if (id.match(isGuid)) {
await adminClient.clientScopes.updateProtocolMapper(
{ id: scopeId, mapperId: id },
map
);
} else {
await adminClient.clientScopes.addProtocolMapper({ id: scopeId }, map);
}
addAlert(t(`mapping${key}Success`), AlertVariant.success);
} catch (error) {
addAlert(t("mappingUpdatedError", { error }), AlertVariant.danger);
addAlert(t(`mapping${key}Error`, { error }), AlertVariant.danger);
}
};
@ -107,21 +124,55 @@ export const MappingDetails = () => {
<>
<DeleteConfirm />
<ViewHeader
titleKey={mapping ? mapping.name! : ""}
subKey={id}
titleKey={mapping ? mapping.name! : t("addMapper")}
subKey={id.match(isGuid) ? id : ""}
badge={mapping?.protocol}
dropdownItems={[
<DropdownItem
key="delete"
value="delete"
onClick={toggleDeleteDialog}
>
{t("common:delete")}
</DropdownItem>,
]}
dropdownItems={
id.match(isGuid)
? [
<DropdownItem
key="delete"
value="delete"
onClick={toggleDeleteDialog}
>
{t("common:delete")}
</DropdownItem>,
]
: undefined
}
/>
<PageSection variant="light">
<Form isHorizontal onSubmit={handleSubmit(save)}>
{!id.match(isGuid) && (
<FormGroup
label={t("name")}
labelIcon={
<HelpItem
helpText="client-scopes-help:mapperName"
forLabel={t("name")}
forID="name"
/>
}
fieldId="name"
isRequired
validated={
errors.name ? ValidatedOptions.error : ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={register({ required: true })}
type="text"
id="name"
name="name"
validated={
errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</FormGroup>
)}
<FormGroup
label={t("realmRolePrefix")}
labelIcon={

View file

@ -19,6 +19,8 @@
"deleteMappingConfirm": "Are you sure you want to delete this mapping?",
"mappingUpdatedSuccess": "Mapping successfully updated",
"mappingUpdatedError": "Could not update mapping: '{{error}}'",
"mappingCreatedSuccess": "Mapping successfully created",
"mappingCreatedError": "Could not create mapping: '{{error}}'",
"realmRolePrefix": "Realm role prefix",
"multiValued": "Multivalued",
"tokenClaimName": "Token claim name",

View file

@ -8,7 +8,7 @@ import { routes } from "../../route-config";
export const PageBreadCrumbs = () => {
const { t } = useTranslation();
const crumbs = useBreadcrumbs(routes(t)).slice(1);
const crumbs = useBreadcrumbs(routes(t), { excludePaths: ["/"] });
return (
<>
{crumbs.length > 1 && (