Allow adding permitted groups to new users with fine-grained (#3179)
permissions.
This commit is contained in:
parent
7e7c23abe7
commit
298411261a
5 changed files with 15 additions and 10 deletions
|
@ -27,6 +27,7 @@ export type GroupPickerDialogProps = {
|
||||||
type: "selectOne" | "selectMany";
|
type: "selectOne" | "selectMany";
|
||||||
filterGroups?: string[];
|
filterGroups?: string[];
|
||||||
text: { title: string; ok: string };
|
text: { title: string; ok: string };
|
||||||
|
canBrowse?: boolean;
|
||||||
onConfirm: (groups: GroupRepresentation[] | undefined) => void;
|
onConfirm: (groups: GroupRepresentation[] | undefined) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
};
|
};
|
||||||
|
@ -40,6 +41,7 @@ export const GroupPickerDialog = ({
|
||||||
type,
|
type,
|
||||||
filterGroups,
|
filterGroups,
|
||||||
text,
|
text,
|
||||||
|
canBrowse = true,
|
||||||
onClose,
|
onClose,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
}: GroupPickerDialogProps) => {
|
}: GroupPickerDialogProps) => {
|
||||||
|
@ -282,7 +284,7 @@ export const GroupPickerDialog = ({
|
||||||
aria-label={t("groupName")}
|
aria-label={t("groupName")}
|
||||||
isPlainButtonAction
|
isPlainButtonAction
|
||||||
>
|
>
|
||||||
{((hasSubgroups(group) && filter === "") ||
|
{((hasSubgroups(group) && filter === "" && canBrowse) ||
|
||||||
type === "selectOne") && (
|
type === "selectOne") && (
|
||||||
<Button
|
<Button
|
||||||
isDisabled
|
isDisabled
|
||||||
|
|
|
@ -28,6 +28,7 @@ import useFormatDate from "../utils/useFormatDate";
|
||||||
import { GroupPickerDialog } from "../components/group/GroupPickerDialog";
|
import { GroupPickerDialog } from "../components/group/GroupPickerDialog";
|
||||||
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||||
import type RequiredActionProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation";
|
import type RequiredActionProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation";
|
||||||
|
import { useAccess } from "../context/access/Access";
|
||||||
|
|
||||||
export type BruteForced = {
|
export type BruteForced = {
|
||||||
isBruteForceProtected?: boolean;
|
isBruteForceProtected?: boolean;
|
||||||
|
@ -61,6 +62,8 @@ export const UserForm = ({
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
const { addAlert, addError } = useAlerts();
|
const { addAlert, addError } = useAlerts();
|
||||||
|
const { hasAccess } = useAccess();
|
||||||
|
const isManager = hasAccess("manage-users");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
@ -144,7 +147,7 @@ export const UserForm = ({
|
||||||
<FormAccess
|
<FormAccess
|
||||||
isHorizontal
|
isHorizontal
|
||||||
onSubmit={handleSubmit(save)}
|
onSubmit={handleSubmit(save)}
|
||||||
role="manage-users"
|
role="query-users"
|
||||||
fineGrainedAccess={user?.access?.manage}
|
fineGrainedAccess={user?.access?.manage}
|
||||||
className="pf-u-mt-lg"
|
className="pf-u-mt-lg"
|
||||||
>
|
>
|
||||||
|
@ -155,6 +158,7 @@ export const UserForm = ({
|
||||||
title: "users:selectGroups",
|
title: "users:selectGroups",
|
||||||
ok: "users:join",
|
ok: "users:join",
|
||||||
}}
|
}}
|
||||||
|
canBrowse={isManager}
|
||||||
onConfirm={(groups) => {
|
onConfirm={(groups) => {
|
||||||
user?.id ? addGroups(groups || []) : addChips(groups || []);
|
user?.id ? addGroups(groups || []) : addChips(groups || []);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||||
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
||||||
import { useAdminClient } from "../context/auth/AdminClient";
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
import { emptyFormatter } from "../util";
|
import { emptyFormatter } from "../util";
|
||||||
|
import { useAccess } from "../context/access/Access";
|
||||||
|
|
||||||
type UserGroupsProps = {
|
type UserGroupsProps = {
|
||||||
user: UserRepresentation;
|
user: UserRepresentation;
|
||||||
|
@ -45,6 +46,9 @@ export const UserGroups = ({ user }: UserGroupsProps) => {
|
||||||
|
|
||||||
const { enabled } = useHelp();
|
const { enabled } = useHelp();
|
||||||
|
|
||||||
|
const { hasAccess } = useAccess();
|
||||||
|
const isManager = hasAccess("manage-users");
|
||||||
|
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
const alphabetize = (groupsList: GroupRepresentation[]) => {
|
const alphabetize = (groupsList: GroupRepresentation[]) => {
|
||||||
return sortBy(groupsList, (group) => group.path?.toUpperCase());
|
return sortBy(groupsList, (group) => group.path?.toUpperCase());
|
||||||
|
@ -254,6 +258,7 @@ export const UserGroups = ({ user }: UserGroupsProps) => {
|
||||||
title: t("joinGroupsFor", { username: user.username }),
|
title: t("joinGroupsFor", { username: user.username }),
|
||||||
ok: "users:join",
|
ok: "users:join",
|
||||||
}}
|
}}
|
||||||
|
canBrowse={isManager}
|
||||||
onClose={() => setOpen(false)}
|
onClose={() => setOpen(false)}
|
||||||
onConfirm={(groups) => {
|
onConfirm={(groups) => {
|
||||||
addGroups(groups || []);
|
addGroups(groups || []);
|
||||||
|
|
|
@ -94,15 +94,9 @@ const UsersTabs = () => {
|
||||||
addAlert(t("userSaved"), AlertVariant.success);
|
addAlert(t("userSaved"), AlertVariant.success);
|
||||||
refresh();
|
refresh();
|
||||||
} else {
|
} else {
|
||||||
|
user.groups = addedGroups.map((group) => group.path!);
|
||||||
const createdUser = await adminClient.users.create(user);
|
const createdUser = await adminClient.users.create(user);
|
||||||
|
|
||||||
addedGroups.forEach(async (group) => {
|
|
||||||
await adminClient.users.addToGroup({
|
|
||||||
id: createdUser.id!,
|
|
||||||
groupId: group.id!,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
addAlert(t("userCreated"), AlertVariant.success);
|
addAlert(t("userCreated"), AlertVariant.success);
|
||||||
navigate(toUser({ id: createdUser.id, realm, tab: "settings" }));
|
navigate(toUser({ id: createdUser.id, realm, tab: "settings" }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const AddUserRoute: RouteDef = {
|
||||||
path: "/:realm/users/add-user",
|
path: "/:realm/users/add-user",
|
||||||
component: lazy(() => import("../UsersTabs")),
|
component: lazy(() => import("../UsersTabs")),
|
||||||
breadcrumb: (t) => t("users:createUser"),
|
breadcrumb: (t) => t("users:createUser"),
|
||||||
access: "manage-users",
|
access: ["query-users", "query-groups"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toAddUser = (params: AddUserParams): Partial<Path> => ({
|
export const toAddUser = (params: AddUserParams): Partial<Path> => ({
|
||||||
|
|
Loading…
Reference in a new issue