Users(groups): functionality for adding multiple users to groups (#534)
* add user to groups modal wip * add logic for selecting multiple groups, API does not support this yet * cfixcheckbox select bug * add functionality to select and add multiple groups * function name * update cypress test
This commit is contained in:
parent
ba4e576a2d
commit
820af6abca
3 changed files with 87 additions and 28 deletions
|
@ -10,6 +10,7 @@ import GroupModal from "../support/pages/admin_console/manage/groups/GroupModal"
|
|||
import UserGroupsPage from "../support/pages/admin_console/manage/users/UserGroupsPage";
|
||||
|
||||
let groupName = "group";
|
||||
let groupsList: string[] = [];
|
||||
|
||||
describe("Group creation", () => {
|
||||
const loginPage = new LoginPage();
|
||||
|
@ -24,7 +25,7 @@ describe("Group creation", () => {
|
|||
sidebarPage.goToGroups();
|
||||
});
|
||||
|
||||
it("Add group to be joined", () => {
|
||||
it("Add groups to be joined", () => {
|
||||
groupName += "_" + (Math.random() + 1).toString(36).substring(7);
|
||||
|
||||
groupModal
|
||||
|
@ -32,6 +33,21 @@ describe("Group creation", () => {
|
|||
.fillGroupForm(groupName)
|
||||
.clickCreate();
|
||||
|
||||
groupsList = [...groupsList, groupName];
|
||||
masthead.checkNotificationMessage("Group created");
|
||||
|
||||
sidebarPage.goToGroups();
|
||||
listingPage.searchItem(groupName, false).itemExist(groupName);
|
||||
|
||||
groupName = "group";
|
||||
groupName += "_" + (Math.random() + 1).toString(36).substring(7);
|
||||
|
||||
groupModal
|
||||
.open("openCreateGroupModal")
|
||||
.fillGroupForm(groupName)
|
||||
.clickCreate();
|
||||
|
||||
groupsList = [...groupsList, groupName];
|
||||
masthead.checkNotificationMessage("Group created");
|
||||
|
||||
sidebarPage.goToGroups();
|
||||
|
@ -101,7 +117,7 @@ describe("Users test", () => {
|
|||
listingPage.searchItem(itemId).itemExist(itemId);
|
||||
});
|
||||
|
||||
it("Add user to group test", function () {
|
||||
it("Add user to groups test", function () {
|
||||
// Go to user groups
|
||||
|
||||
listingPage.searchItem(itemId).itemExist(itemId);
|
||||
|
@ -109,7 +125,11 @@ describe("Users test", () => {
|
|||
|
||||
userGroupsPage.goToGroupsTab();
|
||||
userGroupsPage.toggleAddGroupModal();
|
||||
cy.getId(`${groupName}`).click();
|
||||
|
||||
groupsList.forEach((element) => {
|
||||
cy.getId(`${element}-check`).click();
|
||||
});
|
||||
|
||||
userGroupsPage.joinGroup();
|
||||
|
||||
cy.wait(1000);
|
||||
|
@ -150,4 +170,4 @@ describe("Users test", () => {
|
|||
listingPage.itemExist(itemId, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
DataList,
|
||||
DataListAction,
|
||||
DataListCell,
|
||||
DataListCheck,
|
||||
DataListItem,
|
||||
DataListItemCells,
|
||||
DataListItemRow,
|
||||
|
@ -23,14 +24,19 @@ import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
|
|||
import { AngleRightIcon, SearchIcon } from "@patternfly/react-icons";
|
||||
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
|
||||
import { useErrorHandler } from "react-error-boundary";
|
||||
import { useParams } from "react-router-dom";
|
||||
import _ from "lodash";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
export type JoinGroupDialogProps = {
|
||||
open: boolean;
|
||||
toggleDialog: () => void;
|
||||
onClose: () => void;
|
||||
onConfirm: (newGroup: GroupRepresentation) => void;
|
||||
username: string;
|
||||
onConfirm: (newGroups: Group[]) => void;
|
||||
};
|
||||
|
||||
type Group = GroupRepresentation & {
|
||||
checked?: boolean;
|
||||
};
|
||||
|
||||
export const JoinGroupDialog = ({
|
||||
|
@ -42,11 +48,12 @@ export const JoinGroupDialog = ({
|
|||
}: JoinGroupDialogProps) => {
|
||||
const { t } = useTranslation("roles");
|
||||
const adminClient = useAdminClient();
|
||||
const [selectedRows, setSelectedRows] = useState<Group[]>([]);
|
||||
|
||||
const errorHandler = useErrorHandler();
|
||||
|
||||
const [navigation, setNavigation] = useState<GroupRepresentation[]>([]);
|
||||
const [groups, setGroups] = useState<GroupRepresentation[]>([]);
|
||||
const [navigation, setNavigation] = useState<Group[]>([]);
|
||||
const [groups, setGroups] = useState<Group[]>([]);
|
||||
const [filtered, setFiltered] = useState<GroupRepresentation[]>();
|
||||
const [filter, setFilter] = useState("");
|
||||
|
||||
|
@ -75,6 +82,9 @@ export const JoinGroupDialog = ({
|
|||
setNavigation([...navigation, selectedGroup]);
|
||||
}
|
||||
|
||||
groups.forEach((group: Group) => {
|
||||
group.checked = !!selectedRows.find((r) => r.id === group.id);
|
||||
});
|
||||
setGroups(groups);
|
||||
},
|
||||
errorHandler
|
||||
|
@ -96,8 +106,9 @@ export const JoinGroupDialog = ({
|
|||
form="group-form"
|
||||
onClick={() => {
|
||||
toggleDialog();
|
||||
onConfirm(navigation[navigation.length - 1]);
|
||||
onConfirm(selectedRows);
|
||||
}}
|
||||
isDisabled={selectedRows.length === 0}
|
||||
>
|
||||
{t("users:Join")}
|
||||
</Button>,
|
||||
|
@ -166,17 +177,43 @@ export const JoinGroupDialog = ({
|
|||
</ToolbarContent>
|
||||
</Toolbar>
|
||||
<DataList
|
||||
onSelectDataListItem={(value) => setGroupId(value)}
|
||||
onSelectDataListItem={(value) => {
|
||||
setGroupId(value);
|
||||
}}
|
||||
aria-label={t("groups")}
|
||||
isCompact
|
||||
>
|
||||
{(filtered || groups).map((group) => (
|
||||
{(filtered || groups).map((group: Group) => (
|
||||
<DataListItem
|
||||
aria-labelledby={group.name}
|
||||
key={group.id}
|
||||
id={group.id}
|
||||
onClick={(e) => {
|
||||
if ((e.target as HTMLInputElement).type !== "checkbox") {
|
||||
setGroupId(group.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DataListItemRow data-testid={group.name}>
|
||||
<DataListCheck
|
||||
data-testid={`${group.name}-check`}
|
||||
isChecked={group.checked}
|
||||
onChange={(checked, e) => {
|
||||
group.checked = (e.target as HTMLInputElement).checked;
|
||||
let newSelectedRows: Group[];
|
||||
if (!group.checked) {
|
||||
newSelectedRows = selectedRows.filter(
|
||||
(r) => r.id !== group.id
|
||||
);
|
||||
} else if (group.checked) {
|
||||
newSelectedRows = [...selectedRows, group];
|
||||
}
|
||||
|
||||
setSelectedRows(newSelectedRows!);
|
||||
}}
|
||||
aria-labelledby="data-list-check"
|
||||
/>
|
||||
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key={`name-${group.id}`}>
|
||||
|
|
|
@ -265,23 +265,25 @@ export const UserGroups = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const addGroup = async (group: GroupRepresentation): Promise<void> => {
|
||||
const newGroup = group;
|
||||
const addGroups = async (groups: GroupRepresentation[]): Promise<void> => {
|
||||
const newGroups = groups;
|
||||
|
||||
try {
|
||||
await adminClient.users.addToGroup({
|
||||
id: id,
|
||||
groupId: newGroup.id!,
|
||||
});
|
||||
setList(true);
|
||||
refresh();
|
||||
addAlert(t("users:addedGroupMembership"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(
|
||||
t("users:addedGroupMembershipError", { error }),
|
||||
AlertVariant.danger
|
||||
);
|
||||
}
|
||||
newGroups.forEach(async (group) => {
|
||||
try {
|
||||
await adminClient.users.addToGroup({
|
||||
id: id,
|
||||
groupId: group.id!,
|
||||
});
|
||||
setList(true);
|
||||
refresh();
|
||||
addAlert(t("users:addedGroupMembership"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(
|
||||
t("users:addedGroupMembershipError", { error }),
|
||||
AlertVariant.danger
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -292,7 +294,7 @@ export const UserGroups = () => {
|
|||
<JoinGroupDialog
|
||||
open={open}
|
||||
onClose={() => setOpen(!open)}
|
||||
onConfirm={addGroup}
|
||||
onConfirm={addGroups}
|
||||
toggleDialog={() => toggleModal()}
|
||||
username={username}
|
||||
/>
|
||||
|
|
Loading…
Reference in a new issue