Add filter capability to keys section in realm settings (#666)

* rebase

* fix empty state text
This commit is contained in:
Jenny 2021-06-08 11:45:37 -04:00 committed by GitHub
parent f322edec10
commit d77d9a2a63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 155 additions and 8 deletions

View file

@ -30,7 +30,17 @@ describe("Realm settings", () => {
await new AdminClient().deleteRealm(realmName); await new AdminClient().deleteRealm(realmName);
}); });
it("Go to general tab", () => { const goToKeys = () => {
const keysUrl = "/auth/admin/realms/master/keys";
cy.intercept(keysUrl).as("keysFetch");
cy.getId("rs-keys-tab").click();
cy.wait(10000);
cy.getId("rs-keys-list-tab").click();
return this;
};
it("Go to general tab", function () {
sidebarPage.goToRealmSettings(); sidebarPage.goToRealmSettings();
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch); realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
realmSettingsPage.save(realmSettingsPage.generalSaveBtn); realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
@ -134,21 +144,18 @@ describe("Realm settings", () => {
cy.getId("option-aes-generated").click(); cy.getId("option-aes-generated").click();
realmSettingsPage.enterConsoleDisplayName("test_aes-generated"); realmSettingsPage.enterConsoleDisplayName("test_aes-generated");
cy.wait(200);
realmSettingsPage.addProvider(); realmSettingsPage.addProvider();
realmSettingsPage.toggleAddProviderDropdown(); realmSettingsPage.toggleAddProviderDropdown();
cy.getId("option-ecdsa-generated").click(); cy.getId("option-ecdsa-generated").click();
realmSettingsPage.enterConsoleDisplayName("test_ecdsa-generated"); realmSettingsPage.enterConsoleDisplayName("test_ecdsa-generated");
cy.wait(200);
realmSettingsPage.addProvider(); realmSettingsPage.addProvider();
realmSettingsPage.toggleAddProviderDropdown(); realmSettingsPage.toggleAddProviderDropdown();
cy.getId("option-hmac-generated").click(); cy.getId("option-hmac-generated").click();
realmSettingsPage.enterConsoleDisplayName("test_hmac-generated"); realmSettingsPage.enterConsoleDisplayName("test_hmac-generated");
cy.wait(200);
realmSettingsPage.addProvider(); realmSettingsPage.addProvider();
realmSettingsPage.toggleAddProviderDropdown(); realmSettingsPage.toggleAddProviderDropdown();
@ -157,4 +164,11 @@ describe("Realm settings", () => {
realmSettingsPage.enterConsoleDisplayName("test_rsa-generated"); realmSettingsPage.enterConsoleDisplayName("test_rsa-generated");
realmSettingsPage.addProvider(); realmSettingsPage.addProvider();
}); });
it("Test keys", function () {
sidebarPage.goToRealmSettings();
goToKeys();
realmSettingsPage.testSelectFilter();
});
}); });

View file

@ -32,6 +32,9 @@ export default class RealmSettingsPage {
enableEvents = "eventsEnabled"; enableEvents = "eventsEnabled";
eventsUserSave = "save-user"; eventsUserSave = "save-user";
eventTypeColumn = 'tbody > tr > [data-label="Event saved type"]'; eventTypeColumn = 'tbody > tr > [data-label="Event saved type"]';
filterSelectMenu = ".kc-filter-type-select";
passiveKeysOption = "passive-keys-option";
disabledKeysOption = "disabled-keys-option";
selectLoginThemeType(themeType: string) { selectLoginThemeType(themeType: string) {
const themesUrl = "/auth/admin/realms/master/themes"; const themesUrl = "/auth/admin/realms/master/themes";
@ -89,6 +92,13 @@ export default class RealmSettingsPage {
return this; return this;
} }
testSelectFilter() {
cy.get(this.filterSelectMenu).first().click();
cy.getId(this.passiveKeysOption).click();
cy.get(this.filterSelectMenu).first().click();
cy.getId(this.disabledKeysOption).click();
}
toggleSwitch(switchName: string) { toggleSwitch(switchName: string) {
cy.getId(switchName).click({ force: true }); cy.getId(switchName).click({ force: true });

View file

@ -1,7 +1,14 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useHistory, useRouteMatch } from "react-router-dom"; import { useHistory, useRouteMatch } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button, ButtonVariant, PageSection } from "@patternfly/react-core"; import {
Button,
ButtonVariant,
PageSection,
Select,
SelectOption,
SelectVariant,
} from "@patternfly/react-core";
import { cellWidth } from "@patternfly/react-table"; import { cellWidth } from "@patternfly/react-table";
import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation"; import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
@ -14,6 +21,7 @@ import { useAdminClient } from "../context/auth/AdminClient";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import "./RealmSettingsSection.css"; import "./RealmSettingsSection.css";
import { FilterIcon } from "@patternfly/react-icons";
type KeyData = KeyMetadataRepresentation & { type KeyData = KeyMetadataRepresentation & {
provider?: string; provider?: string;
@ -28,8 +36,15 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
const history = useHistory(); const history = useHistory();
const { url } = useRouteMatch(); const { url } = useRouteMatch();
const [key, setKey] = useState(0);
const [publicKey, setPublicKey] = useState(""); const [publicKey, setPublicKey] = useState("");
const [certificate, setCertificate] = useState(""); const [certificate, setCertificate] = useState("");
const [filterDropdownOpen, setFilterDropdownOpen] = useState(false);
const [filterType, setFilterType] = useState("Active keys");
const refresh = () => {
setKey(new Date().getTime());
};
const adminClient = useAdminClient(); const adminClient = useAdminClient();
const { realm: realmName } = useRealm(); const { realm: realmName } = useRealm();
@ -38,6 +53,7 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
const keysMetaData = await adminClient.realms.getKeys({ const keysMetaData = await adminClient.realms.getKeys({
realm: realmName, realm: realmName,
}); });
const keys = keysMetaData.keys; const keys = keysMetaData.keys;
return keys?.map((key) => { return keys?.map((key) => {
@ -48,6 +64,54 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
})!; })!;
}; };
const activeKeysLoader = async () => {
const keysMetaData = await adminClient.realms.getKeys({
realm: realmName,
});
const keys = keysMetaData.keys;
const activeKeysCopy = keys!.filter((i) => i.status === "ACTIVE");
return activeKeysCopy?.map((key) => {
const provider = realmComponents!.find(
(component: ComponentRepresentation) => component.id === key.providerId
);
return { ...key, provider: provider?.name } as KeyData;
})!;
};
const passiveKeysLoader = async () => {
const keysMetaData = await adminClient.realms.getKeys({
realm: realmName,
});
const keys = keysMetaData.keys;
const passiveKeys = keys!.filter((i) => i.status === "PASSIVE");
return passiveKeys?.map((key) => {
const provider = realmComponents!.find(
(component: ComponentRepresentation) => component.id === key.providerId
);
return { ...key, provider: provider?.name } as KeyData;
})!;
};
const disabledKeysLoader = async () => {
const keysMetaData = await adminClient.realms.getKeys({
realm: realmName,
});
const keys = keysMetaData.keys;
const disabledKeys = keys!.filter((i) => i.status === "DISABLED");
return disabledKeys?.map((key) => {
const provider = realmComponents!.find(
(component: ComponentRepresentation) => component.id === key.providerId
);
return { ...key, provider: provider?.name } as KeyData;
})!;
};
const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({ const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({
titleKey: t("realm-settings:publicKeys").slice(0, -1), titleKey: t("realm-settings:publicKeys").slice(0, -1),
messageKey: publicKey, messageKey: publicKey,
@ -116,6 +180,25 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
} }
}; };
const options = [
<SelectOption
key={1}
data-testid="active-keys-option"
value={t("realm-settings:activeKeys")}
isPlaceholder
/>,
<SelectOption
data-testid="passive-keys-option"
key={2}
value={t("realm-settings:passiveKeys")}
/>,
<SelectOption
data-testid="disabled-keys-option"
key={3}
value={t("realm-settings:disabledKeys")}
/>,
];
return ( return (
<> <>
<PageSection variant="light" padding={{ default: "noPadding" }}> <PageSection variant="light" padding={{ default: "noPadding" }}>
@ -123,9 +206,37 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
<CertificateDialog /> <CertificateDialog />
<KeycloakDataTable <KeycloakDataTable
isNotCompact={true} isNotCompact={true}
loader={loader} key={key}
loader={
filterType === "Active keys"
? activeKeysLoader
: filterType === "Passive keys"
? passiveKeysLoader
: filterType === "Disabled keys"
? disabledKeysLoader
: loader
}
ariaLabelKey="realm-settings:keysList" ariaLabelKey="realm-settings:keysList"
searchPlaceholderKey="realm-settings:searchKey" searchPlaceholderKey="realm-settings:searchKey"
searchTypeComponent={
<Select
width={300}
data-testid="filter-type-select"
isOpen={filterDropdownOpen}
className="kc-filter-type-select"
variant={SelectVariant.single}
onToggle={() => setFilterDropdownOpen(!filterDropdownOpen)}
toggleIcon={<FilterIcon />}
onSelect={(_, value) => {
setFilterType(value as string);
refresh();
setFilterDropdownOpen(false);
}}
selections={filterType}
>
{options}
</Select>
}
canSelectAll canSelectAll
columns={[ columns={[
{ {
@ -144,25 +255,31 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
name: "kid", name: "kid",
displayKey: "realm-settings:kid", displayKey: "realm-settings:kid",
cellFormatters: [emptyFormatter()], cellFormatters: [emptyFormatter()],
transforms: [cellWidth(10)],
}, },
{ {
name: "provider", name: "provider",
displayKey: "realm-settings:provider", displayKey: "realm-settings:provider",
cellRenderer: ProviderRenderer, cellRenderer: ProviderRenderer,
cellFormatters: [emptyFormatter()], cellFormatters: [emptyFormatter()],
transforms: [cellWidth(10)],
}, },
{ {
name: "publicKeys", name: "publicKeys",
displayKey: "realm-settings:publicKeys", displayKey: "realm-settings:publicKeys",
cellRenderer: ButtonRenderer, cellRenderer: ButtonRenderer,
cellFormatters: [], cellFormatters: [],
transforms: [cellWidth(20)],
}, },
]} ]}
emptyState={ emptyState={
<ListEmptyState <ListEmptyState
hasIcon={true} hasIcon={true}
message={t("noRoles")} message={t("realm-settings:noKeys")}
instructions={t("noRolesInstructions")} instructions={
t(`realm-settings:noKeysDescription`) +
`${filterType.toLocaleLowerCase()}.`
}
primaryActionText={t("createRole")} primaryActionText={t("createRole")}
onPrimaryAction={goToCreate} onPrimaryAction={goToCreate}
/> />

View file

@ -279,6 +279,7 @@ export const RealmSettingsSection = () => {
<Tab <Tab
id="keysList" id="keysList"
eventKey={0} eventKey={0}
data-testid="rs-keys-list-tab"
title={<TabTitleText>{t("keysList")}</TabTitleText>} title={<TabTitleText>{t("keysList")}</TabTitleText>}
> >
<KeysListTab realmComponents={realmComponents} /> <KeysListTab realmComponents={realmComponents} />

View file

@ -75,6 +75,11 @@
"providerDescription": "Provider description", "providerDescription": "Provider description",
"addProvider": "Add provider", "addProvider": "Add provider",
"publicKeys": "Public keys", "publicKeys": "Public keys",
"activeKeys": "Active keys",
"passiveKeys": "Passive keys",
"disabledKeys": "Disabled keys",
"noKeys": "No keys",
"noKeysDescription": "You haven't created any ",
"certificate": "Certificate", "certificate": "Certificate",
"userRegistration": "User registration", "userRegistration": "User registration",
"userRegistrationHelpText": "Enable/disable the registration page. A link for registration will show on login page too.", "userRegistrationHelpText": "Enable/disable the registration page. A link for registration will show on login page too.",