wip add groups to user form
This commit is contained in:
parent
62b21dbfe1
commit
10b3619ae9
4 changed files with 216 additions and 31 deletions
|
@ -31,8 +31,9 @@ export type JoinGroupDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
toggleDialog: () => void;
|
toggleDialog: () => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
username: string;
|
username?: string;
|
||||||
onConfirm: (newGroups: Group[]) => void;
|
onConfirm: (newGroups: Group[]) => void;
|
||||||
|
chips?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Group = GroupRepresentation & {
|
type Group = GroupRepresentation & {
|
||||||
|
@ -45,6 +46,7 @@ export const JoinGroupDialog = ({
|
||||||
toggleDialog,
|
toggleDialog,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
username,
|
username,
|
||||||
|
chips,
|
||||||
}: JoinGroupDialogProps) => {
|
}: JoinGroupDialogProps) => {
|
||||||
const { t } = useTranslation("roles");
|
const { t } = useTranslation("roles");
|
||||||
const adminClient = useAdminClient();
|
const adminClient = useAdminClient();
|
||||||
|
@ -61,41 +63,67 @@ export const JoinGroupDialog = ({
|
||||||
|
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
|
|
||||||
useEffect(
|
if (id) {
|
||||||
() =>
|
useEffect(
|
||||||
asyncStateFetch(
|
() =>
|
||||||
async () => {
|
asyncStateFetch(
|
||||||
const existingUserGroups = await adminClient.users.listGroups({ id });
|
async () => {
|
||||||
const allGroups = await adminClient.groups.find();
|
const existingUserGroups = await adminClient.users.listGroups({
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
const allGroups = await adminClient.groups.find();
|
||||||
|
|
||||||
if (groupId) {
|
if (groupId) {
|
||||||
const group = await adminClient.groups.findOne({ id: groupId });
|
const group = await adminClient.groups.findOne({ id: groupId });
|
||||||
return { group, groups: group.subGroups! };
|
return { group, groups: group.subGroups! };
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
groups: _.differenceBy(allGroups, existingUserGroups, "id"),
|
groups: _.differenceBy(allGroups, existingUserGroups, "id"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async ({ group: selectedGroup, groups }) => {
|
async ({ group: selectedGroup, groups }) => {
|
||||||
if (selectedGroup) {
|
if (selectedGroup) {
|
||||||
setNavigation([...navigation, selectedGroup]);
|
setNavigation([...navigation, selectedGroup]);
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.forEach((group: Group) => {
|
groups.forEach((group: Group) => {
|
||||||
group.checked = !!selectedRows.find((r) => r.id === group.id);
|
group.checked = !!selectedRows.find((r) => r.id === group.id);
|
||||||
});
|
});
|
||||||
setGroups(groups);
|
setGroups(groups);
|
||||||
},
|
},
|
||||||
errorHandler
|
errorHandler
|
||||||
),
|
),
|
||||||
[groupId]
|
[groupId]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (!id) {
|
||||||
|
useEffect(() => {
|
||||||
|
return asyncStateFetch(
|
||||||
|
() => {
|
||||||
|
// adminClient.groups.find();
|
||||||
|
return Promise.resolve(adminClient.groups.find());
|
||||||
|
},
|
||||||
|
(groups) => {
|
||||||
|
console.log(groups);
|
||||||
|
console.log("potato", chips)
|
||||||
|
// setGroups(groups.filter((item) => item.name !== chips));
|
||||||
|
setGroups([...groups.filter((row) => !chips.includes(row.name))]);
|
||||||
|
|
||||||
|
// setupForm(realm);
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
variant={ModalVariant.small}
|
variant={ModalVariant.small}
|
||||||
title={`Join groups for user ${username}`}
|
title={
|
||||||
|
username ? `Join groups for user ${username}` : "Select groups to join"
|
||||||
|
}
|
||||||
isOpen={open}
|
isOpen={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
actions={[
|
actions={[
|
||||||
|
|
|
@ -2,10 +2,14 @@ import React, { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
ActionGroup,
|
ActionGroup,
|
||||||
Button,
|
Button,
|
||||||
|
Chip,
|
||||||
|
ChipGroup,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
|
InputGroup,
|
||||||
Select,
|
Select,
|
||||||
SelectOption,
|
SelectOption,
|
||||||
Switch,
|
Switch,
|
||||||
|
TextArea,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
@ -18,6 +22,8 @@ import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
|
import { asyncStateFetch, useAdminClient } from "../context/auth/AdminClient";
|
||||||
import { useErrorHandler } from "react-error-boundary";
|
import { useErrorHandler } from "react-error-boundary";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import { JoinGroupDialog } from "./JoinGroupDialog";
|
||||||
|
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
|
||||||
|
|
||||||
export type UserFormProps = {
|
export type UserFormProps = {
|
||||||
form: UseFormMethods<UserRepresentation>;
|
form: UseFormMethods<UserRepresentation>;
|
||||||
|
@ -45,6 +51,10 @@ export const UserForm = ({
|
||||||
|
|
||||||
const watchUsernameInput = watch("username");
|
const watchUsernameInput = watch("username");
|
||||||
const [timestamp, setTimestamp] = useState(null);
|
const [timestamp, setTimestamp] = useState(null);
|
||||||
|
const [chips, setChips] = useState<(string | undefined)[]>([]);
|
||||||
|
|
||||||
|
const [list, setList] = useState(false);
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editMode) {
|
if (editMode) {
|
||||||
|
@ -56,7 +66,7 @@ export const UserForm = ({
|
||||||
handleError
|
handleError
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [chips]);
|
||||||
|
|
||||||
const setupForm = (user: UserRepresentation) => {
|
const setupForm = (user: UserRepresentation) => {
|
||||||
reset();
|
reset();
|
||||||
|
@ -90,6 +100,82 @@ export const UserForm = ({
|
||||||
setRequiredUserActionsDropdownOpen(false);
|
setRequiredUserActionsDropdownOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteItem = (id: string) => {
|
||||||
|
const copyOfChips = chips;
|
||||||
|
console.log("care", id);
|
||||||
|
|
||||||
|
setChips(copyOfChips.filter((item) => item !== id));
|
||||||
|
|
||||||
|
// const index = copyOfChips.indexOf(id);
|
||||||
|
// if (index !== -1) {
|
||||||
|
// copyOfChips.splice(index, 1);
|
||||||
|
// setChips(copyOfChips);
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteCategory = () => {
|
||||||
|
setChips([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addChips = async (groups: GroupRepresentation[]): Promise<void> => {
|
||||||
|
const newGroups = groups;
|
||||||
|
|
||||||
|
const newGroupNames: (string | undefined)[] = newGroups!.map(
|
||||||
|
(item) => item.name
|
||||||
|
);
|
||||||
|
console.log(newGroupNames);
|
||||||
|
setChips([...chips!, ...newGroupNames]);
|
||||||
|
|
||||||
|
console.log("newGroups", newGroups)
|
||||||
|
|
||||||
|
newGroups.forEach(async (group) => {
|
||||||
|
// try {
|
||||||
|
await adminClient.users.addToGroup({
|
||||||
|
id: id,
|
||||||
|
groupId: group.id!,
|
||||||
|
});
|
||||||
|
// refresh();
|
||||||
|
// addAlert(t("users:addedGroupMembership"), AlertVariant.success);
|
||||||
|
// } catch (error) {
|
||||||
|
// // addAlert(
|
||||||
|
// // t("users:addedGroupMembershipError", { error }),
|
||||||
|
// // AlertVariant.danger
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("beep beep", adminClient.users.listGroups())
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(watchUsernameInput)
|
||||||
|
|
||||||
|
|
||||||
|
const addGroups = async (groups: GroupRepresentation[]): Promise<void> => {
|
||||||
|
const newGroups = groups;
|
||||||
|
|
||||||
|
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
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleModal = () => {
|
||||||
|
setOpen(!open);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormAccess
|
<FormAccess
|
||||||
isHorizontal
|
isHorizontal
|
||||||
|
@ -97,6 +183,15 @@ export const UserForm = ({
|
||||||
role="manage-users"
|
role="manage-users"
|
||||||
className="pf-u-mt-lg"
|
className="pf-u-mt-lg"
|
||||||
>
|
>
|
||||||
|
{open && (
|
||||||
|
<JoinGroupDialog
|
||||||
|
open={open}
|
||||||
|
onClose={() => setOpen(!open)}
|
||||||
|
onConfirm={editMode ? addGroups : addChips}
|
||||||
|
toggleDialog={() => toggleModal()}
|
||||||
|
chips={chips}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{editMode ? (
|
{editMode ? (
|
||||||
<>
|
<>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
@ -295,6 +390,53 @@ export const UserForm = ({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
{!editMode && (
|
||||||
|
<FormGroup
|
||||||
|
label={t("common:groups")}
|
||||||
|
fieldId="kc-groups"
|
||||||
|
validated={errors.requiredActions ? "error" : "default"}
|
||||||
|
helperTextInvalid={t("common:required")}
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("requiredUserActionsHelpText")}
|
||||||
|
forLabel={t("requiredUserActions")}
|
||||||
|
forID="required-user-actions-label"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="groups"
|
||||||
|
defaultValue={[]}
|
||||||
|
typeAheadAriaLabel="Select an action"
|
||||||
|
control={control}
|
||||||
|
render={() => (
|
||||||
|
<>
|
||||||
|
<InputGroup>
|
||||||
|
<ChipGroup categoryName={" "} onClick={deleteCategory}>
|
||||||
|
{chips.map((currentChip) => (
|
||||||
|
<Chip
|
||||||
|
key={currentChip}
|
||||||
|
onClick={() => deleteItem(currentChip!)}
|
||||||
|
>
|
||||||
|
{currentChip}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</ChipGroup>
|
||||||
|
<Button
|
||||||
|
id="kc-join-groups-button"
|
||||||
|
onClick={toggleModal}
|
||||||
|
variant="secondary"
|
||||||
|
// isDisabled={!watchUsernameInput}
|
||||||
|
>
|
||||||
|
{t("users:joinGroups")}
|
||||||
|
</Button>
|
||||||
|
</InputGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
<ActionGroup>
|
<ActionGroup>
|
||||||
<Button
|
<Button
|
||||||
data-testid={!editMode ? "create-user" : "save-user"}
|
data-testid={!editMode ? "create-user" : "save-user"}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"noGroups": "No groups",
|
"noGroups": "No groups",
|
||||||
"noGroupsText": "You haven't added this user to any groups. Join a group to get started.",
|
"noGroupsText": "You haven't added this user to any groups. Join a group to get started.",
|
||||||
"joinGroup": "Join Group",
|
"joinGroup": "Join Group",
|
||||||
|
"joinGroups": "Join Groups",
|
||||||
"searchForGroups": "Search for groups",
|
"searchForGroups": "Search for groups",
|
||||||
"leave": "Leave",
|
"leave": "Leave",
|
||||||
"leaveGroup": "Leave group {{name}}?",
|
"leaveGroup": "Leave group {{name}}?",
|
||||||
|
|
|
@ -6,3 +6,17 @@ button.pf-c-button.pf-m-primary.kc-join-group-button {
|
||||||
margin-left: var(--pf-global--spacer--md);
|
margin-left: var(--pf-global--spacer--md);
|
||||||
margin-right: var(--pf-global--spacer--xl);
|
margin-right: var(--pf-global--spacer--xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pf-c-chip-group,
|
||||||
|
.pf-c-chip-group__list {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button#kc-join-groups-button {
|
||||||
|
height: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-chip-group.pf-m-category {
|
||||||
|
margin-right: var(--pf-global--spacer--md);
|
||||||
|
padding: var(--pf-global--spacer--xs);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue