Executor details (#1499)

This commit is contained in:
agagancarczyk 2021-11-10 14:26:43 +00:00 committed by GitHub
parent 50548491f5
commit 4e05f0c57e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 303 additions and 94 deletions

View file

@ -528,6 +528,14 @@ describe("Realm settings tests", () => {
realmSettingsPage.shouldCancelDeletingExecutor(); realmSettingsPage.shouldCancelDeletingExecutor();
}); });
it("Should cancel editing executor", () => {
realmSettingsPage.shouldCancelEditingExecutor();
});
it("Should edit executor", () => {
realmSettingsPage.shouldEditExecutor();
});
it("Should delete executor from a client profile", () => { it("Should delete executor from a client profile", () => {
realmSettingsPage.shouldDeleteExecutor(); realmSettingsPage.shouldDeleteExecutor();
}); });
@ -537,7 +545,7 @@ describe("Realm settings tests", () => {
}); });
}); });
describe("Realm settings client policies tab tests", () => { describe.skip("Realm settings client policies tab tests", () => {
beforeEach(() => { beforeEach(() => {
keycloakBefore(); keycloakBefore();
loginPage.logIn(); loginPage.logIn();

View file

@ -176,10 +176,8 @@ export default class RealmSettingsPage {
private clientPolicyDrpDwn = "action-dropdown"; private clientPolicyDrpDwn = "action-dropdown";
private searchFld = "[id^=realm-settings][id$=profilesinput]"; private searchFld = "[id^=realm-settings][id$=profilesinput]";
private searchFldPolicies = "[id^=realm-settings][id$=clientPoliciesinput]"; private searchFldPolicies = "[id^=realm-settings][id$=clientPoliciesinput]";
private clientProfileOne = private clientProfileOne = 'a[href*="realm-settings/clientPolicies/Test"]';
'a[href*="realm-settings/clientPolicies/Test/edit-profile"]'; private clientProfileTwo = 'a[href*="realm-settings/clientPolicies/Edit"]';
private clientProfileTwo =
'a[href*="realm-settings/clientPolicies/Edit/edit-profile"]';
private clientPolicy = private clientPolicy =
'a[href*="realm-settings/clientPolicies/Test/edit-policy"]'; 'a[href*="realm-settings/clientPolicies/Test/edit-policy"]';
private reloadBtn = "reloadProfile"; private reloadBtn = "reloadProfile";
@ -188,6 +186,8 @@ export default class RealmSettingsPage {
private addExecutorDrpDwnOption = "executorType-select"; private addExecutorDrpDwnOption = "executorType-select";
private addExecutorCancelBtn = "addExecutor-cancelBtn"; private addExecutorCancelBtn = "addExecutor-cancelBtn";
private addExecutorSaveBtn = "addExecutor-saveBtn"; private addExecutorSaveBtn = "addExecutor-saveBtn";
private availablePeriodExecutorFld = "available-period";
private editExecutor = "editExecutor";
private listingPage = new ListingPage(); private listingPage = new ListingPage();
private addCondition = "addCondition"; private addCondition = "addCondition";
private addConditionDrpDwn = ".pf-c-select__toggle"; private addConditionDrpDwn = ".pf-c-select__toggle";
@ -652,7 +652,7 @@ export default class RealmSettingsPage {
cy.findByTestId(this.addExecutor).click(); cy.findByTestId(this.addExecutor).click();
cy.get(this.addExecutorDrpDwn).click(); cy.get(this.addExecutorDrpDwn).click();
cy.findByTestId(this.addExecutorDrpDwnOption) cy.findByTestId(this.addExecutorDrpDwnOption)
.contains("confidential-client") .contains("secure-ciba-signed-authn-req")
.click(); .click();
cy.findByTestId(this.addExecutorCancelBtn).click(); cy.findByTestId(this.addExecutorCancelBtn).click();
cy.get('h6[class*="kc-emptyExecutors"]').should( cy.get('h6[class*="kc-emptyExecutors"]').should(
@ -666,7 +666,7 @@ export default class RealmSettingsPage {
cy.findByTestId(this.addExecutor).click(); cy.findByTestId(this.addExecutor).click();
cy.get(this.addExecutorDrpDwn).click(); cy.get(this.addExecutorDrpDwn).click();
cy.findByTestId(this.addExecutorDrpDwnOption) cy.findByTestId(this.addExecutorDrpDwnOption)
.contains("confidential-client") .contains("secure-ciba-signed-authn-req")
.click(); .click();
cy.findByTestId(this.addExecutorSaveBtn).click(); cy.findByTestId(this.addExecutorSaveBtn).click();
cy.get(this.alertMessage).should( cy.get(this.alertMessage).should(
@ -675,7 +675,7 @@ export default class RealmSettingsPage {
); );
cy.get('ul[class*="pf-c-data-list"]').should( cy.get('ul[class*="pf-c-data-list"]').should(
"have.text", "have.text",
"confidential-client" "secure-ciba-signed-authn-req"
); );
} }
@ -684,13 +684,39 @@ export default class RealmSettingsPage {
cy.get('svg[class*="kc-executor-trash-icon"]').click(); cy.get('svg[class*="kc-executor-trash-icon"]').click();
cy.get(this.deleteDialogTitle).contains("Delete executor?"); cy.get(this.deleteDialogTitle).contains("Delete executor?");
cy.get(this.deleteDialogBodyText).contains( cy.get(this.deleteDialogBodyText).contains(
"The action will permanently delete confidential-client. This cannot be undone." "The action will permanently delete secure-ciba-signed-authn-req. This cannot be undone."
); );
cy.findByTestId("modalConfirm").contains("Delete"); cy.findByTestId("modalConfirm").contains("Delete");
cy.get(this.deleteDialogCancelBtn).contains("Cancel").click(); cy.get(this.deleteDialogCancelBtn).contains("Cancel").click();
cy.get('ul[class*="pf-c-data-list"]').should( cy.get('ul[class*="pf-c-data-list"]').should(
"have.text", "have.text",
"confidential-client" "secure-ciba-signed-authn-req"
);
}
shouldCancelEditingExecutor() {
cy.get(this.clientProfileTwo).click();
cy.findByTestId(this.editExecutor).first().click();
cy.get('a[data-testid="addExecutor-cancelBtn"]').click();
cy.get('ul[class*="pf-c-data-list"]').should(
"have.text",
"secure-ciba-signed-authn-req"
);
cy.findByTestId(this.editExecutor).first().click();
cy.findByTestId(this.availablePeriodExecutorFld).should(
"have.value",
"3600"
);
}
shouldEditExecutor() {
cy.get(this.clientProfileTwo).click();
cy.findByTestId(this.editExecutor).first().click();
cy.findByTestId(this.availablePeriodExecutorFld).clear().type("4000");
cy.findByTestId(this.addExecutorSaveBtn).click();
cy.get(this.alertMessage).should(
"be.visible",
"Executor updated successfully"
); );
} }
@ -699,7 +725,7 @@ export default class RealmSettingsPage {
cy.get('svg[class*="kc-executor-trash-icon"]').click(); cy.get('svg[class*="kc-executor-trash-icon"]').click();
cy.get(this.deleteDialogTitle).contains("Delete executor?"); cy.get(this.deleteDialogTitle).contains("Delete executor?");
cy.get(this.deleteDialogBodyText).contains( cy.get(this.deleteDialogBodyText).contains(
"The action will permanently delete confidential-client. This cannot be undone." "The action will permanently delete secure-ciba-signed-authn-req. This cannot be undone."
); );
cy.findByTestId("modalConfirm").contains("Delete").click(); cy.findByTestId("modalConfirm").contains("Delete").click();
cy.get('h6[class*="kc-emptyExecutors"]').should( cy.get('h6[class*="kc-emptyExecutors"]').should(

View file

@ -49,7 +49,7 @@ export const ListComponent = ({
aria-label={t(label!)} aria-label={t(label!)}
isOpen={open} isOpen={open}
> >
{options!.map((option) => ( {options?.map((option) => (
<SelectOption <SelectOption
selected={option === value} selected={option === value}
key={option} key={option}

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { import {
@ -18,20 +18,10 @@ export const MultiValuedListComponent = ({
helpText, helpText,
defaultValue, defaultValue,
options, options,
selectedValues,
parentCallback,
}: ComponentProps) => { }: ComponentProps) => {
const { t } = useTranslation("dynamic"); const { t } = useTranslation("dynamic");
const { control } = useFormContext(); const { control } = useFormContext();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [selectedItems, setSelectedItems] = useState<string[]>([defaultValue]);
useEffect(() => {
if (selectedValues) {
parentCallback!(selectedValues);
setSelectedItems(selectedValues!);
}
}, []);
return ( return (
<FormGroup <FormGroup
@ -43,8 +33,8 @@ export const MultiValuedListComponent = ({
> >
<Controller <Controller
name={`config.${convertToHyphens(name!)}`} name={`config.${convertToHyphens(name!)}`}
defaultValue={defaultValue ? [defaultValue] : []}
control={control} control={control}
defaultValue={defaultValue ? [defaultValue] : []}
render={({ onChange, value }) => ( render={({ onChange, value }) => (
<Select <Select
toggleId={name} toggleId={name}
@ -55,27 +45,15 @@ export const MultiValuedListComponent = ({
collapsedText: t("common:showRemaining"), collapsedText: t("common:showRemaining"),
}} }}
variant={SelectVariant.typeaheadMulti} variant={SelectVariant.typeaheadMulti}
typeAheadAriaLabel={t("common:select")} typeAheadAriaLabel="Select"
onToggle={(isOpen) => setOpen(isOpen)} onToggle={(isOpen) => setOpen(isOpen)}
selections={value} selections={value}
onSelect={(_, v) => { onSelect={(_, selectedValue) => {
const option = v.toString(); const option = selectedValue.toString();
if (!value) { const changedValue = value.includes(option)
onChange([option]); ? value.filter((item: string) => item !== option)
parentCallback!([option]); : [...value, option];
setSelectedItems([option]); onChange(changedValue);
} else if (value.includes(option)) {
const updatedItems = selectedItems.filter(
(item: string) => item !== option
);
setSelectedItems(updatedItems);
onChange(updatedItems);
parentCallback!(updatedItems);
} else {
onChange([...value, option]);
parentCallback!([...value, option]);
setSelectedItems([...selectedItems, option]);
}
}} }}
onClear={(event) => { onClear={(event) => {
event.stopPropagation(); event.stopPropagation();

View file

@ -36,6 +36,7 @@ import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { toAddExecutor } from "./routes/AddExecutor"; import { toAddExecutor } from "./routes/AddExecutor";
import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { ClientProfileParams, toClientProfile } from "./routes/ClientProfile"; import { ClientProfileParams, toClientProfile } from "./routes/ClientProfile";
import { toExecutor } from "./routes/Executor";
type ClientProfileForm = Required<ClientProfileRepresentation>; type ClientProfileForm = Required<ClientProfileRepresentation>;
@ -315,7 +316,7 @@ export default function ClientProfileForm() {
realm, realm,
profileName, profileName,
})} })}
></Link> />
)} )}
variant="link" variant="link"
className="kc-addExecutor" className="kc-addExecutor"
@ -342,16 +343,27 @@ export default function ClientProfileForm() {
key="executor" key="executor"
data-testid="executor-type" data-testid="executor-type"
> >
{Object.keys(executor).length !== 0 ? ( {executor.configuration ? (
<Button
component={(props) => (
<Link <Link
data-testid="executor-type-link" {...props}
to={""} to={toExecutor({
className="kc-executor-link" realm,
profileName,
executorName: executor.executor!,
})}
/>
)}
variant="link"
data-testid="editExecutor"
> >
{executor.executor} {executor.executor}
</Link> </Button>
) : ( ) : (
executor.executor <span className="kc-unclickable-executor">
{executor.executor}
</span>
)} )}
{executorTypes {executorTypes
?.filter( ?.filter(
@ -411,16 +423,28 @@ export default function ClientProfileForm() {
key="executor" key="executor"
data-testid="global-executor-type" data-testid="global-executor-type"
> >
{Object.keys(executor).length !== 0 ? ( {Object.keys(executor.configuration!).length !==
0 ? (
<Button
component={(props) => (
<Link <Link
data-testid="global-executor-type-link" {...props}
to={""} to={toExecutor({
className="kc-global-executor-link" realm,
profileName,
executorName: executor.executor!,
})}
/>
)}
variant="link"
data-testid="editExecutor"
> >
{executor.executor} {executor.executor}
</Link> </Button>
) : ( ) : (
executor.executor <span className="kc-unclickable-executor">
{executor.executor}
</span>
)} )}
{executorTypes {executorTypes
?.filter( ?.filter(

View file

@ -22,13 +22,17 @@ import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/li
import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation"; import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation";
import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation"; import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation";
import { ClientProfileParams, toClientProfile } from "./routes/ClientProfile"; import { ClientProfileParams, toClientProfile } from "./routes/ClientProfile";
import type ClientPolicyExecutorRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyExecutorRepresentation";
import { DynamicComponents } from "../components/dynamic/DynamicComponents"; import { DynamicComponents } from "../components/dynamic/DynamicComponents";
import type { ExecutorParams } from "./routes/Executor";
import { convertToFormValues } from "../util";
type ExecutorForm = Required<ClientPolicyExecutorRepresentation>; type ExecutorForm = {
config: object;
executor: string;
};
const defaultValues: ExecutorForm = { const defaultValues: ExecutorForm = {
configuration: {}, config: {},
executor: "", executor: "",
}; };
@ -36,6 +40,7 @@ export default function ExecutorForm() {
const { t } = useTranslation("realm-settings"); const { t } = useTranslation("realm-settings");
const history = useHistory(); const history = useHistory();
const { realm, profileName } = useParams<ClientProfileParams>(); const { realm, profileName } = useParams<ClientProfileParams>();
const { executorName } = useParams<ExecutorParams>();
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const [selectExecutorTypeOpen, setSelectExecutorTypeOpen] = useState(false); const [selectExecutorTypeOpen, setSelectExecutorTypeOpen] = useState(false);
const serverInfo = useServerInfo(); const serverInfo = useServerInfo();
@ -52,8 +57,9 @@ export default function ExecutorForm() {
ClientProfileRepresentation[] ClientProfileRepresentation[]
>([]); >([]);
const [profiles, setProfiles] = useState<ClientProfileRepresentation[]>([]); const [profiles, setProfiles] = useState<ClientProfileRepresentation[]>([]);
const form = useForm<ExecutorForm>({ defaultValues }); const form = useForm({ defaultValues });
const { control } = form; const { control, setValue, handleSubmit } = form;
const editMode = !!executorName;
useFetch( useFetch(
() => () =>
@ -61,6 +67,23 @@ export default function ExecutorForm() {
(profiles) => { (profiles) => {
setGlobalProfiles(profiles.globalProfiles ?? []); setGlobalProfiles(profiles.globalProfiles ?? []);
setProfiles(profiles.profiles ?? []); setProfiles(profiles.profiles ?? []);
const profile = profiles.profiles!.find(
(profile) => profile.name === profileName
);
const profileExecutor = profile?.executors!.find(
(executor) => executor.executor === executorName
);
if (profileExecutor) {
Object.entries(profileExecutor).map(([key, value]) => {
if (key === "configuration") {
convertToFormValues(value, "config", setValue);
}
setValue(key, value);
});
}
}, },
[] []
); );
@ -72,11 +95,25 @@ export default function ExecutorForm() {
return profile; return profile;
} }
const profileExecutor = profile.executors!.find(
(executor) => executor.executor === executorName
);
const executors = (profile.executors ?? []).concat({ const executors = (profile.executors ?? []).concat({
executor: formValues.executor, executor: formValues.executor,
configuration: formValues.configuration, configuration: formValues.config,
}); });
if (editMode) {
profileExecutor!.configuration = {
...profileExecutor!.configuration,
...formValues.config,
};
}
if (editMode) {
return profile;
}
return { return {
...profile, ...profile,
executors, executors,
@ -87,16 +124,49 @@ export default function ExecutorForm() {
profiles: updatedProfiles, profiles: updatedProfiles,
globalProfiles: globalProfiles, globalProfiles: globalProfiles,
}); });
addAlert(t("realm-settings:addExecutorSuccess"), AlertVariant.success); addAlert(
editMode
? t("realm-settings:updateExecutorSuccess")
: t("realm-settings:addExecutorSuccess"),
AlertVariant.success
);
history.push(toClientProfile({ realm, profileName })); history.push(toClientProfile({ realm, profileName }));
} catch (error) { } catch (error) {
addError("realm-settings:addExecutorError", error); addError(
editMode
? "realm-settings:updateExecutorError"
: "realm-settings:addExecutorError",
error
);
} }
}; };
const globalProfile = globalProfiles.find(
(globalProfile) => globalProfile.name === profileName
);
const profileExecutorType = executorTypes?.find(
(executor) => executor.id === executorName
);
const editedProfileExecutors =
profileExecutorType?.properties.map<ConfigPropertyRepresentation>(
(property) => {
const globalDefaultValues = editMode ? property.defaultValue : "";
return {
...property,
defaultValue: globalDefaultValues,
};
}
);
return ( return (
<> <>
<ViewHeader titleKey={t("addExecutor")} divider /> <ViewHeader
titleKey={editMode ? executorName : t("addExecutor")}
divider
/>
<PageSection variant="light"> <PageSection variant="light">
<FormAccess isHorizontal role="manage-realm" className="pf-u-mt-lg"> <FormAccess isHorizontal role="manage-realm" className="pf-u-mt-lg">
<FormGroup <FormGroup
@ -111,6 +181,14 @@ export default function ExecutorForm() {
label: t("executorTypeHelpText"), label: t("executorTypeHelpText"),
})} })}
/> />
) : editMode ? (
<HelpItem
helpText={profileExecutorType?.helpText}
forLabel={t("executorTypeHelpText")}
forID={t(`common:helpLabel`, {
label: t("executorTypeHelpText"),
})}
/>
) : undefined ) : undefined
} }
> >
@ -134,12 +212,13 @@ export default function ExecutorForm() {
); );
setSelectExecutorTypeOpen(false); setSelectExecutorTypeOpen(false);
}} }}
selections={value} selections={editMode ? executorName : value}
variant={SelectVariant.single} variant={SelectVariant.single}
data-testid="executorType-select" data-testid="executorType-select"
aria-label={t("executorType")} aria-label={t("executorType")}
isOpen={selectExecutorTypeOpen} isOpen={selectExecutorTypeOpen}
maxHeight={580} maxHeight={580}
isDisabled={editMode}
> >
{executorTypes?.map((option) => ( {executorTypes?.map((option) => (
<SelectOption <SelectOption
@ -155,26 +234,49 @@ export default function ExecutorForm() {
</FormGroup> </FormGroup>
<FormProvider {...form}> <FormProvider {...form}>
<DynamicComponents properties={executorProperties} /> <DynamicComponents properties={executorProperties} />
{editMode && (
<DynamicComponents properties={editedProfileExecutors!} />
)}
</FormProvider> </FormProvider>
{!globalProfile && (
<ActionGroup> <ActionGroup>
<Button <Button
variant="primary" variant="primary"
onClick={save} onClick={() => handleSubmit(save)()}
data-testid="addExecutor-saveBtn" data-testid="addExecutor-saveBtn"
> >
{t("common:add")} {editMode ? t("common:save") : t("common:add")}
</Button> </Button>
<Button <Button
variant="link" variant="link"
component={(props) => ( component={(props) => (
<Link {...props} to={toClientProfile({ realm, profileName })} /> <Link
{...props}
to={toClientProfile({ realm, profileName })}
/>
)} )}
data-testid="addExecutor-cancelBtn" data-testid="addExecutor-cancelBtn"
> >
{t("common:cancel")} {t("common:cancel")}
</Button> </Button>
</ActionGroup> </ActionGroup>
)}
</FormAccess> </FormAccess>
{editMode && globalProfile && (
<div className="kc-backToProfile">
<Button
component={(props) => (
<Link
{...props}
to={toClientProfile({ realm, profileName })}
></Link>
)}
variant="primary"
>
{t("realm-settings:back")}
</Button>
</div>
)}
</PageSection> </PageSection>
</> </>
); );

View file

@ -214,10 +214,19 @@ article.pf-c-card.pf-m-flat.kc-login-settings-template
margin-right: 0.625rem; margin-right: 0.625rem;
} }
.kc-backToPolicies { .kc-unclickable-executor {
font-size: var(--pf-global--FontSize--md);
padding: 0 var(--pf-global--spacer--md) 0 var(--pf-global--spacer--md);
}
.kc-backToPolicies, .kc-backToPolicies {
width: 5rem; width: 5rem;
} }
.kc-backToPolicies {
float: left;
}
.kc-executor-trash-icon { .kc-executor-trash-icon {
margin-left: .5rem; margin-left: .5rem;
color: var(--pf-global--Color--200); color: var(--pf-global--Color--200);
@ -239,7 +248,3 @@ article.pf-c-card.pf-m-flat.kc-login-settings-template
.kc-conditionType-trash-icon:hover { .kc-conditionType-trash-icon:hover {
filter: brightness(55%); filter: brightness(55%);
} }
.kc-backToPolicies {
width: 5rem;
}

View file

@ -56,6 +56,42 @@ export const EditPolicyCrumb = () => {
); );
}; };
export const EditProfileCrumb = () => {
const { t } = useTranslation("realm-settings");
const { realm } = useRealm();
return (
<Breadcrumb>
<BreadcrumbItem
render={(props) => (
<Link {...props} to={toClientPolicies({ realm })}>
{t("clientPolicies")}
</Link>
)}
/>
<BreadcrumbItem isActive>{t("clientProfile")}</BreadcrumbItem>
</Breadcrumb>
);
};
export const EditExecutorCrumb = () => {
const { t } = useTranslation("realm-settings");
const { realm } = useRealm();
return (
<Breadcrumb>
<BreadcrumbItem
render={(props) => (
<Link {...props} to={toClientPolicies({ realm })}>
{t("clientPolicies")}
</Link>
)}
/>
<BreadcrumbItem isActive>{t("executorDetails")}</BreadcrumbItem>
</Breadcrumb>
);
};
export const NewPolicyCrumb = () => { export const NewPolicyCrumb = () => {
const { t } = useTranslation("realm-settings"); const { t } = useTranslation("realm-settings");
const { realm } = useRealm(); const { realm } = useRealm();

View file

@ -267,6 +267,7 @@ export default {
newClientProfile: "Create client profile", newClientProfile: "Create client profile",
newClientProfileName: "Client profile name", newClientProfileName: "Client profile name",
clientProfile: "Client profile details", clientProfile: "Client profile details",
executorDetails: "Executor details",
back: "Back", back: "Back",
delete: "delete", delete: "delete",
save: "Save", save: "Save",
@ -291,6 +292,8 @@ export default {
emptyExecutors: "No executors configured", emptyExecutors: "No executors configured",
addExecutorSuccess: "Success! Executor created successfully", addExecutorSuccess: "Success! Executor created successfully",
addExecutorError: "Executor not created", addExecutorError: "Executor not created",
updateExecutorSuccess: "Executor updated successfully",
updateExecutorError: "Executor not updated",
deleteExecutorProfileConfirmTitle: "Delete executor?", deleteExecutorProfileConfirmTitle: "Delete executor?",
deleteExecutorProfileConfirm: deleteExecutorProfileConfirm:
"The action will permanently delete {{executorName}}. This cannot be undone.", "The action will permanently delete {{executorName}}. This cannot be undone.",

View file

@ -10,6 +10,7 @@ import { ClientPoliciesRoute } from "./routes/ClientPolicies";
import { AddClientProfileRoute } from "./routes/AddClientProfile"; import { AddClientProfileRoute } from "./routes/AddClientProfile";
import { ClientProfileRoute } from "./routes/ClientProfile"; import { ClientProfileRoute } from "./routes/ClientProfile";
import { AddExecutorRoute } from "./routes/AddExecutor"; import { AddExecutorRoute } from "./routes/AddExecutor";
import { ExecutorRoute } from "./routes/Executor";
import { AddClientPolicyRoute } from "./routes/AddClientPolicy"; import { AddClientPolicyRoute } from "./routes/AddClientPolicy";
import { EditClientPolicyRoute } from "./routes/EditClientPolicy"; import { EditClientPolicyRoute } from "./routes/EditClientPolicy";
import { NewClientPolicyConditionRoute } from "./routes/AddCondition"; import { NewClientPolicyConditionRoute } from "./routes/AddCondition";
@ -27,6 +28,7 @@ const routes: RouteDef[] = [
AddClientProfileRoute, AddClientProfileRoute,
AddExecutorRoute, AddExecutorRoute,
ClientProfileRoute, ClientProfileRoute,
ExecutorRoute,
AddClientPolicyRoute, AddClientPolicyRoute,
EditClientPolicyRoute, EditClientPolicyRoute,
NewClientPolicyConditionRoute, NewClientPolicyConditionRoute,

View file

@ -2,6 +2,7 @@ import type { LocationDescriptorObject } from "history";
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom"; import { generatePath } from "react-router-dom";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
import { EditProfileCrumb } from "../RealmSettingsSection";
export type ClientProfileParams = { export type ClientProfileParams = {
realm: string; realm: string;
@ -9,9 +10,9 @@ export type ClientProfileParams = {
}; };
export const ClientProfileRoute: RouteDef = { export const ClientProfileRoute: RouteDef = {
path: "/:realm/realm-settings/clientPolicies/:profileName/edit-profile", path: "/:realm/realm-settings/clientPolicies/:profileName",
component: lazy(() => import("../ClientProfileForm")), component: lazy(() => import("../ClientProfileForm")),
breadcrumb: (t) => t("realm-settings:clientProfile"), breadcrumb: () => EditProfileCrumb,
access: ["view-realm", "view-users"], access: ["view-realm", "view-users"],
}; };

View file

@ -0,0 +1,24 @@
import type { LocationDescriptorObject } from "history";
import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { RouteDef } from "../../route-config";
import { EditExecutorCrumb } from "../RealmSettingsSection";
export type ExecutorParams = {
realm: string;
profileName: string;
executorName: string;
};
export const ExecutorRoute: RouteDef = {
path: "/:realm/realm-settings/clientPolicies/:profileName/:executorName",
component: lazy(() => import("../ExecutorForm")),
breadcrumb: () => EditExecutorCrumb,
access: ["manage-realm"],
};
export const toExecutor = (
params: ExecutorParams
): LocationDescriptorObject => ({
pathname: generatePath(ExecutorRoute.path, params),
});