Small fix on policies tab (#1246)

This commit is contained in:
Erik Jan de Wit 2021-09-29 10:51:47 +02:00 committed by GitHub
parent b9d1dbff4c
commit cb86e5be3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 65 deletions

View file

@ -144,8 +144,8 @@ export default class RealmSettingsPage {
executeActionsSelectMenuList = "#kc-execute-actions-select-menu > div > ul"; executeActionsSelectMenuList = "#kc-execute-actions-select-menu > div > ul";
private createProfileBtn = "createProfile"; private createProfileBtn = "createProfile";
private formViewSelect = "formView-radioBtn"; private formViewSelect = "formView-profilesView";
private jsonEditorSelect = "formView-radioBtn"; private jsonEditorSelect = "jsonEditor-profilesView";
private newClientProfileNameInput = "client-profile-name"; private newClientProfileNameInput = "client-profile-name";
private newClientProfileDescriptionInput = "client-profile-description"; private newClientProfileDescriptionInput = "client-profile-description";
private saveNewClientProfileBtn = "saveCreateProfile"; private saveNewClientProfileBtn = "saveCreateProfile";

View file

@ -8,15 +8,15 @@ import {
FlexItem, FlexItem,
PageSection, PageSection,
Radio, Radio,
Spinner,
Title, Title,
ToolbarItem, ToolbarItem,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import "./RealmSettingsSection.css";
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAdminClient } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { upperCaseFormatter } from "../util"; import { upperCaseFormatter } from "../util";
import { CodeEditor, Language } from "@patternfly/react-code-editor"; import { CodeEditor, Language } from "@patternfly/react-code-editor";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
@ -24,23 +24,25 @@ import type ClientPolicyRepresentation from "@keycloak/keycloak-admin-client/lib
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import "./RealmSettingsSection.css";
export const PoliciesTab = () => { export const PoliciesTab = () => {
const { t } = useTranslation("realm-settings"); const { t } = useTranslation("realm-settings");
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [policies, setPolicies] = useState<ClientPolicyRepresentation[]>([]); const [policies, setPolicies] = useState<ClientPolicyRepresentation[]>();
const [selectedPolicy, setSelectedPolicy] = const [selectedPolicy, setSelectedPolicy] =
useState<ClientPolicyRepresentation>(); useState<ClientPolicyRepresentation>();
const loader = async () => { useFetch(
const policies = await adminClient.clientPolicies.listPolicies(); () => adminClient.clientPolicies.listPolicies(),
(policies) => setPolicies(policies.policies),
[]
);
setPolicies(policies.policies!); const loader = async () => policies ?? [];
return policies.policies!;
};
const code = useMemo(() => JSON.stringify(policies, null, 2), [policies]); const code = useMemo(() => JSON.stringify(policies, null, 2), [policies]);
@ -61,6 +63,13 @@ export const PoliciesTab = () => {
}, },
}); });
if (!policies) {
return (
<div className="pf-u-text-align-center">
<Spinner />
</div>
);
}
return ( return (
<> <>
<DeleteConfirm /> <DeleteConfirm />
@ -74,20 +83,20 @@ export const PoliciesTab = () => {
<FlexItem> <FlexItem>
<Radio <Radio
isChecked={!show} isChecked={!show}
name="formView" name="policiesView"
onChange={() => setShow(false)} onChange={() => setShow(false)}
label={t("policiesConfigTypes.formView")} label={t("policiesConfigTypes.formView")}
id="formView-radioBtn" id="formView-policiesView"
className="kc-form-radio-btn pf-u-mr-sm pf-u-ml-sm" className="kc-form-radio-btn pf-u-mr-sm pf-u-ml-sm"
/> />
</FlexItem> </FlexItem>
<FlexItem> <FlexItem>
<Radio <Radio
isChecked={show} isChecked={show}
name="jsonEditor" name="policiesView"
onChange={() => setShow(true)} onChange={() => setShow(true)}
label={t("policiesConfigTypes.jsonEditor")} label={t("policiesConfigTypes.jsonEditor")}
id="jsonEditor-radioBtn" id="jsonEditor-policiesView"
className="kc-editor-radio-btn" className="kc-editor-radio-btn"
/> />
</FlexItem> </FlexItem>
@ -96,6 +105,7 @@ export const PoliciesTab = () => {
<Divider /> <Divider />
{!show ? ( {!show ? (
<KeycloakDataTable <KeycloakDataTable
key={policies.length}
emptyState={ emptyState={
<ListEmptyState <ListEmptyState
message={t("realm-settings:noClientPolicies")} message={t("realm-settings:noClientPolicies")}
@ -103,9 +113,8 @@ export const PoliciesTab = () => {
primaryActionText={t("realm-settings:createClientPolicy")} primaryActionText={t("realm-settings:createClientPolicy")}
/> />
} }
ariaLabelKey="identity-providers:mappersList" ariaLabelKey="realm-settings:clientPolicies"
searchPlaceholderKey="realm-settings:clientPolicySearch" searchPlaceholderKey="realm-settings:clientPolicySearch"
isPaginated
loader={loader} loader={loader}
toolbarItem={ toolbarItem={
<ToolbarItem> <ToolbarItem>
@ -130,16 +139,13 @@ export const PoliciesTab = () => {
columns={[ columns={[
{ {
name: "name", name: "name",
displayKey: "common:name",
}, },
{ {
name: "enabled", name: "enabled",
displayKey: "common:enabled",
cellFormatters: [upperCaseFormatter()], cellFormatters: [upperCaseFormatter()],
}, },
{ {
name: "description", name: "description",
displayKey: "common:description",
}, },
]} ]}
/> />

View file

@ -6,6 +6,7 @@ import {
ButtonVariant, ButtonVariant,
Label, Label,
PageSection, PageSection,
Spinner,
ToolbarItem, ToolbarItem,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { Divider, Flex, FlexItem, Radio, Title } from "@patternfly/react-core"; import { Divider, Flex, FlexItem, Radio, Title } from "@patternfly/react-core";
@ -13,15 +14,16 @@ import { CodeEditor, Language } from "@patternfly/react-code-editor";
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAdminClient } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import "./RealmSettingsSection.css";
import { toNewClientProfile } from "./routes/NewClientProfile"; import { toNewClientProfile } from "./routes/NewClientProfile";
import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation"; import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation";
import "./RealmSettingsSection.css";
type ClientProfile = ClientProfileRepresentation & { type ClientProfile = ClientProfileRepresentation & {
global: boolean; global: boolean;
}; };
@ -38,12 +40,12 @@ export const ProfilesTab = () => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const loader = async () => { useFetch(
const allProfiles = await adminClient.clientPolicies.listProfiles({ () =>
realm, adminClient.clientPolicies.listProfiles({
includeGlobalProfiles: true, includeGlobalProfiles: true,
}); }),
(allProfiles) => {
setGlobalProfiles(allProfiles.globalProfiles); setGlobalProfiles(allProfiles.globalProfiles);
const globalProfiles = allProfiles.globalProfiles?.map( const globalProfiles = allProfiles.globalProfiles?.map(
@ -59,10 +61,12 @@ export const ProfilesTab = () => {
})); }));
const allClientProfiles = globalProfiles?.concat(profiles ?? []); const allClientProfiles = globalProfiles?.concat(profiles ?? []);
setTableProfiles(allClientProfiles); setTableProfiles(allClientProfiles || []);
},
[key]
);
return allClientProfiles ?? []; const loader = async () => tableProfiles ?? [];
};
const code = useMemo( const code = useMemo(
() => JSON.stringify(tableProfiles, null, 2), () => JSON.stringify(tableProfiles, null, 2),
@ -96,11 +100,18 @@ export const ProfilesTab = () => {
const cellFormatter = (row: ClientProfile) => ( const cellFormatter = (row: ClientProfile) => (
<Link to={""} key={row.name}> <Link to={""} key={row.name}>
{row.name} {""} {row.name} {row.global && <Label color="blue">{t("global")}</Label>}
{row.global && <Label color="blue">{t("global")}</Label>}
</Link> </Link>
); );
if (!tableProfiles) {
return (
<div className="pf-u-text-align-center">
<Spinner />
</div>
);
}
return ( return (
<> <>
<DeleteConfirm /> <DeleteConfirm />
@ -114,23 +125,23 @@ export const ProfilesTab = () => {
<FlexItem> <FlexItem>
<Radio <Radio
isChecked={!show} isChecked={!show}
name="formView" name="profilesView"
onChange={() => setShow(false)} onChange={() => setShow(false)}
label={t("profilesConfigTypes.formView")} label={t("profilesConfigTypes.formView")}
id="formView-radioBtn" id="formView-profilesView"
className="kc-form-radio-btn pf-u-mr-sm pf-u-ml-sm" className="kc-form-radio-btn pf-u-mr-sm pf-u-ml-sm"
data-testid="formView-radioBtn" data-testid="formView-profilesView"
/> />
</FlexItem> </FlexItem>
<FlexItem> <FlexItem>
<Radio <Radio
isChecked={show} isChecked={show}
name="jsonEditor" name="profilesView"
onChange={() => setShow(true)} onChange={() => setShow(true)}
label={t("profilesConfigTypes.jsonEditor")} label={t("profilesConfigTypes.jsonEditor")}
id="jsonEditor-radioBtn" id="jsonEditor-profilesView"
className="kc-editor-radio-btn" className="kc-editor-radio-btn"
data-testid="jsonEditor-radioBtn" data-testid="jsonEditor-profilesView"
/> />
</FlexItem> </FlexItem>
</Flex> </Flex>
@ -138,10 +149,9 @@ export const ProfilesTab = () => {
<Divider /> <Divider />
{!show ? ( {!show ? (
<KeycloakDataTable <KeycloakDataTable
key={key} key={tableProfiles.length}
ariaLabelKey="userEventsRegistered" ariaLabelKey="realm-settings:profiles"
searchPlaceholderKey="realm-settings:clientProfileSearch" searchPlaceholderKey="realm-settings:clientProfileSearch"
isPaginated
loader={loader} loader={loader}
toolbarItem={ toolbarItem={
<ToolbarItem> <ToolbarItem>

View file

@ -2,7 +2,7 @@ import { Breadcrumb, BreadcrumbItem, Spinner } from "@patternfly/react-core";
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import React, { useEffect, useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useAdminClient, useFetch } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
@ -58,15 +58,6 @@ export const RealmSettingsSection = () => {
setKey(key + 1); setKey(key + 1);
}; };
// delays realm fetch by 100ms in order to fetch newly updated value from server
useEffect(() => {
const update = async () => {
const realm = await adminClient.realms.findOne({ realm: realmName });
setRealm(realm);
};
setTimeout(update, 100);
}, [key]);
useFetch( useFetch(
async () => { async () => {
const realm = await adminClient.realms.findOne({ realm: realmName }); const realm = await adminClient.realms.findOne({ realm: realmName });
@ -83,7 +74,7 @@ export const RealmSettingsSection = () => {
setCurrentUser(user); setCurrentUser(user);
setRealm(realm); setRealm(realm);
}, },
[] [key]
); );
if (!realm || !realmComponents || !currentUser) { if (!realm || !realmComponents || !currentUser) {