From db71fad81fcf6d6c9386472f48b63e1fd0b9ec36 Mon Sep 17 00:00:00 2001
From: Eugenia <32821331+jenny-s51@users.noreply.github.com>
Date: Thu, 4 Feb 2021 15:50:13 -0500
Subject: [PATCH] Realm Roles: associated roles modal functionality (#351)
* WIP modal
* modal WIP
* add modal
* place modal in separate file
* format
* wip implementation
* getCompositeRoles with Jeff
* add associated roles tab WIP
* addComposites function WIP
* fix post call
* additional roles fetch
* big rebase
* WIP refresh
* resolve conflicts with Erik latest -> fixes role creation
* delete refresh from associatedrolestab
* fix key and localize
* gets rid of console warnings from watch
* cypress tests, bump react-hook-form to remove console warnings
* update snapshot
* fix delete confirm role name
* delete add
* refresh with Jeff, update cypress tests, select additional roles tab on add
* make dropdownId optional
* format
* remove log stmt
---
package.json | 2 +-
.../__snapshots__/FormAccess.test.tsx.snap | 43 ++++--
.../table-toolbar/KeycloakDataTable.tsx | 6 +
src/components/view-header/ViewHeader.tsx | 7 +-
src/realm-roles/AssociatedRolesModal.tsx | 18 ++-
src/realm-roles/AssociatedRolesTab.tsx | 137 ++++++++++++++++++
src/realm-roles/RealmRoleTabs.tsx | 78 +++++++++-
src/realm-roles/RoleAttributes.tsx | 2 +-
src/realm-roles/RolesList.tsx | 2 +-
src/realm-roles/messages.json | 11 +-
.../integration/realm_roles_test.spec.ts | 22 ++-
yarn.lock | 13 +-
12 files changed, 302 insertions(+), 39 deletions(-)
create mode 100644 src/realm-roles/AssociatedRolesTab.tsx
diff --git a/package.json b/package.json
index fa4ebee027..ad0fea1596 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"moment": "^2.29.1",
"react": "^16.8.5",
"react-dom": "^16.8.5",
- "react-hook-form": "^6.8.2",
+ "react-hook-form": "^6.8.3",
"react-i18next": "^11.7.0",
"react-router-dom": "^5.2.0",
"use-react-router-breadcrumbs": "^1.0.5"
diff --git a/src/components/form-access/__tests__/__snapshots__/FormAccess.test.tsx.snap b/src/components/form-access/__tests__/__snapshots__/FormAccess.test.tsx.snap
index 55821eba20..9debc1f2b2 100644
--- a/src/components/form-access/__tests__/__snapshots__/FormAccess.test.tsx.snap
+++ b/src/components/form-access/__tests__/__snapshots__/FormAccess.test.tsx.snap
@@ -90,11 +90,14 @@ exports[` render normal form 1`] = `
"fieldArrayNamesRef": Object {
"current": Set {},
},
+ "fieldArrayValuesRef": Object {
+ "current": Object {},
+ },
"fieldsRef": Object {
"current": Object {
"consentRequired": Object {
"ref": Object {
- "focus": undefined,
+ "focus": [Function],
"name": "consentRequired",
},
},
@@ -113,6 +116,18 @@ exports[` render normal form 1`] = `
"fieldsWithValidationRef": Object {
"current": Object {},
},
+ "formState": Object {
+ "dirtyFields": Object {},
+ "errors": Object {},
+ "isDirty": false,
+ "isSubmitSuccessful": false,
+ "isSubmitted": false,
+ "isSubmitting": false,
+ "isValid": false,
+ "isValidating": false,
+ "submitCount": 0,
+ "touched": Object {},
+ },
"formStateRef": Object {
"current": Object {
"dirtyFields": Object {},
@@ -122,14 +137,13 @@ exports[` render normal form 1`] = `
"isSubmitted": false,
"isSubmitting": false,
"isValid": false,
+ "isValidating": false,
"submitCount": 0,
"touched": Object {},
},
},
"getValues": [Function],
- "isWatchAllRef": Object {
- "current": false,
- },
+ "isFormDirty": [Function],
"mode": Object {
"isOnAll": false,
"isOnBlur": false,
@@ -143,16 +157,21 @@ exports[` render normal form 1`] = `
},
"readFormStateRef": Object {
"current": Object {
- "dirtyFields": false,
- "isDirty": false,
- "isSubmitting": false,
- "isValid": false,
- "touched": false,
+ "constructor": true,
+ "dirtyFields": true,
+ "errors": true,
+ "isDirty": true,
+ "isSubmitSuccessful": true,
+ "isSubmitted": true,
+ "isSubmitting": true,
+ "isValid": true,
+ "isValidating": true,
+ "submitCount": true,
+ "touched": true,
},
},
"register": [Function],
"removeFieldEventListener": [Function],
- "renderWatchedInputs": [Function],
"resetFieldArrayFunctionRef": Object {
"current": Object {},
},
@@ -164,6 +183,7 @@ exports[` render normal form 1`] = `
"trigger": [Function],
"unregister": [Function],
"updateFormState": [Function],
+ "updateWatchedValue": [Function],
"useWatchFieldsRef": Object {
"current": Object {},
},
@@ -174,9 +194,6 @@ exports[` render normal form 1`] = `
"current": Object {},
},
"validateResolver": undefined,
- "watchFieldsRef": Object {
- "current": Set {},
- },
"watchInternal": [Function],
}
}
diff --git a/src/components/table-toolbar/KeycloakDataTable.tsx b/src/components/table-toolbar/KeycloakDataTable.tsx
index 5c162a5cd0..6b8a8b803b 100644
--- a/src/components/table-toolbar/KeycloakDataTable.tsx
+++ b/src/components/table-toolbar/KeycloakDataTable.tsx
@@ -84,6 +84,7 @@ export type DataListProps = {
isPaginated?: boolean;
ariaLabelKey: string;
searchPlaceholderKey: string;
+ setRefresher?: (refresher: () => void) => void;
columns: Field[];
actions?: Action[];
actionResolver?: IActionsResolver;
@@ -118,6 +119,7 @@ export function KeycloakDataTable({
searchPlaceholderKey,
isPaginated = false,
onSelect,
+ setRefresher,
canSelectAll = false,
loader,
columns,
@@ -138,6 +140,10 @@ export function KeycloakDataTable({
const [key, setKey] = useState(0);
const refresh = () => setKey(new Date().getTime());
+ useEffect(() => {
+ setRefresher && setRefresher(refresh);
+ }, []);
+
useEffect(() => {
return asyncStateFetch(
async () => {
diff --git a/src/components/view-header/ViewHeader.tsx b/src/components/view-header/ViewHeader.tsx
index 7a7a54725d..5d6aa4e78a 100644
--- a/src/components/view-header/ViewHeader.tsx
+++ b/src/components/view-header/ViewHeader.tsx
@@ -24,6 +24,7 @@ export type ViewHeaderProps = {
titleKey: string;
badge?: string;
subKey: string;
+ actionsDropdownId?: string;
subKeyLinkProps?: ButtonProps;
dropdownItems?: ReactElement[];
lowerDropdownItems?: any;
@@ -33,6 +34,7 @@ export type ViewHeaderProps = {
};
export const ViewHeader = ({
+ actionsDropdownId,
titleKey,
badge,
subKey,
@@ -99,7 +101,10 @@ export const ViewHeader = ({
+
{t("common:action")}
}
diff --git a/src/realm-roles/AssociatedRolesModal.tsx b/src/realm-roles/AssociatedRolesModal.tsx
index 403a89d192..b520718b8c 100644
--- a/src/realm-roles/AssociatedRolesModal.tsx
+++ b/src/realm-roles/AssociatedRolesModal.tsx
@@ -12,6 +12,8 @@ import { boolFormatter } from "../util";
export type AssociatedRolesModalProps = {
open: boolean;
toggleDialog: () => void;
+ onConfirm: (newReps: RoleRepresentation[]) => void;
+ existingCompositeRoles: RoleRepresentation[];
};
const attributesToArray = (attributes: { [key: string]: string }): any => {
@@ -40,9 +42,17 @@ export const AssociatedRolesModal = (props: AssociatedRolesModalProps) => {
const loader = async () => {
const allRoles = await adminClient.roles.find();
- const roles = allRoles.filter((x) => x.name != name);
+ const existingAdditionalRoles = await adminClient.roles.getCompositeRoles({
+ id,
+ });
- return roles;
+ return allRoles.filter((role: RoleRepresentation) => {
+ return (
+ existingAdditionalRoles.find(
+ (existing: RoleRepresentation) => existing.name === role.name
+ ) === undefined && role.name !== name
+ );
+ });
};
useEffect(() => {
@@ -76,10 +86,12 @@ export const AssociatedRolesModal = (props: AssociatedRolesModalProps) => {
actions={[