add create client policy form; WIP (#1488)
add client policy tests checkout realm settings test from master RealmSettingsPage.ts master remove comment and add missing translation fix tests PR feedback from Jon and Erik rebase editClientPolicy edit client policy add client policy conditions form fix bug in create form remove comment update help text fixes breadcrumbs add support for adding multiple conditions, deleting conditions, and list conditions in data table clean up names add delete functionality to conditions form PR feedback from Jon useMemo for conditions remove comments and logs remove unused hook PR feedback from Jon messages rename message rebase remove duplicate value fixed multi select bug conditionConfigs wip add all config fields, labels, and help text for condition types wip config POST config post is working fix bug in multiline string POST fix any client empty config client scopes config wip fix config settings for client-updater-context fix client access type config clean up configuration conditionals add aria label to resolve critical axe issue Apply suggestions from code review Co-authored-by: Jon Koops <jonkoops@gmail.com> address PR feedback from Jon fix undef error wip edit condition configs fix import wip edit configs wip edit condition configs populate all multiline input fields with data from server update functionality condition configs done update route and delete comment fix client updater context add tests add test for editing condition remove comment fix test unskip tests need optional chain for cypress test fix breadcrumb
This commit is contained in:
parent
386201595b
commit
0565f6a482
11 changed files with 334 additions and 51 deletions
|
@ -566,6 +566,30 @@ describe("Realm settings tests", () => {
|
||||||
realmSettingsPage.shouldSearchClientPolicy();
|
realmSettingsPage.shouldSearchClientPolicy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should not have conditions configured by default", () => {
|
||||||
|
realmSettingsPage.shouldNotHaveConditionsConfigured();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should cancel adding a new condition to a client profile", () => {
|
||||||
|
realmSettingsPage.shouldCancelAddingCondition();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should add a new condition to a client profile", () => {
|
||||||
|
realmSettingsPage.shouldAddCondition();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should edit the condition of a client profile", () => {
|
||||||
|
realmSettingsPage.shouldEditCondition();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should cancel deleting condition from a client profile", () => {
|
||||||
|
realmSettingsPage.shouldCancelDeletingCondition();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should delete condition from a client profile", () => {
|
||||||
|
realmSettingsPage.shouldDeleteCondition();
|
||||||
|
});
|
||||||
|
|
||||||
it("Check cancelling the client policy deletion", () => {
|
it("Check cancelling the client policy deletion", () => {
|
||||||
realmSettingsPage.shouldDisplayDeleteClientPolicyDialog();
|
realmSettingsPage.shouldDisplayDeleteClientPolicyDialog();
|
||||||
});
|
});
|
||||||
|
|
|
@ -176,8 +176,12 @@ 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 = 'a[href*="realm-settings/clientPolicies/Test"]';
|
private clientProfileOne =
|
||||||
private clientProfileTwo = 'a[href*="realm-settings/clientPolicies/Edit"]';
|
'a[href*="realm-settings/clientPolicies/Test/edit-profile"]';
|
||||||
|
private clientProfileTwo =
|
||||||
|
'a[href*="realm-settings/clientPolicies/Edit/edit-profile"]';
|
||||||
|
private clientPolicy =
|
||||||
|
'a[href*="realm-settings/clientPolicies/Test/edit-policy"]';
|
||||||
private reloadBtn = "reloadProfile";
|
private reloadBtn = "reloadProfile";
|
||||||
private addExecutor = "addExecutor";
|
private addExecutor = "addExecutor";
|
||||||
private addExecutorDrpDwn = ".pf-c-select__toggle";
|
private addExecutorDrpDwn = ".pf-c-select__toggle";
|
||||||
|
@ -185,6 +189,13 @@ export default class RealmSettingsPage {
|
||||||
private addExecutorCancelBtn = "addExecutor-cancelBtn";
|
private addExecutorCancelBtn = "addExecutor-cancelBtn";
|
||||||
private addExecutorSaveBtn = "addExecutor-saveBtn";
|
private addExecutorSaveBtn = "addExecutor-saveBtn";
|
||||||
private listingPage = new ListingPage();
|
private listingPage = new ListingPage();
|
||||||
|
private addCondition = "addCondition";
|
||||||
|
private addConditionDrpDwn = ".pf-c-select__toggle";
|
||||||
|
private addConditionDrpDwnOption = "conditionType-select";
|
||||||
|
private addConditionCancelBtn = "addCondition-cancelBtn";
|
||||||
|
private addConditionSaveBtn = "addCondition-saveBtn";
|
||||||
|
private conditionTypeLink = "condition-type-link";
|
||||||
|
private addValue = "addValue";
|
||||||
|
|
||||||
selectLoginThemeType(themeType: string) {
|
selectLoginThemeType(themeType: string) {
|
||||||
cy.get(this.selectLoginTheme).click();
|
cy.get(this.selectLoginTheme).click();
|
||||||
|
@ -843,6 +854,87 @@ export default class RealmSettingsPage {
|
||||||
cy.get("table").should("be.visible").contains("td", "Test");
|
cy.get("table").should("be.visible").contains("td", "Test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldNotHaveConditionsConfigured() {
|
||||||
|
cy.get(this.clientPolicy).click();
|
||||||
|
cy.get('h6[class*="kc-emptyConditions"]').should(
|
||||||
|
"have.text",
|
||||||
|
"No conditions configured"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldCancelAddingCondition() {
|
||||||
|
cy.get(this.clientPolicy).click();
|
||||||
|
cy.findByTestId(this.addCondition).click();
|
||||||
|
cy.get(this.addConditionDrpDwn).click();
|
||||||
|
cy.findByTestId(this.addConditionDrpDwnOption)
|
||||||
|
.contains("any-client")
|
||||||
|
.click();
|
||||||
|
cy.findByTestId(this.addConditionCancelBtn).click();
|
||||||
|
cy.get('h6[class*="kc-emptyConditions"]').should(
|
||||||
|
"have.text",
|
||||||
|
"No conditions configured"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldAddCondition() {
|
||||||
|
cy.get(this.clientPolicy).click();
|
||||||
|
cy.findByTestId(this.addCondition).click();
|
||||||
|
cy.get(this.addConditionDrpDwn).click();
|
||||||
|
cy.findByTestId(this.addConditionDrpDwnOption)
|
||||||
|
.contains("client-roles")
|
||||||
|
.click();
|
||||||
|
cy.get('input[name="config.roles[0].value"]').click().type("role 1");
|
||||||
|
|
||||||
|
cy.findByTestId(this.addConditionSaveBtn).click();
|
||||||
|
cy.get(this.alertMessage).should(
|
||||||
|
"be.visible",
|
||||||
|
"Success! Condition created successfully"
|
||||||
|
);
|
||||||
|
cy.get('ul[class*="pf-c-data-list"]').should("have.text", "client-roles");
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldEditCondition() {
|
||||||
|
cy.get(this.clientPolicy).click();
|
||||||
|
|
||||||
|
cy.findByTestId(this.conditionTypeLink).contains("client-roles").click();
|
||||||
|
|
||||||
|
cy.findByTestId(this.addValue).click();
|
||||||
|
|
||||||
|
cy.get('input[name="config.roles[1].value"]').click().type("role 2");
|
||||||
|
|
||||||
|
cy.findByTestId(this.addConditionSaveBtn).click();
|
||||||
|
cy.get(this.alertMessage).should(
|
||||||
|
"be.visible",
|
||||||
|
"Success! Condition updated successfully"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldCancelDeletingCondition() {
|
||||||
|
cy.get(this.clientPolicy).click();
|
||||||
|
cy.get('svg[class*="kc-conditionType-trash-icon"]').click();
|
||||||
|
cy.get(this.deleteDialogTitle).contains("Delete condition?");
|
||||||
|
cy.get(this.deleteDialogBodyText).contains(
|
||||||
|
"This action will permanently delete client-roles. This cannot be undone."
|
||||||
|
);
|
||||||
|
cy.findByTestId("modalConfirm").contains("Delete");
|
||||||
|
cy.get(this.deleteDialogCancelBtn).contains("Cancel").click();
|
||||||
|
cy.get('ul[class*="pf-c-data-list"]').should("have.text", "client-roles");
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldDeleteCondition() {
|
||||||
|
cy.get(this.clientPolicy).click();
|
||||||
|
cy.get('svg[class*="kc-conditionType-trash-icon"]').click();
|
||||||
|
cy.get(this.deleteDialogTitle).contains("Delete condition?");
|
||||||
|
cy.get(this.deleteDialogBodyText).contains(
|
||||||
|
"This action will permanently delete client-roles. This cannot be undone."
|
||||||
|
);
|
||||||
|
cy.findByTestId("modalConfirm").contains("Delete").click();
|
||||||
|
cy.get('h6[class*="kc-emptyConditions"]').should(
|
||||||
|
"have.text",
|
||||||
|
"No conditions configured"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
shouldDeleteClientPolicyDialog() {
|
shouldDeleteClientPolicyDialog() {
|
||||||
this.listingPage.searchItem("Test", false);
|
this.listingPage.searchItem("Test", false);
|
||||||
this.listingPage.clickRowDetails("Test").clickDetailMenu("Delete");
|
this.listingPage.clickRowDetails("Test").clickDetailMenu("Delete");
|
||||||
|
|
|
@ -5,15 +5,28 @@ import { COMPONENTS, isValidComponentType } from "./components";
|
||||||
|
|
||||||
type DynamicComponentProps = {
|
type DynamicComponentProps = {
|
||||||
properties: ConfigPropertyRepresentation[];
|
properties: ConfigPropertyRepresentation[];
|
||||||
|
selectedValues?: string[];
|
||||||
|
parentCallback?: (data: string[]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DynamicComponents = ({ properties }: DynamicComponentProps) => (
|
export const DynamicComponents = ({
|
||||||
|
properties,
|
||||||
|
selectedValues,
|
||||||
|
parentCallback,
|
||||||
|
}: DynamicComponentProps) => (
|
||||||
<>
|
<>
|
||||||
{properties.map((property) => {
|
{properties.map((property) => {
|
||||||
const componentType = property.type!;
|
const componentType = property.type!;
|
||||||
if (isValidComponentType(componentType)) {
|
if (isValidComponentType(componentType)) {
|
||||||
const Component = COMPONENTS[componentType];
|
const Component = COMPONENTS[componentType];
|
||||||
return <Component key={property.name} {...property} />;
|
return (
|
||||||
|
<Component
|
||||||
|
key={property.name}
|
||||||
|
selectedValues={selectedValues}
|
||||||
|
parentCallback={parentCallback}
|
||||||
|
{...property}
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.warn(`There is no editor registered for ${componentType}`);
|
console.warn(`There is no editor registered for ${componentType}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, 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,10 +18,20 @@ 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
|
||||||
|
@ -52,10 +62,19 @@ export const MultiValuedListComponent = ({
|
||||||
const option = v.toString();
|
const option = v.toString();
|
||||||
if (!value) {
|
if (!value) {
|
||||||
onChange([option]);
|
onChange([option]);
|
||||||
|
parentCallback!([option]);
|
||||||
|
setSelectedItems([option]);
|
||||||
} else if (value.includes(option)) {
|
} else if (value.includes(option)) {
|
||||||
onChange(value.filter((item: string) => item !== option));
|
const updatedItems = selectedItems.filter(
|
||||||
|
(item: string) => item !== option
|
||||||
|
);
|
||||||
|
setSelectedItems(updatedItems);
|
||||||
|
onChange(updatedItems);
|
||||||
|
parentCallback!(updatedItems);
|
||||||
} else {
|
} else {
|
||||||
onChange([...value, option]);
|
onChange([...value, option]);
|
||||||
|
parentCallback!([...value, option]);
|
||||||
|
setSelectedItems([...selectedItems, option]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClear={(event) => {
|
onClear={(event) => {
|
||||||
|
|
|
@ -10,7 +10,10 @@ import { ClientSelectComponent } from "./ClientSelectComponent";
|
||||||
import { MultiValuedStringComponent } from "./MultivaluedStringComponent";
|
import { MultiValuedStringComponent } from "./MultivaluedStringComponent";
|
||||||
import { MultiValuedListComponent } from "./MultivaluedListComponent";
|
import { MultiValuedListComponent } from "./MultivaluedListComponent";
|
||||||
|
|
||||||
export type ComponentProps = Omit<ConfigPropertyRepresentation, "type">;
|
export type ComponentProps = Omit<ConfigPropertyRepresentation, "type"> & {
|
||||||
|
selectedValues?: string[];
|
||||||
|
parentCallback?: (data: any) => void;
|
||||||
|
};
|
||||||
const ComponentTypes = [
|
const ComponentTypes = [
|
||||||
"String",
|
"String",
|
||||||
"boolean",
|
"boolean",
|
||||||
|
|
|
@ -15,13 +15,13 @@ export type MultiLine = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function convertToMultiline(fields: string[]): MultiLine[] {
|
export function convertToMultiline(fields: string[]): MultiLine[] {
|
||||||
return (fields && fields.length > 0 ? fields : [""]).map((field) => {
|
return (fields.length > 0 ? fields : [""]).map((field) => {
|
||||||
return { value: field };
|
return { value: field };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toValue(formValue: MultiLine[]): string[] {
|
export function toValue(formValue: MultiLine[]): string[] {
|
||||||
return formValue?.map((field) => field.value);
|
return formValue.map((field) => field.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MultiLineInputProps = Omit<TextInputProps, "form"> & {
|
export type MultiLineInputProps = Omit<TextInputProps, "form"> & {
|
||||||
|
@ -76,6 +76,8 @@ export const MultiLineInput = ({
|
||||||
onClick={() => append({})}
|
onClick={() => append({})}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
aria-label={t("common:add")}
|
aria-label={t("common:add")}
|
||||||
|
data-testid="addValue"
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
isDisabled={rest.isDisabled || !currentValues?.[index]?.value}
|
isDisabled={rest.isDisabled || !currentValues?.[index]?.value}
|
||||||
>
|
>
|
||||||
<PlusCircleIcon /> {t(addButtonLabel || "common:add")}
|
<PlusCircleIcon /> {t(addButtonLabel || "common:add")}
|
||||||
|
|
|
@ -23,10 +23,15 @@ import { useAlerts } from "../components/alert/Alerts";
|
||||||
import { useHistory, useParams } from "react-router";
|
import { useHistory, useParams } from "react-router";
|
||||||
import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
|
import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation";
|
||||||
import { useRealm } from "../context/realm-context/RealmContext";
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
import type { EditClientPolicyParams } from "./routes/EditClientPolicy";
|
|
||||||
import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation";
|
import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation";
|
||||||
import type ClientPolicyConditionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyConditionRepresentation";
|
import type ClientPolicyConditionRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyConditionRepresentation";
|
||||||
import { DynamicComponents } from "../components/dynamic/DynamicComponents";
|
import { DynamicComponents } from "../components/dynamic/DynamicComponents";
|
||||||
|
import {
|
||||||
|
EditClientPolicyParams,
|
||||||
|
toEditClientPolicy,
|
||||||
|
} from "./routes/EditClientPolicy";
|
||||||
|
import type { EditClientPolicyConditionParams } from "./routes/EditCondition";
|
||||||
|
import { convertToMultiline } from "../components/multi-line-input/MultiLineInput";
|
||||||
|
|
||||||
export type ItemType = { value: string };
|
export type ItemType = { value: string };
|
||||||
|
|
||||||
|
@ -45,12 +50,17 @@ export default function NewClientPolicyCondition() {
|
||||||
const [condition, setCondition] = useState<
|
const [condition, setCondition] = useState<
|
||||||
ClientPolicyConditionRepresentation[]
|
ClientPolicyConditionRepresentation[]
|
||||||
>([]);
|
>([]);
|
||||||
|
const [conditionData, setConditionData] =
|
||||||
|
useState<ClientPolicyConditionRepresentation>();
|
||||||
const [conditionType, setConditionType] = useState("");
|
const [conditionType, setConditionType] = useState("");
|
||||||
const [conditionProperties, setConditionProperties] = useState<
|
const [conditionProperties, setConditionProperties] = useState<
|
||||||
ConfigPropertyRepresentation[]
|
ConfigPropertyRepresentation[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
const [selectedVals, setSelectedVals] = useState<any>();
|
||||||
|
|
||||||
const { policyName } = useParams<EditClientPolicyParams>();
|
const { policyName } = useParams<EditClientPolicyParams>();
|
||||||
|
const { conditionName } = useParams<EditClientPolicyConditionParams>();
|
||||||
|
|
||||||
const serverInfo = useServerInfo();
|
const serverInfo = useServerInfo();
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
|
@ -62,48 +72,139 @@ export default function NewClientPolicyCondition() {
|
||||||
|
|
||||||
const adminClient = useAdminClient();
|
const adminClient = useAdminClient();
|
||||||
|
|
||||||
|
const setupForm = (condition: ClientPolicyConditionRepresentation) => {
|
||||||
|
form.reset();
|
||||||
|
|
||||||
|
Object.entries(condition).map(([key, value]) => {
|
||||||
|
if (key === "configuration") {
|
||||||
|
if (
|
||||||
|
conditionName === "client-roles" ||
|
||||||
|
conditionName === "client-updater-source-roles"
|
||||||
|
) {
|
||||||
|
form.setValue("config.roles", convertToMultiline(value["roles"]));
|
||||||
|
} else if (conditionName === "client-scopes") {
|
||||||
|
form.setValue("config.scopes", convertToMultiline(value["scopes"]));
|
||||||
|
form.setValue("config.type", value["type"]);
|
||||||
|
} else if (conditionName === "client-updater-source-groups") {
|
||||||
|
form.setValue("config.groups", convertToMultiline(value["groups"]));
|
||||||
|
} else if (conditionName === "client-updater-source-host") {
|
||||||
|
form.setValue(
|
||||||
|
"config.trusted-hosts",
|
||||||
|
convertToMultiline(value["trusted-hosts"])
|
||||||
|
);
|
||||||
|
} else if (conditionName === "client-updater-context") {
|
||||||
|
form.setValue(
|
||||||
|
"config.update-client-source",
|
||||||
|
value["update-client-source"][0]["update-client-source"]
|
||||||
|
);
|
||||||
|
} else if (conditionName === "client-access-type") {
|
||||||
|
form.setValue("config.type", value.type[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
form.setValue(key, value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useFetch(
|
useFetch(
|
||||||
() => adminClient.clientPolicies.listPolicies(),
|
() => adminClient.clientPolicies.listPolicies(),
|
||||||
(policies) => {
|
(policies) => {
|
||||||
setPolicies(policies.policies ?? []);
|
setPolicies(policies.policies ?? []);
|
||||||
|
if (conditionName) {
|
||||||
|
const currentPolicy = policies.policies?.find(
|
||||||
|
(item) => item.name === policyName
|
||||||
|
);
|
||||||
|
|
||||||
|
const typeAndConfigData = currentPolicy?.conditions?.find(
|
||||||
|
(item) => item.condition === conditionName
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentCondition = conditionTypes?.find(
|
||||||
|
(condition) => condition.id === conditionName
|
||||||
|
);
|
||||||
|
|
||||||
|
setConditionData(typeAndConfigData!);
|
||||||
|
setSelectedVals(Object.values(typeAndConfigData?.configuration!)[0][0]);
|
||||||
|
setConditionProperties(currentCondition?.properties!);
|
||||||
|
setupForm(typeAndConfigData!);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
|
const formValues = form.getValues();
|
||||||
|
const configValues = formValues.config;
|
||||||
|
|
||||||
|
const writeConfig = () => {
|
||||||
|
if (
|
||||||
|
condition[0]?.condition === "any-client" ||
|
||||||
|
conditionName === "any-client"
|
||||||
|
) {
|
||||||
|
return {};
|
||||||
|
} else if (
|
||||||
|
condition[0]?.condition === "client-access-type" ||
|
||||||
|
conditionName === "client-access-type"
|
||||||
|
) {
|
||||||
|
return { type: [formValues.config.type] };
|
||||||
|
} else if (
|
||||||
|
condition[0]?.condition === "client-updater-context" ||
|
||||||
|
conditionName === "client-updater-context"
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
"update-client-source": [Object.values(formValues)[0]],
|
||||||
|
};
|
||||||
|
} else if (
|
||||||
|
condition[0]?.condition === "client-scopes" ||
|
||||||
|
conditionName === "client-scopes"
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: Object.values(formValues)[0].type,
|
||||||
|
scopes: (Object.values(formValues)[0].scopes as ItemType[]).map(
|
||||||
|
(item) => (item as ItemType).value
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else
|
||||||
|
return {
|
||||||
|
[Object.keys(configValues)[0]]: Object.values(
|
||||||
|
configValues?.[Object.keys(configValues)[0]]
|
||||||
|
).map((item) => (item as ItemType).value),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const updatedPolicies = policies.map((policy) => {
|
const updatedPolicies = policies.map((policy) => {
|
||||||
if (policy.name !== policyName) {
|
if (policy.name !== policyName) {
|
||||||
return policy;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formValues = form.getValues();
|
let conditions = policy.conditions ?? [];
|
||||||
const configValues = formValues.config;
|
|
||||||
|
|
||||||
const writeConfig = () => {
|
if (conditionName) {
|
||||||
if (condition[0]?.condition === "any-client") {
|
const createdCondition = {
|
||||||
return {};
|
condition: conditionData?.condition,
|
||||||
} else if (condition[0]?.condition === "client-access-type") {
|
configuration: writeConfig(),
|
||||||
return { type: [formValues["client-accesstype"].label] };
|
};
|
||||||
} else if (condition[0]?.condition === "client-updater-context") {
|
|
||||||
return {
|
|
||||||
"update-client-source": [Object.values(formValues)[0]],
|
|
||||||
};
|
|
||||||
} else if (condition[0]?.condition === "client-scopes") {
|
|
||||||
return {
|
|
||||||
type: Object.values(formValues)[0].type,
|
|
||||||
scopes: (Object.values(formValues)[0].scopes as ItemType[]).map(
|
|
||||||
(item) => (item as ItemType).value
|
|
||||||
),
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
return {
|
|
||||||
[Object.keys(configValues)[0]]: Object.values(
|
|
||||||
configValues?.[Object.keys(configValues)[0]]
|
|
||||||
).map((item) => (item as ItemType).value),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const conditions = (policy.conditions ?? []).concat({
|
const index = conditions.findIndex(
|
||||||
|
(condition) => conditionName === condition.condition
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newConditions = [
|
||||||
|
...conditions.slice(0, index),
|
||||||
|
createdCondition,
|
||||||
|
...conditions.slice(index + 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...policy,
|
||||||
|
conditions: newConditions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
conditions = conditions.concat({
|
||||||
condition: condition[0].condition,
|
condition: condition[0].condition,
|
||||||
configuration: writeConfig(),
|
configuration: writeConfig(),
|
||||||
});
|
});
|
||||||
|
@ -112,7 +213,7 @@ export default function NewClientPolicyCondition() {
|
||||||
...policy,
|
...policy,
|
||||||
conditions,
|
conditions,
|
||||||
};
|
};
|
||||||
});
|
}) as ClientPolicyRepresentation[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await adminClient.clientPolicies.updatePolicy({
|
await adminClient.clientPolicies.updatePolicy({
|
||||||
|
@ -123,7 +224,9 @@ export default function NewClientPolicyCondition() {
|
||||||
`/${realm}/realm-settings/clientPolicies/${policyName}/edit-policy`
|
`/${realm}/realm-settings/clientPolicies/${policyName}/edit-policy`
|
||||||
);
|
);
|
||||||
addAlert(
|
addAlert(
|
||||||
t("realm-settings:createClientConditionSuccess"),
|
conditionName
|
||||||
|
? t("realm-settings:updateClientConditionSuccess")
|
||||||
|
: t("realm-settings:createClientConditionSuccess"),
|
||||||
AlertVariant.success
|
AlertVariant.success
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -131,9 +234,16 @@ export default function NewClientPolicyCondition() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCallback = (childData: any) => {
|
||||||
|
setSelectedVals(childData);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageSection variant="light">
|
<PageSection variant="light">
|
||||||
<FormPanel className="kc-login-screen" title={t("addCondition")}>
|
<FormPanel
|
||||||
|
className="kc-login-screen"
|
||||||
|
title={conditionName ? t("editCondition") : t("addCondition")}
|
||||||
|
>
|
||||||
<FormAccess
|
<FormAccess
|
||||||
isHorizontal
|
isHorizontal
|
||||||
role="manage-realm"
|
role="manage-realm"
|
||||||
|
@ -166,7 +276,9 @@ export default function NewClientPolicyCondition() {
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Select
|
<Select
|
||||||
placeholderText={t("selectACondition")}
|
placeholderText={t("selectACondition")}
|
||||||
|
data-testid="conditionType-select"
|
||||||
toggleId="provider"
|
toggleId="provider"
|
||||||
|
isDisabled={!!conditionName}
|
||||||
onToggle={(toggle) => setOpenConditionType(toggle)}
|
onToggle={(toggle) => setOpenConditionType(toggle)}
|
||||||
onSelect={(_, value) => {
|
onSelect={(_, value) => {
|
||||||
onChange(value);
|
onChange(value);
|
||||||
|
@ -181,7 +293,7 @@ export default function NewClientPolicyCondition() {
|
||||||
]);
|
]);
|
||||||
setOpenConditionType(false);
|
setOpenConditionType(false);
|
||||||
}}
|
}}
|
||||||
selections={conditionType}
|
selections={conditionName ? conditionName : conditionType}
|
||||||
variant={SelectVariant.single}
|
variant={SelectVariant.single}
|
||||||
aria-label={t("conditionType")}
|
aria-label={t("conditionType")}
|
||||||
isOpen={openConditionType}
|
isOpen={openConditionType}
|
||||||
|
@ -205,23 +317,32 @@ export default function NewClientPolicyCondition() {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<DynamicComponents properties={conditionProperties} />
|
<DynamicComponents
|
||||||
|
properties={conditionProperties}
|
||||||
|
selectedValues={
|
||||||
|
conditionName === "client-access-type"
|
||||||
|
? selectedVals
|
||||||
|
: conditionName === "client-updater-context"
|
||||||
|
? selectedVals?.["update-client-source"]
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
parentCallback={handleCallback}
|
||||||
|
/>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
<ActionGroup>
|
<ActionGroup>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
data-testid="edit-policy-tab-save"
|
data-testid="addCondition-saveBtn"
|
||||||
isDisabled={conditionType === ""}
|
isDisabled={conditionType === "" && !conditionName}
|
||||||
>
|
>
|
||||||
{t("common:add")}
|
{conditionName ? t("common:save") : t("common:add")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="link"
|
variant="link"
|
||||||
|
data-testid="addCondition-cancelBtn"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
history.push(
|
history.push(toEditClientPolicy({ realm, policyName }))
|
||||||
`/${realm}/realm-settings/clientPolicies/${policyName}/edit-policy`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("common:cancel")}
|
{t("common:cancel")}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import type ClientPolicyRepresentation from "@keycloak/keycloak-admin-client/lib
|
||||||
import { toClientPolicies } from "./routes/ClientPolicies";
|
import { toClientPolicies } from "./routes/ClientPolicies";
|
||||||
import { toNewClientPolicyCondition } from "./routes/AddCondition";
|
import { toNewClientPolicyCondition } from "./routes/AddCondition";
|
||||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
import { toEditClientPolicyCondition } from "./routes/EditCondition";
|
||||||
import type { EditClientPolicyParams } from "./routes/EditClientPolicy";
|
import type { EditClientPolicyParams } from "./routes/EditClientPolicy";
|
||||||
import { AddClientProfileModal } from "./AddClientProfileModal";
|
import { AddClientProfileModal } from "./AddClientProfileModal";
|
||||||
import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation";
|
import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation";
|
||||||
|
@ -462,7 +463,7 @@ export default function NewClientPolicyForm() {
|
||||||
)}
|
)}
|
||||||
variant="link"
|
variant="link"
|
||||||
className="kc-addCondition"
|
className="kc-addCondition"
|
||||||
data-testid="cancelCreateProfile"
|
data-testid="addCondition"
|
||||||
icon={<PlusCircleIcon />}
|
icon={<PlusCircleIcon />}
|
||||||
>
|
>
|
||||||
{t("realm-settings:addCondition")}
|
{t("realm-settings:addCondition")}
|
||||||
|
@ -490,7 +491,11 @@ export default function NewClientPolicyForm() {
|
||||||
<Link
|
<Link
|
||||||
key={condition.condition}
|
key={condition.condition}
|
||||||
data-testid="condition-type-link"
|
data-testid="condition-type-link"
|
||||||
to={""}
|
to={toEditClientPolicyCondition({
|
||||||
|
realm,
|
||||||
|
conditionName: condition.condition!,
|
||||||
|
policyName: policyName,
|
||||||
|
})}
|
||||||
className="kc-condition-link"
|
className="kc-condition-link"
|
||||||
>
|
>
|
||||||
{condition.condition}
|
{condition.condition}
|
||||||
|
@ -570,7 +575,7 @@ export default function NewClientPolicyForm() {
|
||||||
id="addClientProfile"
|
id="addClientProfile"
|
||||||
variant="link"
|
variant="link"
|
||||||
className="kc-addClientProfile"
|
className="kc-addClientProfile"
|
||||||
data-testid="cancelCreateProfile"
|
data-testid="addClientProfile"
|
||||||
icon={<PlusCircleIcon />}
|
icon={<PlusCircleIcon />}
|
||||||
onClick={toggleModal}
|
onClick={toggleModal}
|
||||||
>
|
>
|
||||||
|
|
|
@ -200,6 +200,7 @@ export default {
|
||||||
createClientPolicySuccess: "New policy created",
|
createClientPolicySuccess: "New policy created",
|
||||||
createClientConditionSuccess: "Condition created successfully.",
|
createClientConditionSuccess: "Condition created successfully.",
|
||||||
createClientConditionError: "Error creating condition: {{error}}",
|
createClientConditionError: "Error creating condition: {{error}}",
|
||||||
|
updateClientConditionSuccess: "Condition updated successfully.",
|
||||||
deleteClientConditionSuccess: "Condition deleted successfully.",
|
deleteClientConditionSuccess: "Condition deleted successfully.",
|
||||||
deleteClientConditionError: "Error creating condition: {{error}}",
|
deleteClientConditionError: "Error creating condition: {{error}}",
|
||||||
clientPolicySearch: "Search client policy",
|
clientPolicySearch: "Search client policy",
|
||||||
|
@ -312,6 +313,7 @@ export default {
|
||||||
clientUpdaterSourceRoles: "Updating entity role",
|
clientUpdaterSourceRoles: "Updating entity role",
|
||||||
conditionsHelpItem: "Conditions help item",
|
conditionsHelpItem: "Conditions help item",
|
||||||
addCondition: "Add condition",
|
addCondition: "Add condition",
|
||||||
|
editCondition: "Edit condition",
|
||||||
emptyConditions: "No conditions configured",
|
emptyConditions: "No conditions configured",
|
||||||
updateClientPoliciesSuccess:
|
updateClientPoliciesSuccess:
|
||||||
"The client policies configuration was updated",
|
"The client policies configuration was updated",
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { AddExecutorRoute } from "./routes/AddExecutor";
|
||||||
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";
|
||||||
|
import { EditClientPolicyConditionRoute } from "./routes/EditCondition";
|
||||||
|
|
||||||
const routes: RouteDef[] = [
|
const routes: RouteDef[] = [
|
||||||
RealmSettingsRoute,
|
RealmSettingsRoute,
|
||||||
|
@ -29,6 +30,7 @@ const routes: RouteDef[] = [
|
||||||
AddClientPolicyRoute,
|
AddClientPolicyRoute,
|
||||||
EditClientPolicyRoute,
|
EditClientPolicyRoute,
|
||||||
NewClientPolicyConditionRoute,
|
NewClientPolicyConditionRoute,
|
||||||
|
EditClientPolicyConditionRoute,
|
||||||
];
|
];
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
|
|
@ -12,7 +12,7 @@ export type EditClientPolicyConditionParams = {
|
||||||
export const EditClientPolicyConditionRoute: RouteDef = {
|
export const EditClientPolicyConditionRoute: RouteDef = {
|
||||||
path: "/:realm/realm-settings/clientPolicies/:policyName?/edit-policy/:conditionName/edit-condition",
|
path: "/:realm/realm-settings/clientPolicies/:policyName?/edit-policy/:conditionName/edit-condition",
|
||||||
component: NewClientPolicyCondition,
|
component: NewClientPolicyCondition,
|
||||||
breadcrumb: (t) => t("realm-settings:addCondition"),
|
breadcrumb: (t) => t("realm-settings:editCondition"),
|
||||||
access: "manage-clients",
|
access: "manage-clients",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue