hooked up the build in mapper dialog (#197)
* hooked up the build in mapper dialog * spelling * useEffect for setTimout * fix state * fix bug with alerts clearing checked items * fixed tests * Update src/client-scopes/messages.json Co-authored-by: Stan Silvert <ssilvert@redhat.com> * simplified dialog usage Co-authored-by: Stan Silvert <ssilvert@redhat.com>
This commit is contained in:
parent
7ebe695921
commit
d6e1161c83
9 changed files with 13814 additions and 13741 deletions
|
@ -1,4 +1,4 @@
|
||||||
import React, { ReactElement, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonVariant,
|
ButtonVariant,
|
||||||
|
@ -8,6 +8,7 @@ import {
|
||||||
DataListItemCells,
|
DataListItemCells,
|
||||||
DataListItemRow,
|
DataListItemRow,
|
||||||
Modal,
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
Text,
|
Text,
|
||||||
TextContent,
|
TextContent,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
|
@ -24,75 +25,67 @@ import {
|
||||||
ProtocolMapperRepresentation,
|
ProtocolMapperRepresentation,
|
||||||
ProtocolMapperTypeRepresentation,
|
ProtocolMapperTypeRepresentation,
|
||||||
} from "../../context/server-info/server-info";
|
} from "../../context/server-info/server-info";
|
||||||
|
import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState";
|
||||||
|
|
||||||
export type AddMapperDialogProps = {
|
export type AddMapperDialogModalProps = {
|
||||||
protocol: string;
|
protocol: string;
|
||||||
buildIn: boolean;
|
filter?: ProtocolMapperRepresentation[];
|
||||||
onConfirm: (
|
onConfirm: (
|
||||||
value: ProtocolMapperTypeRepresentation | ProtocolMapperRepresentation[]
|
value: ProtocolMapperTypeRepresentation | ProtocolMapperRepresentation[]
|
||||||
) => {};
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type AddMapperDialogModalProps = AddMapperDialogProps & {
|
export type AddMapperDialogProps = AddMapperDialogModalProps & {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
toggleDialog: () => void;
|
toggleDialog: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAddMapperDialog = (
|
export const AddMapperDialog = (props: AddMapperDialogProps) => {
|
||||||
props: AddMapperDialogProps
|
const { t } = useTranslation("client-scopes");
|
||||||
): [() => void, () => ReactElement] => {
|
|
||||||
const [show, setShow] = useState(false);
|
|
||||||
|
|
||||||
function toggleDialog() {
|
const serverInfo = useServerInfo();
|
||||||
setShow((show) => !show);
|
const protocol = props.protocol;
|
||||||
|
const protocolMappers = serverInfo.protocolMapperTypes[protocol];
|
||||||
|
const builtInMappers = serverInfo.builtinProtocolMappers[protocol];
|
||||||
|
const [filter, setFilter] = useState<ProtocolMapperRepresentation[]>([]);
|
||||||
|
|
||||||
|
const allRows = builtInMappers.map((mapper) => {
|
||||||
|
const mapperType = protocolMappers.filter(
|
||||||
|
(type) => type.id === mapper.protocolMapper
|
||||||
|
)[0];
|
||||||
|
return {
|
||||||
|
item: mapper,
|
||||||
|
selected: false,
|
||||||
|
cells: [mapper.name, mapperType.helpText],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const [rows, setRows] = useState(allRows);
|
||||||
|
|
||||||
|
if (props.filter && props.filter.length !== filter.length) {
|
||||||
|
setFilter(props.filter);
|
||||||
|
const nameFilter = props.filter.map((f) => f.name);
|
||||||
|
setRows([...allRows.filter((row) => !nameFilter.includes(row.item.name))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Dialog = () => (
|
const isBuiltIn = !!props.filter;
|
||||||
<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 (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
variant={ModalVariant.medium}
|
||||||
title={t("chooseAMapperType")}
|
title={t("chooseAMapperType")}
|
||||||
isOpen={open}
|
isOpen={props.open}
|
||||||
onClose={toggleDialog}
|
|
||||||
actions={
|
actions={
|
||||||
buildIn
|
isBuiltIn
|
||||||
? [
|
? [
|
||||||
<Button
|
<Button
|
||||||
id="modal-confirm"
|
id="modal-confirm"
|
||||||
key="confirm"
|
key="confirm"
|
||||||
|
isDisabled={rows.length === 0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onConfirm(
|
props.onConfirm(
|
||||||
rows.filter((row) => row.selected).map((row) => row.item)
|
rows.filter((row) => row.selected).map((row) => row.item)
|
||||||
);
|
);
|
||||||
toggleDialog();
|
props.toggleDialog();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("common:add")}
|
{t("common:add")}
|
||||||
|
@ -102,7 +95,7 @@ export const AddMapperDialog = ({
|
||||||
key="cancel"
|
key="cancel"
|
||||||
variant={ButtonVariant.secondary}
|
variant={ButtonVariant.secondary}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
toggleDialog();
|
props.toggleDialog();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("common:cancel")}
|
{t("common:cancel")}
|
||||||
|
@ -114,12 +107,12 @@ export const AddMapperDialog = ({
|
||||||
<TextContent>
|
<TextContent>
|
||||||
<Text>{t("predefinedMappingDescription")}</Text>
|
<Text>{t("predefinedMappingDescription")}</Text>
|
||||||
</TextContent>
|
</TextContent>
|
||||||
{!buildIn && (
|
{!isBuiltIn && (
|
||||||
<DataList
|
<DataList
|
||||||
onSelectDataListItem={(id) => {
|
onSelectDataListItem={(id) => {
|
||||||
const mapper = protocolMappers.find((mapper) => mapper.id === id);
|
const mapper = protocolMappers.find((mapper) => mapper.id === id);
|
||||||
onConfirm(mapper!);
|
props.onConfirm(mapper!);
|
||||||
toggleDialog();
|
props.toggleDialog();
|
||||||
}}
|
}}
|
||||||
aria-label={t("chooseAMapperType")}
|
aria-label={t("chooseAMapperType")}
|
||||||
isCompact
|
isCompact
|
||||||
|
@ -146,7 +139,7 @@ export const AddMapperDialog = ({
|
||||||
))}
|
))}
|
||||||
</DataList>
|
</DataList>
|
||||||
)}
|
)}
|
||||||
{buildIn && (
|
{isBuiltIn && rows.length > 0 && (
|
||||||
<Table
|
<Table
|
||||||
variant={TableVariant.compact}
|
variant={TableVariant.compact}
|
||||||
cells={[t("name"), t("description")]}
|
cells={[t("name"), t("description")]}
|
||||||
|
@ -162,6 +155,12 @@ export const AddMapperDialog = ({
|
||||||
<TableBody />
|
<TableBody />
|
||||||
</Table>
|
</Table>
|
||||||
)}
|
)}
|
||||||
|
{isBuiltIn && rows.length === 0 && (
|
||||||
|
<ListEmptyState
|
||||||
|
message={t("emptyMappers")}
|
||||||
|
instructions={t("emptyBuiltInMappersInstructions")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { mount } from "enzyme";
|
import { mount } from "enzyme";
|
||||||
import { Button } from "@patternfly/react-core";
|
import { Button } from "@patternfly/react-core";
|
||||||
|
|
||||||
import serverInfo from "../../../context/server-info/__tests__/mock.json";
|
import serverInfo from "../../../context/server-info/__tests__/mock.json";
|
||||||
import { ServerInfoContext } from "../../../context/server-info/ServerInfoProvider";
|
import { ServerInfoContext } from "../../../context/server-info/ServerInfoProvider";
|
||||||
import { AddMapperDialogProps, useAddMapperDialog } from "../MapperDialog";
|
import { AddMapperDialogModalProps, AddMapperDialog } from "../MapperDialog";
|
||||||
|
|
||||||
describe("<MapperDialog/>", () => {
|
describe("<MapperDialog/>", () => {
|
||||||
const Test = (args: AddMapperDialogProps) => {
|
const Test = (args: AddMapperDialogModalProps) => {
|
||||||
const [toggle, Dialog] = useAddMapperDialog(args);
|
const [open, setOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<ServerInfoContext.Provider value={serverInfo}>
|
<ServerInfoContext.Provider value={serverInfo}>
|
||||||
<Dialog />
|
<AddMapperDialog
|
||||||
<Button id="open" onClick={toggle}>
|
{...args}
|
||||||
|
open={open}
|
||||||
|
toggleDialog={() => setOpen(!open)}
|
||||||
|
/>
|
||||||
|
<Button id="open" onClick={() => setOpen(true)}>
|
||||||
Show
|
Show
|
||||||
</Button>
|
</Button>
|
||||||
</ServerInfoContext.Provider>
|
</ServerInfoContext.Provider>
|
||||||
|
@ -22,7 +26,7 @@ describe("<MapperDialog/>", () => {
|
||||||
it("should return empty array when selecting nothing", () => {
|
it("should return empty array when selecting nothing", () => {
|
||||||
const onConfirm = jest.fn();
|
const onConfirm = jest.fn();
|
||||||
const container = mount(
|
const container = mount(
|
||||||
<Test buildIn={true} protocol="openid-connect" onConfirm={onConfirm} />
|
<Test filter={[]} protocol="openid-connect" onConfirm={onConfirm} />
|
||||||
);
|
);
|
||||||
|
|
||||||
container.find("button#open").simulate("click");
|
container.find("button#open").simulate("click");
|
||||||
|
@ -36,7 +40,7 @@ describe("<MapperDialog/>", () => {
|
||||||
const onConfirm = jest.fn();
|
const onConfirm = jest.fn();
|
||||||
const protocol = "openid-connect";
|
const protocol = "openid-connect";
|
||||||
const container = mount(
|
const container = mount(
|
||||||
<Test buildIn={true} protocol={protocol} onConfirm={onConfirm} />
|
<Test filter={[]} protocol={protocol} onConfirm={onConfirm} />
|
||||||
);
|
);
|
||||||
|
|
||||||
container.find("button#open").simulate("click");
|
container.find("button#open").simulate("click");
|
||||||
|
@ -57,9 +61,7 @@ describe("<MapperDialog/>", () => {
|
||||||
it("should return selected protocol mapping type on click", () => {
|
it("should return selected protocol mapping type on click", () => {
|
||||||
const onConfirm = jest.fn();
|
const onConfirm = jest.fn();
|
||||||
const protocol = "openid-connect";
|
const protocol = "openid-connect";
|
||||||
const container = mount(
|
const container = mount(<Test protocol={protocol} onConfirm={onConfirm} />);
|
||||||
<Test buildIn={false} protocol={protocol} onConfirm={onConfirm} />
|
|
||||||
);
|
|
||||||
|
|
||||||
container.find("button#open").simulate("click");
|
container.find("button#open").simulate("click");
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
AlertVariant,
|
AlertVariant,
|
||||||
ButtonVariant,
|
ButtonVariant,
|
||||||
|
@ -16,6 +17,11 @@ import {
|
||||||
import { CaretDownIcon } from "@patternfly/react-icons";
|
import { CaretDownIcon } from "@patternfly/react-icons";
|
||||||
|
|
||||||
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
||||||
|
import {
|
||||||
|
ProtocolMapperRepresentation as ServerInfoProtocolMapper,
|
||||||
|
ProtocolMapperTypeRepresentation,
|
||||||
|
} from "../../context/server-info/server-info";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ClientScopeRepresentation,
|
ClientScopeRepresentation,
|
||||||
ProtocolMapperRepresentation,
|
ProtocolMapperRepresentation,
|
||||||
|
@ -25,10 +31,11 @@ import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState
|
||||||
import { HttpClientContext } from "../../context/http-service/HttpClientContext";
|
import { HttpClientContext } from "../../context/http-service/HttpClientContext";
|
||||||
import { RealmContext } from "../../context/realm-context/RealmContext";
|
import { RealmContext } from "../../context/realm-context/RealmContext";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
import { Link } from "react-router-dom";
|
import { AddMapperDialog } from "../add/MapperDialog";
|
||||||
|
|
||||||
type MapperListProps = {
|
type MapperListProps = {
|
||||||
clientScope: ClientScopeRepresentation;
|
clientScope: ClientScopeRepresentation;
|
||||||
|
refresh: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Row = {
|
type Row = {
|
||||||
|
@ -38,7 +45,7 @@ type Row = {
|
||||||
priority: number;
|
priority: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MapperList = ({ clientScope }: MapperListProps) => {
|
export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
|
||||||
const { t } = useTranslation("client-scopes");
|
const { t } = useTranslation("client-scopes");
|
||||||
const httpClient = useContext(HttpClientContext)!;
|
const httpClient = useContext(HttpClientContext)!;
|
||||||
const { realm } = useContext(RealmContext);
|
const { realm } = useContext(RealmContext);
|
||||||
|
@ -53,21 +60,48 @@ export const MapperList = ({ clientScope }: MapperListProps) => {
|
||||||
clientScope.protocol!
|
clientScope.protocol!
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const [builtInDialogOpen, setBuiltInDialogOpen] = useState(false);
|
||||||
|
const toggleBuiltInMapperDialog = () =>
|
||||||
|
setBuiltInDialogOpen(!builtInDialogOpen);
|
||||||
|
const addMappers = async (
|
||||||
|
mappers: ProtocolMapperTypeRepresentation | ProtocolMapperRepresentation[]
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
await httpClient.doPost(
|
||||||
|
`/admin/realms/${realm}/client-scopes/${clientScope.id}/protocol-mappers/add-models`,
|
||||||
|
mappers
|
||||||
|
);
|
||||||
|
refresh();
|
||||||
|
addAlert(t("mappingCreatedSuccess"), AlertVariant.success);
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(t("mappingCreatedError", { error }), AlertVariant.danger);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!mapperList) {
|
if (!mapperList) {
|
||||||
return (
|
return (
|
||||||
<ListEmptyState
|
<>
|
||||||
message={t("emptyMappers")}
|
<AddMapperDialog
|
||||||
instructions={t("emptyMappersInstructions")}
|
protocol={clientScope.protocol!}
|
||||||
primaryActionText={t("emptyPrimaryAction")}
|
filter={(mapperList as ServerInfoProtocolMapper[]) || []}
|
||||||
onPrimaryAction={() => {}}
|
onConfirm={addMappers}
|
||||||
secondaryActions={[
|
open={builtInDialogOpen}
|
||||||
{
|
toggleDialog={toggleBuiltInMapperDialog}
|
||||||
text: t("emptySecondaryAction"),
|
/>
|
||||||
onClick: () => {},
|
<ListEmptyState
|
||||||
type: ButtonVariant.secondary,
|
message={t("emptyMappers")}
|
||||||
},
|
instructions={t("emptyMappersInstructions")}
|
||||||
]}
|
primaryActionText={t("emptyPrimaryAction")}
|
||||||
/>
|
onPrimaryAction={toggleBuiltInMapperDialog}
|
||||||
|
secondaryActions={[
|
||||||
|
{
|
||||||
|
text: t("emptySecondaryAction"),
|
||||||
|
onClick: () => {},
|
||||||
|
type: ButtonVariant.secondary,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +156,7 @@ export const MapperList = ({ clientScope }: MapperListProps) => {
|
||||||
}
|
}
|
||||||
isOpen={mapperAction}
|
isOpen={mapperAction}
|
||||||
dropdownItems={[
|
dropdownItems={[
|
||||||
<DropdownItem key="predefined">
|
<DropdownItem key="predefined" onClick={toggleBuiltInMapperDialog}>
|
||||||
{t("fromPredefinedMapper")}
|
{t("fromPredefinedMapper")}
|
||||||
</DropdownItem>,
|
</DropdownItem>,
|
||||||
<DropdownItem key="byConfiguration">
|
<DropdownItem key="byConfiguration">
|
||||||
|
@ -132,6 +166,13 @@ export const MapperList = ({ clientScope }: MapperListProps) => {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<AddMapperDialog
|
||||||
|
protocol={clientScope.protocol!}
|
||||||
|
filter={(mapperList as ServerInfoProtocolMapper[]) || []}
|
||||||
|
onConfirm={addMappers}
|
||||||
|
open={builtInDialogOpen}
|
||||||
|
toggleDialog={toggleBuiltInMapperDialog}
|
||||||
|
/>
|
||||||
<Table
|
<Table
|
||||||
variant={TableVariant.compact}
|
variant={TableVariant.compact}
|
||||||
cells={[t("name"), t("category"), t("type"), t("priority")]}
|
cells={[t("name"), t("category"), t("type"), t("priority")]}
|
||||||
|
@ -147,6 +188,7 @@ export const MapperList = ({ clientScope }: MapperListProps) => {
|
||||||
await httpClient.doDelete(
|
await httpClient.doDelete(
|
||||||
`/admin/realms/${realm}/client-scopes/${clientScope.id}/protocol-mappers/models/${data[rowId].mapper.id}`
|
`/admin/realms/${realm}/client-scopes/${clientScope.id}/protocol-mappers/models/${data[rowId].mapper.id}`
|
||||||
);
|
);
|
||||||
|
refresh();
|
||||||
addAlert(t("mappingDeletedSuccess"), AlertVariant.success);
|
addAlert(t("mappingDeletedSuccess"), AlertVariant.success);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addAlert(
|
addAlert(
|
||||||
|
|
|
@ -46,24 +46,26 @@ export const ClientScopeForm = () => {
|
||||||
const [open, isOpen] = useState(false);
|
const [open, isOpen] = useState(false);
|
||||||
const { addAlert } = useAlerts();
|
const { addAlert } = useAlerts();
|
||||||
|
|
||||||
useEffect(() => {
|
const load = async () => {
|
||||||
(async () => {
|
if (id) {
|
||||||
if (id) {
|
const response = await httpClient.doGet<ClientScopeRepresentation>(
|
||||||
const response = await httpClient.doGet<ClientScopeRepresentation>(
|
`/admin/realms/${realm}/client-scopes/${id}`
|
||||||
`/admin/realms/${realm}/client-scopes/${id}`
|
);
|
||||||
);
|
if (response.data) {
|
||||||
if (response.data) {
|
Object.entries(response.data).map((entry) => {
|
||||||
Object.entries(response.data).map((entry) => {
|
if (entry[0] === "attributes") {
|
||||||
if (entry[0] === "attributes") {
|
convertToFormValues(entry[1], "attributes", setValue);
|
||||||
convertToFormValues(entry[1], "attributes", setValue);
|
}
|
||||||
}
|
setValue(entry[0], entry[1]);
|
||||||
setValue(entry[0], entry[1]);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setClientScope(response.data);
|
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
setClientScope(response.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
load();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const save = async (clientScopes: ClientScopeRepresentation) => {
|
const save = async (clientScopes: ClientScopeRepresentation) => {
|
||||||
|
@ -297,7 +299,9 @@ export const ClientScopeForm = () => {
|
||||||
</Form>
|
</Form>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab eventKey={1} title={<TabTitleText>{t("mappers")}</TabTitleText>}>
|
<Tab eventKey={1} title={<TabTitleText>{t("mappers")}</TabTitleText>}>
|
||||||
{clientScope && <MapperList clientScope={clientScope} />}
|
{clientScope && (
|
||||||
|
<MapperList clientScope={clientScope} refresh={load} />
|
||||||
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
"protocol": "Protocol",
|
"protocol": "Protocol",
|
||||||
"includeInTokenScope": "Include in token scope",
|
"includeInTokenScope": "Include in token scope",
|
||||||
"mappingDetails": "Mapper details",
|
"mappingDetails": "Mapper details",
|
||||||
|
"mappingCreatedSuccess": "Mapping successfully created",
|
||||||
|
"mappingCreatedError": "Could not create mapping: '{{error}}'",
|
||||||
"deleteMappingTitle": "Delete mapping?",
|
"deleteMappingTitle": "Delete mapping?",
|
||||||
"deleteMappingConfirm": "Are you sure you want to delete this mapping?",
|
"deleteMappingConfirm": "Are you sure you want to delete this mapping?",
|
||||||
"mappingUpdatedSuccess": "Mapping successfully updated",
|
"mappingUpdatedSuccess": "Mapping successfully updated",
|
||||||
|
@ -49,6 +51,7 @@
|
||||||
"byConfiguration": "By configuration",
|
"byConfiguration": "By configuration",
|
||||||
"emptyMappers": "No mappers",
|
"emptyMappers": "No mappers",
|
||||||
"emptyMappersInstructions": "If you want to add mappers, please click the button below to add some predefined mappers or to configure a new mapper.",
|
"emptyMappersInstructions": "If you want to add mappers, please click the button below to add some predefined mappers or to configure a new mapper.",
|
||||||
|
"emptyBuiltInMappersInstructions": "All built in mappers were added to this client",
|
||||||
"emptyPrimaryAction": "Add predefined mapper",
|
"emptyPrimaryAction": "Add predefined mapper",
|
||||||
"emptySecondaryAction": "Configure a new mapper",
|
"emptySecondaryAction": "Configure a new mapper",
|
||||||
"mappingDeletedSuccess": "Mapping successfully deleted",
|
"mappingDeletedSuccess": "Mapping successfully deleted",
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import React, { useState, createContext, ReactNode, useContext } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
createContext,
|
||||||
|
ReactNode,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
} from "react";
|
||||||
import { AlertType, AlertPanel } from "./AlertPanel";
|
import { AlertType, AlertPanel } from "./AlertPanel";
|
||||||
import { AlertVariant } from "@patternfly/react-core";
|
import { AlertVariant } from "@patternfly/react-core";
|
||||||
|
|
||||||
|
@ -12,21 +18,39 @@ export const AlertContext = createContext<AlertProps>({
|
||||||
|
|
||||||
export const useAlerts = () => useContext(AlertContext);
|
export const useAlerts = () => useContext(AlertContext);
|
||||||
|
|
||||||
|
type TimeOut = {
|
||||||
|
key: number;
|
||||||
|
timeOut: NodeJS.Timeout;
|
||||||
|
};
|
||||||
|
|
||||||
export const AlertProvider = ({ children }: { children: ReactNode }) => {
|
export const AlertProvider = ({ children }: { children: ReactNode }) => {
|
||||||
const [alerts, setAlerts] = useState<AlertType[]>([]);
|
const [alerts, setAlerts] = useState<AlertType[]>([]);
|
||||||
|
const [timers, setTimers] = useState<TimeOut[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timersKeys = timers.map((timer) => timer.key);
|
||||||
|
const timeOuts = alerts
|
||||||
|
.filter((alert) => !timersKeys.includes(alert.key))
|
||||||
|
.map((alert) => {
|
||||||
|
const timeOut = setTimeout(() => hideAlert(alert.key), 8000);
|
||||||
|
return { key: alert.key, timeOut };
|
||||||
|
});
|
||||||
|
setTimers([...timers, ...timeOuts]);
|
||||||
|
return () => timers.forEach((timer) => clearTimeout(timer.timeOut));
|
||||||
|
}, [alerts]);
|
||||||
|
|
||||||
const createId = () => new Date().getTime();
|
const createId = () => new Date().getTime();
|
||||||
|
|
||||||
const hideAlert = (key: number) => {
|
const hideAlert = (key: number) => {
|
||||||
setAlerts((alerts) => [...alerts.filter((el) => el.key !== key)]);
|
setAlerts((alerts) => [...alerts.filter((el) => el.key !== key)]);
|
||||||
|
setTimers((timers) => [...timers.filter((timer) => timer.key === key)]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const addAlert = (
|
const addAlert = (
|
||||||
message: string,
|
message: string,
|
||||||
variant: AlertVariant = AlertVariant.default
|
variant: AlertVariant = AlertVariant.default
|
||||||
) => {
|
) => {
|
||||||
const key = createId();
|
setAlerts([...alerts, { key: createId(), message, variant }]);
|
||||||
setAlerts([...alerts, { key, message, variant }]);
|
|
||||||
setTimeout(() => hideAlert(key), 8000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { Button } from "@patternfly/react-core";
|
import { Button } from "@patternfly/react-core";
|
||||||
import { Meta, Story } from "@storybook/react";
|
import { Meta, Story } from "@storybook/react";
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import { ServerInfoContext } from "../context/server-info/ServerInfoProvider";
|
||||||
import {
|
import {
|
||||||
AddMapperDialog,
|
AddMapperDialog,
|
||||||
AddMapperDialogProps,
|
AddMapperDialogProps,
|
||||||
useAddMapperDialog,
|
|
||||||
} from "../client-scopes/add/MapperDialog";
|
} from "../client-scopes/add/MapperDialog";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -16,11 +15,15 @@ export default {
|
||||||
} as Meta;
|
} as Meta;
|
||||||
|
|
||||||
const Template: Story<AddMapperDialogProps> = (args) => {
|
const Template: Story<AddMapperDialogProps> = (args) => {
|
||||||
const [toggle, Dialog] = useAddMapperDialog(args);
|
const [open, setOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<ServerInfoContext.Provider value={serverInfo}>
|
<ServerInfoContext.Provider value={serverInfo}>
|
||||||
<Dialog />
|
<AddMapperDialog
|
||||||
<Button onClick={toggle}>Show</Button>
|
{...args}
|
||||||
|
open={open}
|
||||||
|
toggleDialog={() => setOpen(!open)}
|
||||||
|
/>
|
||||||
|
<Button onClick={() => setOpen(true)}>Show</Button>
|
||||||
</ServerInfoContext.Provider>
|
</ServerInfoContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -28,11 +31,10 @@ const Template: Story<AddMapperDialogProps> = (args) => {
|
||||||
export const BuildInDialog = Template.bind({});
|
export const BuildInDialog = Template.bind({});
|
||||||
BuildInDialog.args = {
|
BuildInDialog.args = {
|
||||||
protocol: "openid-connect",
|
protocol: "openid-connect",
|
||||||
buildIn: true,
|
filter: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProtocolMapperDialog = Template.bind({});
|
export const ProtocolMapperDialog = Template.bind({});
|
||||||
ProtocolMapperDialog.args = {
|
ProtocolMapperDialog.args = {
|
||||||
protocol: "openid-connect",
|
protocol: "openid-connect",
|
||||||
buildIn: false,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,6 @@ export default {
|
||||||
|
|
||||||
export const MapperListExample = () => (
|
export const MapperListExample = () => (
|
||||||
<ServerInfoContext.Provider value={serverInfo}>
|
<ServerInfoContext.Provider value={serverInfo}>
|
||||||
<MapperList clientScope={clientScopeMock} />
|
<MapperList clientScope={clientScopeMock} refresh={() => {}} />
|
||||||
</ServerInfoContext.Provider>
|
</ServerInfoContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue