fixing uxd issues (#477)

* fixing uxd issues

* add select all checkbox

* added intermidate "style" to select all checkbox
This commit is contained in:
Erik Jan de Wit 2021-04-07 07:42:30 +02:00 committed by GitHub
parent dd19613557
commit 2417c285e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 62 deletions

View file

@ -312,7 +312,6 @@ export const ClientDetails = () => {
>
<Tabs
activeKey={activeTab2}
isSecondary
onSelect={(_, key) => setActiveTab2(key as number)}
>
<Tab

View file

@ -34,6 +34,7 @@
"client": "Client scope",
"assigned": "Assigned type"
},
"assignedClientScope": "Assigned client scope",
"assignedType": "Assigned type",
"hideInheritedRoles": "Hide inherited roles",
"inherentFrom": "Inherited from",

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import {
Button,
@ -10,18 +10,13 @@ import {
DropdownDirection,
} from "@patternfly/react-core";
import { CaretUpIcon } from "@patternfly/react-icons";
import {
Table,
TableBody,
TableHeader,
TableVariant,
} from "@patternfly/react-table";
import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation";
import {
ClientScopeType,
clientScopeTypesDropdown,
} from "../../components/client-scope/ClientScopeTypes";
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
export type AddScopeDialogProps = {
clientScopes: ClientScopeRepresentation[];
@ -32,11 +27,7 @@ export type AddScopeDialogProps = {
) => void;
};
type Row = {
selected: boolean;
scope: ClientScopeRepresentation;
cells: (string | undefined)[];
};
import "./client-scopes.css";
export const AddScopeDialog = ({
clientScopes,
@ -46,26 +37,14 @@ export const AddScopeDialog = ({
}: AddScopeDialogProps) => {
const { t } = useTranslation("clients");
const [addToggle, setAddToggle] = useState(false);
const [rows, setRows] = useState<Row[]>([]);
const [rows, setRows] = useState<ClientScopeRepresentation[]>([]);
useEffect(() => {
setRows(
clientScopes.map((scope) => {
return {
selected: false,
scope,
cells: [scope.name, scope.description],
};
})
);
}, [clientScopes]);
const loader = () => Promise.resolve(clientScopes);
const action = (scope: ClientScopeType) => {
const scopes = rows
.filter((row) => row.selected)
.map((row) => {
return { scope: row.scope, type: scope };
});
const scopes = rows.map((row) => {
return { scope: row, type: scope };
});
onAdd(scopes);
setAddToggle(false);
toggleDialog();
@ -79,12 +58,14 @@ export const AddScopeDialog = ({
onClose={toggleDialog}
actions={[
<Dropdown
className="keycloak__client-scopes-add__add-dropdown"
id="add-dropdown"
key="add-dropdown"
direction={DropdownDirection.up}
isOpen={addToggle}
toggle={
<DropdownToggle
isDisabled={rows.length === 0}
onToggle={() => setAddToggle(!addToggle)}
isPrimary
toggleIndicator={CaretUpIcon}
@ -100,12 +81,7 @@ export const AddScopeDialog = ({
key="cancel"
variant={ButtonVariant.secondary}
onClick={() => {
setRows(
rows.map((row) => {
row.selected = false;
return row;
})
);
setRows([]);
toggleDialog();
}}
>
@ -113,28 +89,21 @@ export const AddScopeDialog = ({
</Button>,
]}
>
<Table
variant={TableVariant.compact}
cells={[t("common:name"), t("common:description")]}
onSelect={(_, isSelected, rowIndex) => {
if (rowIndex === -1) {
setRows(
rows.map((row) => {
row.selected = isSelected;
return row;
})
);
} else {
rows[rowIndex].selected = isSelected;
setRows([...rows]);
}
}}
rows={rows}
aria-label={t("chooseAMapperType")}
>
<TableHeader />
<TableBody />
</Table>
<KeycloakDataTable
loader={loader}
ariaLabelKey="client-scopes:chooseAMapperType"
searchPlaceholderKey="client-scopes:searchFor"
canSelectAll
onSelect={(rows) => setRows(rows)}
columns={[
{
name: "name",
},
{
name: "description",
},
]}
/>
</Modal>
);
};

View file

@ -27,6 +27,8 @@ import {
import { useAlerts } from "../../components/alert/Alerts";
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
import "./client-scopes.css";
export type ClientScopesProps = {
clientId: string;
protocol: string;
@ -197,9 +199,11 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
loader={loader}
ariaLabelKey="clients:clientScopeList"
searchPlaceholderKey="clients:searchByName"
canSelectAll
onSelect={(rows) => setSelectedRows([...rows])}
searchTypeComponent={
<Dropdown
className="keycloak__client-scopes__searchtype"
toggle={
<DropdownToggle
id="toggle-id"
@ -245,6 +249,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
key="add-dropdown"
isOpen={addToggle}
selections={[]}
isDisabled={selectedRows.length === 0}
placeholderText={t("changeTypeTo")}
onToggle={() => setAddToggle(!addToggle)}
onSelect={async (_, value) => {
@ -323,6 +328,7 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
columns={[
{
name: "name",
displayKey: "clients:assignedClientScope",
},
{
name: "type",
@ -331,6 +337,24 @@ export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => {
},
{ name: "description" },
]}
actions={[
{
title: t("common:remove"),
onRowClick: async (row) => {
try {
await removeScope(adminClient, clientId, row, row.type);
addAlert(t("clientScopeRemoveSuccess"), AlertVariant.success);
refresh();
} catch (error) {
addAlert(
t("clientScopeRemoveError", { error }),
AlertVariant.danger
);
}
return true;
},
},
]}
emptyState={
<ListEmptyState
message={t("clients:emptyClientScopes")}

View file

@ -0,0 +1,8 @@
.keycloak__client-scopes__searchtype button {
width: 200px;
}
.keycloak__client-scopes-add__add-dropdown {
margin-right: var(--pf-global--spacer--md);
}

View file

@ -153,6 +153,22 @@ export function KeycloakDataTable<T>({
const refresh = () => setKey(new Date().getTime());
const handleError = useErrorHandler();
useEffect(() => {
if (canSelectAll) {
const checkboxes = document
.getElementsByClassName("pf-c-table__check")
.item(0);
if (checkboxes) {
const checkAllCheckbox = checkboxes.children!.item(
0
)! as HTMLInputElement;
checkAllCheckbox.indeterminate =
selected.length > 0 &&
selected.length < (filteredData || rows)!.length;
}
}
}, [selected]);
useEffect(() => {
return asyncStateFetch(
async () => {
@ -242,25 +258,26 @@ export function KeycloakDataTable<T>({
);
const _onSelect = (isSelected: boolean, rowIndex: number) => {
const data = filteredData || rows;
if (rowIndex === -1) {
setRows(
rows!.map((row) => {
data!.map((row) => {
row.selected = isSelected;
return row;
})
);
} else {
rows![rowIndex].selected = isSelected;
data![rowIndex].selected = isSelected;
setRows([...rows!]);
}
const difference = _.differenceBy(
selected,
rows!.map((row) => row.data),
data!.map((row) => row.data),
"id"
);
const selectedRows = [
...difference,
...rows!.filter((row) => row.selected).map((row) => row.data),
...data!.filter((row) => row.selected).map((row) => row.data),
];
setSelected(selectedRows);
onSelect!(selectedRows);