From d08b55ae9a9c6ed59f4c6aa27d2dbb63e23f0f4a Mon Sep 17 00:00:00 2001
From: Jenny <32821331+jenny-s51@users.noreply.github.com>
Date: Wed, 24 Nov 2021 11:19:28 -0500
Subject: [PATCH] Realm settings(client policies): add/edit
client-updater-source-groups condition (#1577)
---
src/clients/scopes/AddScopeDialog.tsx | 1 +
src/components/dynamic/DynamicComponents.tsx | 2 +-
.../dynamic/MultivaluedChipsComponent.tsx | 172 ++++++++++++++++++
src/components/group/GroupPickerDialog.tsx | 13 +-
src/groups/GroupTable.tsx | 2 +-
.../NewClientPolicyCondition.tsx | 22 ++-
src/realm-settings/RealmSettingsSection.css | 4 +
src/user/UserForm.tsx | 4 +-
src/user/user-section.css | 5 +
9 files changed, 211 insertions(+), 14 deletions(-)
create mode 100644 src/components/dynamic/MultivaluedChipsComponent.tsx
diff --git a/src/clients/scopes/AddScopeDialog.tsx b/src/clients/scopes/AddScopeDialog.tsx
index afe0fecfe9..7d2d92fba2 100644
--- a/src/clients/scopes/AddScopeDialog.tsx
+++ b/src/clients/scopes/AddScopeDialog.tsx
@@ -298,6 +298,7 @@ export const AddScopeDialog = ({
{
name: "name",
},
+ { name: "protocol", displayKey: "Protocol" },
{
name: "protocol",
displayKey: "clients:protocol",
diff --git a/src/components/dynamic/DynamicComponents.tsx b/src/components/dynamic/DynamicComponents.tsx
index a6f692cc92..fd3b7ceea2 100644
--- a/src/components/dynamic/DynamicComponents.tsx
+++ b/src/components/dynamic/DynamicComponents.tsx
@@ -13,7 +13,7 @@ export const DynamicComponents = ({ properties }: DynamicComponentProps) => (
<>
{properties.map((property) => {
const componentType = property.type!;
- if (isValidComponentType(componentType)) {
+ if (isValidComponentType(componentType) && property.name !== "scopes") {
const Component = COMPONENTS[componentType];
return ;
} else {
diff --git a/src/components/dynamic/MultivaluedChipsComponent.tsx b/src/components/dynamic/MultivaluedChipsComponent.tsx
new file mode 100644
index 0000000000..98dbf77e48
--- /dev/null
+++ b/src/components/dynamic/MultivaluedChipsComponent.tsx
@@ -0,0 +1,172 @@
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { Controller, useFormContext } from "react-hook-form";
+import {
+ Button,
+ Chip,
+ ChipGroup,
+ FormGroup,
+ TextInput,
+} from "@patternfly/react-core";
+
+import { HelpItem } from "../help-enabler/HelpItem";
+import type { ComponentProps } from "./components";
+import { AddScopeDialog } from "../../clients/scopes/AddScopeDialog";
+import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
+import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
+import { useParams } from "react-router";
+import type { EditClientPolicyConditionParams } from "../../realm-settings/routes/EditCondition";
+import { GroupPickerDialog } from "../group/GroupPickerDialog";
+import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
+
+export const MultivaluedChipsComponent = ({
+ defaultValue,
+ name,
+}: ComponentProps) => {
+ const { t } = useTranslation("dynamic");
+ const { control } = useFormContext();
+ const { conditionName } = useParams();
+ const adminClient = useAdminClient();
+ const [open, setOpen] = useState(false);
+ const [clientScopes, setClientScopes] = useState(
+ []
+ );
+ const [selectedGroups, setSelectedGroups] = useState(
+ []
+ );
+
+ useFetch(
+ () => adminClient.clientScopes.find(),
+ (clientScopes) => {
+ setClientScopes(clientScopes);
+ },
+ []
+ );
+
+ const toggleModal = () => {
+ setOpen(!open);
+ };
+
+ return (
+
+ }
+ fieldId={name!}
+ >
+ {
+ return (
+ <>
+ {open && name === "scopes" && (
+ !value.includes(scope.name!)
+ )}
+ isClientScopesConditionType
+ open={open}
+ toggleDialog={() => setOpen(!open)}
+ onAdd={(scopes) => {
+ onChange([
+ ...value,
+ ...scopes
+ .map((scope) => scope.scope)
+ .map((item) => item.name!),
+ ]);
+ }}
+ />
+ )}
+ {open && name === "groups" && (
+ {
+ onChange([...value, ...groups.map((group) => group.name)]);
+ setSelectedGroups([...selectedGroups!, ...groups]);
+ setOpen(false);
+ }}
+ onClose={() => {
+ setOpen(false);
+ }}
+ filterGroups={value}
+ />
+ )}
+ {value.length === 0 && !conditionName && (
+
+ )}
+ {
+ onChange([]);
+ if (name === "groups") {
+ setSelectedGroups([]);
+ }
+ }}
+ >
+ {value.map((currentChip: string) => (
+ {
+ onChange(
+ value.filter((item: string) => item !== currentChip)
+ );
+ if (name === "groups") {
+ setSelectedGroups(
+ value.filter((item: string) => item !== currentChip)
+ );
+ }
+ }}
+ >
+ {currentChip}
+
+ ))}
+
+
+ >
+ );
+ }}
+ />
+
+ );
+};
diff --git a/src/components/group/GroupPickerDialog.tsx b/src/components/group/GroupPickerDialog.tsx
index 73088efab5..51d37c9a5e 100644
--- a/src/components/group/GroupPickerDialog.tsx
+++ b/src/components/group/GroupPickerDialog.tsx
@@ -25,7 +25,7 @@ import { GroupPath } from "./GroupPath";
export type GroupPickerDialogProps = {
id?: string;
type: "selectOne" | "selectMany";
- filterGroups?: GroupRepresentation[];
+ filterGroups?: string[];
text: { title: string; ok: string };
onConfirm: (groups: GroupRepresentation[]) => void;
onClose: () => void;
@@ -100,9 +100,10 @@ export const GroupPickerDialog = ({
);
const isRowDisabled = (row?: GroupRepresentation) => {
- return !![...joinedGroups, ...(filterGroups || [])].find(
- (group) => group.id === row?.id
- );
+ return [
+ ...joinedGroups.map((item) => item.name),
+ ...(filterGroups || []),
+ ].some((group) => group === row?.name);
};
const hasSubgroups = (group: GroupRepresentation) => {
@@ -129,7 +130,7 @@ export const GroupPickerDialog = ({
{type === "selectMany" && (
{
{move && (
p.name === key);
if (
property?.type === "MultivaluedString" &&
- property.name !== "scopes"
+ property.name !== "scopes" &&
+ property.name !== "groups"
) {
form.setValue(formKey, convertToMultiline(value));
} else if (property?.name === "client-scopes") {
@@ -135,7 +136,9 @@ export default function NewClientPolicyCondition() {
const writeConfig = () => {
return conditionProperties.reduce((r: any, p) => {
- p.type === "MultivaluedString" && p.name !== "scopes"
+ p.type === "MultivaluedString" &&
+ p.name !== "scopes" &&
+ p.name !== "groups"
? (r[p.name!] = toValue(configValues[p.name!]))
: (r[p.name!] = configValues[p.name!]);
return r;
@@ -300,11 +303,22 @@ export default function NewClientPolicyCondition() {
conditionName === "client-scopes")
) {
return (
-
);
+ } else if (
+ property.name === "groups" &&
+ (conditionType === "client-updater-source-groups" ||
+ conditionName === "client-updater-source-groups")
+ ) {
+ return (
+
+ );
} else if (isValidComponentType(componentType)) {
const Component = COMPONENTS[componentType];
return ;
diff --git a/src/realm-settings/RealmSettingsSection.css b/src/realm-settings/RealmSettingsSection.css
index a70ce217fb..34c83f9f21 100644
--- a/src/realm-settings/RealmSettingsSection.css
+++ b/src/realm-settings/RealmSettingsSection.css
@@ -265,3 +265,7 @@ input#kc-scopes {
min-width: 585px;
padding-left: none;
}
+
+.kc-join-group-modal-check {
+ margin-right: var(--pf-global--spacer--sm);
+}
diff --git a/src/user/UserForm.tsx b/src/user/UserForm.tsx
index 1d80e9f980..64048597ff 100644
--- a/src/user/UserForm.tsx
+++ b/src/user/UserForm.tsx
@@ -145,13 +145,13 @@ export const UserForm = ({
setOpen(false);
}}
onClose={() => setOpen(false)}
- filterGroups={selectedGroups}
+ filterGroups={selectedGroups.map((group) => group.name!)}
/>
)}
{user?.id ? (
<>
-
+