fix issue by introducing toolbar for fedrated user (#1417)

* fix issue by introducing toolbar for fedrated user

fixes: #1416

* code review
This commit is contained in:
Erik Jan de Wit 2021-10-27 11:19:13 +02:00 committed by GitHub
parent 56eb774dd3
commit d0c6bc4cc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -4,23 +4,29 @@ import {
ButtonVariant, ButtonVariant,
Dropdown, Dropdown,
DropdownItem, DropdownItem,
EmptyState,
InputGroup,
KebabToggle, KebabToggle,
Label, Label,
PageSection, PageSection,
Text, Text,
TextContent, TextContent,
TextInput,
Toolbar,
ToolbarContent,
ToolbarItem, ToolbarItem,
Tooltip, Tooltip,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { import {
ExclamationCircleIcon, ExclamationCircleIcon,
InfoCircleIcon, InfoCircleIcon,
SearchIcon,
WarningTriangleIcon, WarningTriangleIcon,
} from "@patternfly/react-icons"; } from "@patternfly/react-icons";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useHistory, useRouteMatch } from "react-router-dom"; import { Link, useHistory } from "react-router-dom";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
@ -32,6 +38,7 @@ import { emptyFormatter } from "../util";
import { toUser } from "./routes/User"; import { toUser } from "./routes/User";
import "./user-section.css"; import "./user-section.css";
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import { toAddUser } from "./routes/AddUser";
type BruteUser = UserRepresentation & { type BruteUser = UserRepresentation & {
brute?: Record<string, object>; brute?: Record<string, object>;
@ -43,8 +50,8 @@ export const UsersSection = () => {
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const { realm: realmName } = useRealm(); const { realm: realmName } = useRealm();
const history = useHistory(); const history = useHistory();
const { url } = useRouteMatch();
const [listUsers, setListUsers] = useState(false); const [listUsers, setListUsers] = useState(false);
const [searchUser, setSearchUser] = useState<string>();
const [realm, setRealm] = useState<RealmRepresentation>(); const [realm, setRealm] = useState<RealmRepresentation>();
const [kebabOpen, setKebabOpen] = useState(false); const [kebabOpen, setKebabOpen] = useState(false);
const [selectedRows, setSelectedRows] = useState<UserRepresentation[]>([]); const [selectedRows, setSelectedRows] = useState<UserRepresentation[]>([]);
@ -87,7 +94,7 @@ export const UsersSection = () => {
max: max!, max: max!,
}; };
const searchParam = search || ""; const searchParam = search || searchUser || "";
if (searchParam) { if (searchParam) {
params.search = searchParam; params.search = searchParam;
} }
@ -186,7 +193,60 @@ export const UsersSection = () => {
); );
}; };
const goToCreate = () => history.push(`${url}/add-user`); const goToCreate = () => history.push(toAddUser({ realm: realmName }));
const toolbar = (
<>
<ToolbarItem>
<Button data-testid="add-user" onClick={goToCreate}>
{t("addUser")}
</Button>
</ToolbarItem>
{!realm?.bruteForceProtected ? (
<ToolbarItem>
<Button
variant={ButtonVariant.plain}
onClick={toggleDeleteDialog}
isDisabled={selectedRows.length === 0}
>
{t("deleteUser")}
</Button>
</ToolbarItem>
) : (
<ToolbarItem>
<Dropdown
toggle={<KebabToggle onToggle={(open) => setKebabOpen(open)} />}
isOpen={kebabOpen}
isPlain
dropdownItems={[
<DropdownItem
key="deleteUser"
component="button"
isDisabled={selectedRows.length === 0}
onClick={() => {
toggleDeleteDialog();
setKebabOpen(false);
}}
>
{t("deleteUser")}
</DropdownItem>,
<DropdownItem
key="unlock"
component="button"
onClick={() => {
toggleUnlockUsersDialog();
setKebabOpen(false);
}}
>
{t("unlockAllUsers")}
</DropdownItem>,
]}
/>
</ToolbarItem>
)}
</>
);
return ( return (
<> <>
@ -208,9 +268,43 @@ export const UsersSection = () => {
onSelect={(rows) => setSelectedRows([...rows])} onSelect={(rows) => setSelectedRows([...rows])}
emptyState={ emptyState={
!listUsers ? ( !listUsers ? (
<TextContent className="kc-search-users-text"> <>
<Text>{t("searchForUserDescription")}</Text> <Toolbar>
</TextContent> <ToolbarContent>
<ToolbarItem>
<InputGroup>
<TextInput
name="search-input"
type="search"
aria-label={t("search")}
placeholder={t("users:searchForUser")}
onChange={(value) => {
setSearchUser(value);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
refresh();
}
}}
/>
<Button
variant={ButtonVariant.control}
aria-label={t("common:search")}
onClick={refresh}
>
<SearchIcon />
</Button>
</InputGroup>
</ToolbarItem>
{toolbar}
</ToolbarContent>
</Toolbar>
<EmptyState data-testid="empty-state" variant="large">
<TextContent className="kc-search-users-text">
<Text>{t("searchForUserDescription")}</Text>
</TextContent>
</EmptyState>
</>
) : ( ) : (
<ListEmptyState <ListEmptyState
message={t("noUsersFound")} message={t("noUsersFound")}
@ -220,61 +314,7 @@ export const UsersSection = () => {
/> />
) )
} }
toolbarItem={ toolbarItem={toolbar}
<>
<ToolbarItem>
<Button data-testid="add-user" onClick={goToCreate}>
{t("addUser")}
</Button>
</ToolbarItem>
{!realm?.bruteForceProtected && (
<ToolbarItem>
<Button
variant={ButtonVariant.plain}
onClick={toggleDeleteDialog}
isDisabled={selectedRows.length === 0}
>
{t("deleteUser")}
</Button>
</ToolbarItem>
)}
{realm?.bruteForceProtected && (
<ToolbarItem>
<Dropdown
toggle={
<KebabToggle onToggle={() => setKebabOpen(!kebabOpen)} />
}
isOpen={kebabOpen}
isPlain
dropdownItems={[
<DropdownItem
key="deleteUser"
component="button"
isDisabled={selectedRows.length === 0}
onClick={() => {
toggleDeleteDialog();
setKebabOpen(false);
}}
>
{t("deleteUser")}
</DropdownItem>,
<DropdownItem
key="unlock"
component="button"
onClick={() => {
toggleUnlockUsersDialog();
setKebabOpen(false);
}}
>
{t("unlockAllUsers")}
</DropdownItem>,
]}
/>
</ToolbarItem>
)}
</>
}
actions={[ actions={[
{ {
title: t("common:delete"), title: t("common:delete"),