diff --git a/cypress/integration/group_test.spec.ts b/cypress/integration/group_test.spec.ts index 525cbff11d..a268a2ba2a 100644 --- a/cypress/integration/group_test.spec.ts +++ b/cypress/integration/group_test.spec.ts @@ -22,8 +22,17 @@ describe("Group test", () => { let groupName = "group"; + const clickGroup = (itemName: string) => { + const membersUrl = `/auth/admin/realms/master/groups/*/members`; + cy.intercept(membersUrl).as("groupFetch"); + cy.get("table").contains(itemName).click(); + cy.wait(["@groupFetch"]); + + return this; + }; + describe("Group creation", () => { - beforeEach(function () { + beforeEach(() => { keycloakBefore(); loginPage.logIn(); sidebarPage.goToGroups(); @@ -52,7 +61,7 @@ describe("Group test", () => { .open("empty-primary-action") .fillGroupForm(groupName) .clickCreate(); - listingPage.goToItemDetails(groupName); + clickGroup(groupName); viewHeaderPage.clickAction("renameGroupAction"); const newName = "Renamed group"; @@ -62,6 +71,7 @@ describe("Group test", () => { sidebarPage.goToGroups(); listingPage.searchItem(newName, false).itemExist(newName); listingPage.deleteItem(newName); + masthead.checkNotificationMessage("Group deleted"); }); it("Should move group", () => { @@ -78,12 +88,12 @@ describe("Group test", () => { moveGroupModal.clickMove(); masthead.checkNotificationMessage("Group moved"); - listingPage.itemExist(groupName, false).goToItemDetails(targetGroupName); - cy.wait(2000); + listingPage.itemExist(groupName, false); + clickGroup(targetGroupName); listingPage.itemExist(groupName); - cy.wait(1000); sidebarPage.goToGroups(); listingPage.deleteItem(targetGroupName); + masthead.checkNotificationMessage("Group deleted"); }); it("Should move group to root", async () => { @@ -102,7 +112,7 @@ describe("Group test", () => { listingPage.deleteItem(groups[0]); listingPage.deleteItem(groups[1]); }); - + it("Group search", () => { viewHeaderPage.clickAction("searchGroup"); searchGroupPage.searchGroup("group").clickSearchButton(); @@ -141,7 +151,7 @@ describe("Group test", () => { }); it("Should display all the subgroups", () => { - listingPage.goToItemDetails(groups[0]); + clickGroup(groups[0]); detailPage.checkListSubGroup([groups[1]]); const added = "addedGroup"; @@ -151,7 +161,7 @@ describe("Group test", () => { }); it("Should display members", () => { - listingPage.goToItemDetails(groups[0]); + clickGroup(groups[0]); detailPage.clickMembersTab().checkListMembers(["user0", "user3"]); detailPage .clickIncludeSubGroups() @@ -159,7 +169,7 @@ describe("Group test", () => { }); it("Should add members", () => { - listingPage.goToItemDetails(groups[0]); + clickGroup(groups[0]); detailPage .clickMembersTab() .clickAddMembers() @@ -171,7 +181,7 @@ describe("Group test", () => { }); it("Attributes CRUD test", () => { - listingPage.goToItemDetails(groups[0]); + clickGroup(groups[0]); detailPage .clickAttributesTab() .fillAttribute("key", "value") diff --git a/src/components/table-toolbar/KeycloakDataTable.tsx b/src/components/table-toolbar/KeycloakDataTable.tsx index 49cc4bf581..9b476d6902 100644 --- a/src/components/table-toolbar/KeycloakDataTable.tsx +++ b/src/components/table-toolbar/KeycloakDataTable.tsx @@ -229,13 +229,11 @@ export function KeycloakDataTable({ return node.map(getNodeText).join(""); } if (typeof node === "object" && node) { - if ((node as TitleCell).title) { - return getNodeText( - isValidElement((node as TitleCell).title) - ? (node as TitleCell).title.props.children - : (node as JSX.Element).props.children - ); - } + return getNodeText( + isValidElement((node as TitleCell).title) + ? (node as TitleCell).title.props.children + : (node as JSX.Element).props.children + ); } return ""; }; diff --git a/src/groups/GroupTable.tsx b/src/groups/GroupTable.tsx index f14ceadb9d..ee6191552f 100644 --- a/src/groups/GroupTable.tsx +++ b/src/groups/GroupTable.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { Link, useHistory, useLocation } from "react-router-dom"; import { useTranslation } from "react-i18next"; import _ from "lodash"; @@ -14,7 +14,6 @@ import { UsersIcon } from "@patternfly/react-icons"; import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation"; import { useAdminClient } from "../context/auth/AdminClient"; -import { useSubGroups } from "./SubGroupsContext"; import { useAlerts } from "../components/alert/Alerts"; import { useRealm } from "../context/realm-context/RealmContext"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; @@ -22,6 +21,7 @@ import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { GroupsModal } from "./GroupsModal"; import { getLastId } from "./groupIdUtils"; import { MoveGroupDialog } from "./MoveGroupDialog"; +import { useSubGroups } from "./SubGroupsContext"; type GroupTableData = GroupRepresentation & { membersLength?: number; @@ -38,7 +38,7 @@ export const GroupTable = () => { const [selectedRows, setSelectedRows] = useState([]); const [move, setMove] = useState(); - const { subGroups } = useSubGroups(); + const { subGroups, setSubGroups } = useSubGroups(); const [key, setKey] = useState(0); const refresh = () => setKey(new Date().getTime()); @@ -47,30 +47,15 @@ export const GroupTable = () => { const location = useLocation(); const id = getLastId(location.pathname); - useEffect(() => { - refresh(); - }, [subGroups]); - const getMembers = async (id: string) => { const response = await adminClient.groups.listMembers({ id }); return response ? response.length : 0; }; - const loader = async (first?: number, max?: number, search?: string) => { - const params: { [name: string]: string | number } = { - first: first!, - max: max!, - }; - - const searchParam = search || ""; - - if (searchParam) { - params.search = searchParam; - } - + const loader = async () => { const groupsData = id - ? (await adminClient.groups.findOne({ id, ...params })).subGroups - : await adminClient.groups.find(params); + ? (await adminClient.groups.findOne({ id })).subGroups + : await adminClient.groups.find(); if (groupsData) { const memberPromises = groupsData.map((group) => getMembers(group.id!)); @@ -111,7 +96,14 @@ export const GroupTable = () => { const GroupNameCell = (group: GroupTableData) => ( <> - + { + delete group.membersLength; + setSubGroups([...subGroups, group]); + }} + > {group.name} @@ -131,8 +123,7 @@ export const GroupTable = () => { return ( <> setSelectedRows([...rows])} canSelectAll={false} loader={loader} diff --git a/src/groups/GroupsSection.tsx b/src/groups/GroupsSection.tsx index f4e19d8d5a..2f2491b2bf 100644 --- a/src/groups/GroupsSection.tsx +++ b/src/groups/GroupsSection.tsx @@ -60,8 +60,8 @@ export const GroupsSection = () => { asyncStateFetch( async () => { const ids = getId(location.pathname); - const isNavigationStateInValid = - ids && ids.length !== subGroups.length + 1; + const isNavigationStateInValid = ids && ids.length > subGroups.length; + if (isNavigationStateInValid) { const groups: GroupRepresentation[] = []; for (const i of ids!) { @@ -69,20 +69,12 @@ export const GroupsSection = () => { if (group) groups.push(group); } return groups; - } else { - if (id) { - const group = await adminClient.groups.findOne({ id: id }); - if (group) { - return [...subGroups, group]; - } else { - return subGroups; - } - } else { - return subGroups; - } } + return []; + }, + (groups: GroupRepresentation[]) => { + if (groups.length) setSubGroups(groups); }, - (groups: GroupRepresentation[]) => setSubGroups(groups), errorHandler ), [id] diff --git a/src/groups/Members.tsx b/src/groups/Members.tsx index 487856425a..309a720abc 100644 --- a/src/groups/Members.tsx +++ b/src/groups/Members.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { useLocation } from "react-router-dom"; import { useTranslation } from "react-i18next"; import _ from "lodash"; @@ -35,7 +35,7 @@ export const Members = () => { const location = useLocation(); const id = getLastId(location.pathname); const [includeSubGroup, setIncludeSubGroup] = useState(false); - const { currentGroup, subGroups } = useSubGroups(); + const { currentGroup } = useSubGroups(); const [addMembers, setAddMembers] = useState(false); const [isKebabOpen, setIsKebabOpen] = useState(false); const [selectedRows, setSelectedRows] = useState([]); @@ -43,10 +43,6 @@ export const Members = () => { const [key, setKey] = useState(0); const refresh = () => setKey(new Date().getTime()); - useEffect(() => { - refresh(); - }, [id, subGroups, includeSubGroup]); - const getMembership = async (id: string) => await adminClient.users.listGroups({ id: id! }); @@ -107,7 +103,7 @@ export const Members = () => { /> )} { const clear = () => setSubGroups([]); const remove = (group: GroupRepresentation) => setSubGroups( - subGroups.slice( - 0, - subGroups.findIndex((g) => g.id === group.id) - ) + subGroups.slice(0, subGroups.findIndex((g) => g.id === group.id) + 1) ); const currentGroup = () => subGroups[subGroups.length - 1]; return (