Users(groups): list top level groups, implement direct membership check (#467)

* usergroups call wip

user groups

add user groups tab and list group data

clean up log stmts

add cypress test

clean up userGroups

remove comment

fix types

cypress test

fix lint and cypress test

lint

address PR feedback from Mark

clean up

remove component from viewheader

rebase and format

remove duplicate identifier

wrap groups in section

fix ts errors

add search functionality

remove comment

list groups initially

remove log stmt

wip parent groups listing

list parent groups

format

direct membership check

* format

* lint

* wip get intermediate groups

* wip get leafs

* wip list all groups

* wip list all paths

* listing for all groups completed

* remove comment

* wip filter out unjoinedf groups

* list all subgroups done

* format

* remove log stmts
This commit is contained in:
Eugenia 2021-04-01 14:47:05 -04:00 committed by GitHub
parent 4a2fd791e2
commit 5dbb6726ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -17,6 +17,7 @@ import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation"; import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
import { cellWidth } from "@patternfly/react-table"; import { cellWidth } from "@patternfly/react-table";
import { useErrorHandler } from "react-error-boundary"; import { useErrorHandler } from "react-error-boundary";
import _ from "lodash";
export const UserGroups = () => { export const UserGroups = () => {
const { t } = useTranslation("roles"); const { t } = useTranslation("roles");
@ -30,11 +31,15 @@ export const UserGroups = () => {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [isDirectMembership, setDirectMembership] = useState(false); const [isDirectMembership, setDirectMembership] = useState(true);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const alphabetize = (groupsList: GroupRepresentation[]) => {
return _.sortBy(groupsList, (group) => group.path?.toUpperCase());
};
const loader = async (first?: number, max?: number, search?: string) => { const loader = async (first?: number, max?: number, search?: string) => {
const params: { [name: string]: string | number } = { const params: { [name: string]: string | number } = {
first: first!, first: first!,
@ -54,7 +59,94 @@ export const UserGroups = () => {
return []; return [];
} }
return await adminClient.users.listGroups({ ...params, id }); const joinedGroups = await adminClient.users.listGroups({ ...params, id });
const allCreatedGroups = await adminClient.groups.find();
const getAllPaths = joinedGroups.reduce(
(acc: string[], cur) => (cur.path && acc.push(cur.path), acc),
[]
);
const parentGroupNames: string[] = [];
const allGroupMembership: string[] = [];
const slicedGroups: string[] = [];
const rootLevelGroups: GroupRepresentation[] = [...allCreatedGroups];
let allPaths: GroupRepresentation[] = [];
const getAllSubgroupPaths = (
o: any,
f: any,
context: GroupRepresentation[]
): GroupRepresentation[] => {
f(o, context);
if (typeof o !== "object") return context;
if (Array.isArray(o))
return o.forEach((e) => getAllSubgroupPaths(e, f, context)), context;
for (const prop in o) getAllSubgroupPaths(o[prop], f, context);
return context;
};
const arr = getAllSubgroupPaths(
rootLevelGroups,
(x: GroupRepresentation, context: GroupRepresentation[][]) => {
if (x !== undefined && x.subGroups) context.push(x.subGroups);
},
[]
);
const allSubgroups: GroupRepresentation[] = [].concat(...(arr as any));
allPaths = [...rootLevelGroups, ...allSubgroups];
getAllPaths.forEach((item) => {
const paths = item.split("/");
const groups: string[] = [];
paths.reduce((acc, value) => {
const path = acc + "/" + value;
groups.push(path);
return path;
}, "");
for (let i = 1; i < groups.length; i++) {
slicedGroups.push(groups[i].substring(1));
}
});
allGroupMembership.push(...slicedGroups);
allPaths.forEach((item) => {
if (item.subGroups!.length !== 0) {
allPaths.push(...item!.subGroups!);
}
});
allPaths = allPaths.filter((group) =>
allGroupMembership.includes(group.path as any)
);
const topLevelGroups = allCreatedGroups.filter((value) =>
parentGroupNames.includes(value.name!)
);
const subgroupArray: any[] = [];
topLevelGroups.forEach((group) => subgroupArray.push(group.subGroups));
const directMembership = joinedGroups.filter(
(value) => !topLevelGroups.includes(value)
);
const filterDupesfromGroups = allPaths.filter(
(thing, index, self) =>
index === self.findIndex((t) => t.name === thing.name)
);
if (isDirectMembership) {
return alphabetize(directMembership);
}
return alphabetize(filterDupesfromGroups);
}; };
useEffect(() => { useEffect(() => {