Small fix on policies tab (#1246)
This commit is contained in:
parent
b9d1dbff4c
commit
cb86e5be3f
4 changed files with 72 additions and 65 deletions
|
@ -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";
|
||||||
|
|
|
@ -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",
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue