Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Introduced a predefined mapper dialog #169

Merged
merged 6 commits into from Oct 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
167 changes: 167 additions & 0 deletions src/client-scopes/add/MapperDialog.tsx
@@ -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 changes: 75 additions & 0 deletions src/client-scopes/add/__tests__/MapperDialog.test.tsx
@@ -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]
);
});
});