Introduced a predefined mapper dialog (#169)
* added optional dialog variant * added predefined scope dialog * added mapper dialog for predefined and custom * format * changed to use dataList instead of table * fixed test
This commit is contained in:
parent
49284a0f11
commit
a9dc031fff
8 changed files with 19464 additions and 11 deletions
167
src/client-scopes/add/MapperDialog.tsx
Normal file
167
src/client-scopes/add/MapperDialog.tsx
Normal file
|
@ -0,0 +1,167 @@
|
|||
import React, { ReactElement, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DataList,
|
||||
DataListCell,
|
||||
DataListItem,
|
||||
DataListItemCells,
|
||||
DataListItemRow,
|
||||
Modal,
|
||||
Text,
|
||||
TextContent,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableHeader,
|
||||
TableVariant,
|
||||
} from "@patternfly/react-table";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
||||
import {
|
||||
ProtocolMapperRepresentation,
|
||||
ProtocolMapperTypeRepresentation,
|
||||
} from "../../context/server-info/server-info";
|
||||
|
||||
export type AddMapperDialogProps = {
|
||||
protocol: string;
|
||||
buildIn: boolean;
|
||||
onConfirm: (
|
||||
value: ProtocolMapperTypeRepresentation | ProtocolMapperRepresentation[]
|
||||
) => {};
|
||||
};
|
||||
|
||||
type AddMapperDialogModalProps = AddMapperDialogProps & {
|
||||
open: boolean;
|
||||
toggleDialog: () => void;
|
||||
};
|
||||
|
||||
export const useAddMapperDialog = (
|
||||
props: AddMapperDialogProps
|
||||
): [() => void, () => ReactElement] => {
|
||||
const [show, setShow] = useState(false);
|
||||
|
||||
function toggleDialog() {
|
||||
setShow((show) => !show);
|
||||
}
|
||||
|
||||
const Dialog = () => (
|
||||
<AddMapperDialog {...props} open={show} toggleDialog={toggleDialog} />
|
||||
);
|
||||
return [toggleDialog, Dialog];
|
||||
};
|
||||
|
||||
export const AddMapperDialog = ({
|
||||
protocol,
|
||||
buildIn,
|
||||
open,
|
||||
toggleDialog,
|
||||
onConfirm,
|
||||
}: AddMapperDialogModalProps) => {
|
||||
const serverInfo = useServerInfo();
|
||||
const protocolMappers = serverInfo.protocolMapperTypes[protocol];
|
||||
const buildInMappers = serverInfo.builtinProtocolMappers[protocol];
|
||||
const { t } = useTranslation("client-scopes");
|
||||
const [rows, setRows] = useState(
|
||||
buildInMappers.map((mapper) => {
|
||||
const mapperType = protocolMappers.filter(
|
||||
(type) => type.id === mapper.protocolMapper
|
||||
)[0];
|
||||
return {
|
||||
item: mapper,
|
||||
selected: false,
|
||||
cells: [mapper.name, mapperType.helpText],
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t("chooseAMapperType")}
|
||||
isOpen={open}
|
||||
onClose={toggleDialog}
|
||||
actions={
|
||||
buildIn
|
||||
? [
|
||||
<Button
|
||||
id="modal-confirm"
|
||||
key="confirm"
|
||||
onClick={() => {
|
||||
onConfirm(
|
||||
rows.filter((row) => row.selected).map((row) => row.item)
|
||||
);
|
||||
toggleDialog();
|
||||
}}
|
||||
>
|
||||
{t("common:add")}
|
||||
</Button>,
|
||||
<Button
|
||||
id="modal-cancel"
|
||||
key="cancel"
|
||||
variant={ButtonVariant.secondary}
|
||||
onClick={() => {
|
||||
toggleDialog();
|
||||
}}
|
||||
>
|
||||
{t("common:cancel")}
|
||||
</Button>,
|
||||
]
|
||||
: []
|
||||
}
|
||||
>
|
||||
<TextContent>
|
||||
<Text>{t("predefinedMappingDescription")}</Text>
|
||||
</TextContent>
|
||||
{!buildIn && (
|
||||
<DataList
|
||||
onSelectDataListItem={(id) => {
|
||||
const mapper = protocolMappers.find((mapper) => mapper.id === id);
|
||||
onConfirm(mapper!);
|
||||
toggleDialog();
|
||||
}}
|
||||
aria-label={t("chooseAMapperType")}
|
||||
isCompact
|
||||
>
|
||||
{protocolMappers.map((mapper) => (
|
||||
<DataListItem
|
||||
aria-labelledby={mapper.name}
|
||||
key={mapper.id}
|
||||
id={mapper.id}
|
||||
>
|
||||
<DataListItemRow>
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key={`name-${mapper.id}`}>
|
||||
<>{mapper.name}</>
|
||||
</DataListCell>,
|
||||
<DataListCell key={`helpText-${mapper.id}`}>
|
||||
<>{mapper.helpText}</>
|
||||
</DataListCell>,
|
||||
]}
|
||||
/>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
))}
|
||||
</DataList>
|
||||
)}
|
||||
{buildIn && (
|
||||
<Table
|
||||
variant={TableVariant.compact}
|
||||
cells={[t("name"), t("description")]}
|
||||
onSelect={(_, isSelected, rowIndex) => {
|
||||
rows[rowIndex].selected = isSelected;
|
||||
setRows([...rows]);
|
||||
}}
|
||||
canSelectAll={false}
|
||||
rows={rows}
|
||||
aria-label={t("chooseAMapperType")}
|
||||
>
|
||||
<TableHeader />
|
||||
<TableBody />
|
||||
</Table>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
75
src/client-scopes/add/__tests__/MapperDialog.test.tsx
Normal file
75
src/client-scopes/add/__tests__/MapperDialog.test.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
import React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { Button } from "@patternfly/react-core";
|
||||
|
||||
import serverInfo from "../../../context/server-info/__tests__/mock.json";
|
||||
import { ServerInfoContext } from "../../../context/server-info/ServerInfoProvider";
|
||||
import { AddMapperDialogProps, useAddMapperDialog } from "../MapperDialog";
|
||||
|
||||
describe("<MapperDialog/>", () => {
|
||||
const Test = (args: AddMapperDialogProps) => {
|
||||
const [toggle, Dialog] = useAddMapperDialog(args);
|
||||
return (
|
||||
<ServerInfoContext.Provider value={serverInfo}>
|
||||
<Dialog />
|
||||
<Button id="open" onClick={toggle}>
|
||||
Show
|
||||
</Button>
|
||||
</ServerInfoContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
it("should return empty array when selecting nothing", () => {
|
||||
const onConfirm = jest.fn();
|
||||
const container = mount(
|
||||
<Test buildIn={true} protocol="openid-connect" onConfirm={onConfirm} />
|
||||
);
|
||||
|
||||
container.find("button#open").simulate("click");
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
container.find("button#modal-confirm").simulate("click");
|
||||
expect(onConfirm).toBeCalledWith([]);
|
||||
});
|
||||
|
||||
it("should return array with selected build in protocol mapping", () => {
|
||||
const onConfirm = jest.fn();
|
||||
const protocol = "openid-connect";
|
||||
const container = mount(
|
||||
<Test buildIn={true} protocol={protocol} onConfirm={onConfirm} />
|
||||
);
|
||||
|
||||
container.find("button#open").simulate("click");
|
||||
container
|
||||
.find("input[name='checkrow0']")
|
||||
.simulate("change", { target: { value: true } });
|
||||
container
|
||||
.find("input[name='checkrow1']")
|
||||
.simulate("change", { target: { value: true } });
|
||||
|
||||
container.find("button#modal-confirm").simulate("click");
|
||||
expect(onConfirm).toBeCalledWith([
|
||||
serverInfo.builtinProtocolMappers[protocol][0],
|
||||
serverInfo.builtinProtocolMappers[protocol][1],
|
||||
]);
|
||||
});
|
||||
|
||||
it("should return selected protocol mapping type on click", () => {
|
||||
const onConfirm = jest.fn();
|
||||
const protocol = "openid-connect";
|
||||
const container = mount(
|
||||
<Test buildIn={false} protocol={protocol} onConfirm={onConfirm} />
|
||||
);
|
||||
|
||||
container.find("button#open").simulate("click");
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
container
|
||||
.find("div.pf-c-data-list__item-content")
|
||||
.first()
|
||||
.simulate("click");
|
||||
expect(onConfirm).toBeCalledWith(
|
||||
serverInfo.protocolMapperTypes[protocol][0]
|
||||
);
|
||||
});
|
||||
});
|
19167
src/client-scopes/add/__tests__/__snapshots__/MapperDialog.test.tsx.snap
Normal file
19167
src/client-scopes/add/__tests__/__snapshots__/MapperDialog.test.tsx.snap
Normal file
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,9 @@
|
|||
"mappingDeletedError": "Could not delete mapping: '{{error}}'",
|
||||
"displayOnConsentScreen": "Display on consent screen",
|
||||
"consentScreenText": "Consent screen text",
|
||||
"guiOrder": "Display Order"
|
||||
"guiOrder": "Display Order",
|
||||
"chooseAMapperType": "Choose a mapper type",
|
||||
"predefinedMappingDescription": "Choose one of the predefined mappings from this table",
|
||||
"mappingTable": "Table with predefined mapping"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"fullName": "{{givenName}} {{familyName}}",
|
||||
"unknownUser": "Anonymous",
|
||||
|
||||
"add": "Add",
|
||||
"create": "Create",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
|
|
|
@ -38,6 +38,7 @@ export type ConfirmDialogProps = {
|
|||
cancelButtonLabel?: string;
|
||||
continueButtonLabel?: string;
|
||||
continueButtonVariant?: ButtonVariant;
|
||||
variant?: ModalVariant;
|
||||
onConfirm: () => void;
|
||||
onCancel?: () => void;
|
||||
children?: ReactNode;
|
||||
|
@ -53,6 +54,7 @@ export const ConfirmDialogModal = ({
|
|||
onCancel,
|
||||
children,
|
||||
open = true,
|
||||
variant = ModalVariant.default,
|
||||
toggleDialog,
|
||||
}: ConfirmDialogModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -61,7 +63,7 @@ export const ConfirmDialogModal = ({
|
|||
title={t(titleKey)}
|
||||
isOpen={open}
|
||||
onClose={toggleDialog}
|
||||
variant={ModalVariant.small}
|
||||
variant={variant}
|
||||
actions={[
|
||||
<Button
|
||||
id="modal-confirm"
|
||||
|
|
|
@ -48,7 +48,7 @@ exports[`Confirmation dialog renders simple confirm dialog 1`] = `
|
|||
ouiaSafe={true}
|
||||
showClose={true}
|
||||
title="Delete app02?"
|
||||
variant="small"
|
||||
variant="default"
|
||||
>
|
||||
<Portal
|
||||
containerInfo={
|
||||
|
@ -63,8 +63,8 @@ exports[`Confirmation dialog renders simple confirm dialog 1`] = `
|
|||
aria-describedby="pf-modal-part-3"
|
||||
aria-labelledby="pf-modal-part-2"
|
||||
aria-modal="true"
|
||||
class="pf-c-modal-box pf-m-sm"
|
||||
data-ouia-component-id="OUIA-Generated-Modal-small-2"
|
||||
class="pf-c-modal-box"
|
||||
data-ouia-component-id="OUIA-Generated-Modal-default-2"
|
||||
data-ouia-component-type="PF4/ModalContent"
|
||||
data-ouia-safe="true"
|
||||
id="pf-modal-part-1"
|
||||
|
@ -170,11 +170,11 @@ exports[`Confirmation dialog renders simple confirm dialog 1`] = `
|
|||
isOpen={true}
|
||||
labelId="pf-modal-part-2"
|
||||
onClose={[Function]}
|
||||
ouiaId="OUIA-Generated-Modal-small-2"
|
||||
ouiaId="OUIA-Generated-Modal-default-2"
|
||||
ouiaSafe={true}
|
||||
showClose={true}
|
||||
title="Delete app02?"
|
||||
variant="small"
|
||||
variant="default"
|
||||
>
|
||||
<Backdrop>
|
||||
<div
|
||||
|
@ -198,20 +198,20 @@ exports[`Confirmation dialog renders simple confirm dialog 1`] = `
|
|||
aria-label=""
|
||||
aria-labelledby="pf-modal-part-2"
|
||||
className=""
|
||||
data-ouia-component-id="OUIA-Generated-Modal-small-2"
|
||||
data-ouia-component-id="OUIA-Generated-Modal-default-2"
|
||||
data-ouia-component-type="PF4/ModalContent"
|
||||
data-ouia-safe={true}
|
||||
id="pf-modal-part-1"
|
||||
style={Object {}}
|
||||
variant="small"
|
||||
variant="default"
|
||||
>
|
||||
<div
|
||||
aria-describedby="pf-modal-part-3"
|
||||
aria-label={null}
|
||||
aria-labelledby="pf-modal-part-2"
|
||||
aria-modal="true"
|
||||
className="pf-c-modal-box pf-m-sm"
|
||||
data-ouia-component-id="OUIA-Generated-Modal-small-2"
|
||||
className="pf-c-modal-box"
|
||||
data-ouia-component-id="OUIA-Generated-Modal-default-2"
|
||||
data-ouia-component-type="PF4/ModalContent"
|
||||
data-ouia-safe={true}
|
||||
id="pf-modal-part-1"
|
||||
|
|
38
src/stories/AddMapperDialog.stories.tsx
Normal file
38
src/stories/AddMapperDialog.stories.tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
import React from "react";
|
||||
import { Button } from "@patternfly/react-core";
|
||||
import { Meta, Story } from "@storybook/react";
|
||||
|
||||
import serverInfo from "../context/server-info/__tests__/mock.json";
|
||||
import { ServerInfoContext } from "../context/server-info/ServerInfoProvider";
|
||||
import {
|
||||
AddMapperDialog,
|
||||
AddMapperDialogProps,
|
||||
useAddMapperDialog,
|
||||
} from "../client-scopes/add/MapperDialog";
|
||||
|
||||
export default {
|
||||
title: "Add mapper dialog",
|
||||
component: AddMapperDialog,
|
||||
} as Meta;
|
||||
|
||||
const Template: Story<AddMapperDialogProps> = (args) => {
|
||||
const [toggle, Dialog] = useAddMapperDialog(args);
|
||||
return (
|
||||
<ServerInfoContext.Provider value={serverInfo}>
|
||||
<Dialog />
|
||||
<Button onClick={toggle}>Show</Button>
|
||||
</ServerInfoContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const BuildInDialog = Template.bind({});
|
||||
BuildInDialog.args = {
|
||||
protocol: "openid-connect",
|
||||
buildIn: true,
|
||||
};
|
||||
|
||||
export const ProtocolMapperDialog = Template.bind({});
|
||||
ProtocolMapperDialog.args = {
|
||||
protocol: "openid-connect",
|
||||
buildIn: false,
|
||||
};
|
Loading…
Reference in a new issue