use ui-shared (#27908)

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
Erik Jan de Wit 2024-03-22 16:56:17 +01:00 committed by GitHub
parent 4fb2f73b2c
commit e9a1a6b982
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 96 additions and 275 deletions

View file

@ -320,7 +320,7 @@ describe("Clients test", () => {
createClientPage createClientPage
.fillClientData("") .fillClientData("")
.selectClientType("openid-connect") .selectClientType("OpenID Connect")
.cancel(); .cancel();
cy.url().should("not.include", "/add-client"); cy.url().should("not.include", "/add-client");
@ -360,7 +360,7 @@ describe("Clients test", () => {
createClientPage createClientPage
.fillClientData("test_client") .fillClientData("test_client")
.selectClientType("openid-connect") .selectClientType("OpenID Connect")
.continue() .continue()
.back() .back()
.checkGeneralSettingsStepActive(); .checkGeneralSettingsStepActive();
@ -373,7 +373,7 @@ describe("Clients test", () => {
createClientPage createClientPage
.fillClientData("") .fillClientData("")
.selectClientType("openid-connect") .selectClientType("OpenID Connect")
.continue() .continue()
.checkClientIdRequiredMessage(); .checkClientIdRequiredMessage();
@ -398,7 +398,7 @@ describe("Clients test", () => {
commonPage.tableToolbarUtils().clickPrimaryButton(); commonPage.tableToolbarUtils().clickPrimaryButton();
createClientPage createClientPage
.selectClientType("openid-connect") .selectClientType("OpenID Connect")
.fillClientData(itemId) .fillClientData(itemId)
.continue() .continue()
.switchClientAuthentication() .switchClientAuthentication()
@ -765,7 +765,7 @@ describe("Clients test", () => {
client = "client_" + uuid(); client = "client_" + uuid();
commonPage.tableToolbarUtils().createClient(); commonPage.tableToolbarUtils().createClient();
createClientPage createClientPage
.selectClientType("openid-connect") .selectClientType("OpenID Connect")
.fillClientData(client) .fillClientData(client)
.continue(); .continue();

View file

@ -127,7 +127,7 @@ describe("User Fed LDAP mapper tests", () => {
sidebarPage.goToClients(); sidebarPage.goToClients();
listingPage.goToCreateItem(); listingPage.goToCreateItem();
createClientPage createClientPage
.selectClientType("openid-connect") .selectClientType("OpenID Connect")
.fillClientData(clientName) .fillClientData(clientName)
.continue() .continue()
.continue() .continue()

View file

@ -1,8 +1,8 @@
import Select from "../../../../forms/Select";
import CommonPage from "../../../CommonPage"; import CommonPage from "../../../CommonPage";
export default class CreateClientPage extends CommonPage { export default class CreateClientPage extends CommonPage {
#clientTypeDrpDwn = ".pf-c-select__toggle"; #clientTypeDrpDwn = "#protocol";
#clientTypeList = ".pf-c-select__toggle + ul";
#clientIdInput = "#clientId"; #clientIdInput = "#clientId";
#clientIdError = "#clientId + div"; #clientIdError = "#clientId + div";
#clientNameInput = "#name"; #clientNameInput = "#name";
@ -31,13 +31,15 @@ export default class CreateClientPage extends CommonPage {
#firstWebOriginsInput = "webOrigins0"; #firstWebOriginsInput = "webOrigins0";
#adminUrlInput = "adminUrl"; #adminUrlInput = "adminUrl";
#loginThemeDrpDwn = "#loginTheme"; #loginThemeDrpDwn = "#login_theme";
#loginThemeList = 'ul[aria-label="Login theme"]'; #loginThemeList = 'ul[class="pf-c-select__menu"]';
#consentRequiredSwitch = '[for="kc-consent-switch"] > .pf-c-switch__toggle'; #consentRequiredSwitch = '[for="consentRequired"] .pf-c-switch__toggle';
#consentRequiredSwitchInput = "#kc-consent-switch"; #consentRequiredSwitchInput = "#consentRequired";
#displayClientOnScreenSwitch = '[for="kc-display-on-client-switch"]'; #displayClientOnScreenSwitch =
#displayClientOnScreenSwitchInput = "#kc-display-on-client-switch"; '[for="attributes.display🍺on🍺consent🍺screen"].pf-c-switch';
#clientConsentScreenText = "#kc-consent-screen-text"; #displayClientOnScreenSwitchInput =
"#attributes\\.display🍺on🍺consent🍺screen";
#clientConsentScreenText = "attributes.consent🍺screen🍺text";
#frontChannelLogoutSwitch = #frontChannelLogoutSwitch =
'[for="kc-frontchannelLogout-switch"] > .pf-c-switch__toggle'; '[for="kc-frontchannelLogout-switch"] > .pf-c-switch__toggle';
@ -60,8 +62,7 @@ export default class CreateClientPage extends CommonPage {
//#region General Settings //#region General Settings
selectClientType(clientType: string) { selectClientType(clientType: string) {
cy.get(this.#clientTypeDrpDwn).click(); Select.selectItem(cy.get(this.#clientTypeDrpDwn), clientType);
cy.get(this.#clientTypeList).findByTestId(`option-${clientType}`).click();
return this; return this;
} }
@ -238,11 +239,11 @@ export default class CreateClientPage extends CommonPage {
} }
checkLoginSettingsElements() { checkLoginSettingsElements() {
cy.get(this.#clientConsentScreenText).scrollIntoView(); cy.findByTestId(this.#clientConsentScreenText).scrollIntoView();
cy.get(this.#loginThemeDrpDwn).should("not.be.disabled"); cy.get(this.#loginThemeDrpDwn).should("not.be.disabled");
cy.get(this.#consentRequiredSwitchInput).should("not.be.disabled"); cy.get(this.#consentRequiredSwitchInput).should("not.be.disabled");
cy.get(this.#displayClientOnScreenSwitchInput).should("be.disabled"); cy.get(this.#displayClientOnScreenSwitchInput).should("be.disabled");
cy.get(this.#clientConsentScreenText).should("be.disabled"); cy.findByTestId(this.#clientConsentScreenText).should("be.disabled");
cy.get(this.#loginThemeDrpDwn).click(); cy.get(this.#loginThemeDrpDwn).click();
cy.get(this.#loginThemeList).findByText("base").should("exist"); cy.get(this.#loginThemeList).findByText("base").should("exist");
@ -251,13 +252,13 @@ export default class CreateClientPage extends CommonPage {
cy.get(this.#consentRequiredSwitch).click(); cy.get(this.#consentRequiredSwitch).click();
cy.get(this.#displayClientOnScreenSwitchInput).should("not.be.disabled"); cy.get(this.#displayClientOnScreenSwitchInput).should("not.be.disabled");
cy.get(this.#clientConsentScreenText).should("be.disabled"); cy.findByTestId(this.#clientConsentScreenText).should("be.disabled");
cy.get(this.#displayClientOnScreenSwitch).click(); cy.get(this.#displayClientOnScreenSwitch).click();
cy.get(this.#clientConsentScreenText).should("not.be.disabled"); cy.findByTestId(this.#clientConsentScreenText).should("not.be.disabled");
cy.get(this.#displayClientOnScreenSwitch).click(); cy.get(this.#displayClientOnScreenSwitch).click();
cy.get(this.#clientConsentScreenText).should("be.disabled"); cy.findByTestId(this.#clientConsentScreenText).should("be.disabled");
cy.get(this.#consentRequiredSwitch).click(); cy.get(this.#consentRequiredSwitch).click();
cy.get(this.#displayClientOnScreenSwitchInput).should("be.disabled"); cy.get(this.#displayClientOnScreenSwitchInput).should("be.disabled");

View file

@ -26,10 +26,10 @@ export default class SettingsTab extends PageObject {
"#saml🍺server🍺signature🍺keyinfo🍺xmlSigKeyInfoKeyNameTransformer"; "#saml🍺server🍺signature🍺keyinfo🍺xmlSigKeyInfoKeyNameTransformer";
#canonicalization = "#saml_signature_canonicalization_method"; #canonicalization = "#saml_signature_canonicalization_method";
#loginTheme = "#loginTheme"; #loginTheme = "#login_theme";
#consentSwitch = "#kc-consent-switch"; #consentSwitch = "#consentRequired";
#displayClientSwitch = "#kc-display-on-client-switch"; #displayClientSwitch = "attributes.display🍺on🍺consent🍺screen";
#consentScreenText = "#kc-consent-screen-text"; #consentScreenText = "attributes.consent🍺screen🍺text";
#saveBtn = "settings-save"; #saveBtn = "settings-save";
#revertBtn = "settingsRevert"; #revertBtn = "settingsRevert";
@ -124,7 +124,7 @@ export default class SettingsTab extends PageObject {
} }
public clickDisplayClientSwitch() { public clickDisplayClientSwitch() {
cy.get(this.#displayClientSwitch).parent().click(); cy.findByTestId(this.#displayClientSwitch).parent().click();
return this; return this;
} }
@ -202,13 +202,14 @@ export default class SettingsTab extends PageObject {
} }
public assertLoginSettings() { public assertLoginSettings() {
cy.get(this.#displayClientSwitch).should("be.disabled"); cy.findByTestId(this.#displayClientSwitch).should("be.disabled");
cy.get(this.#consentScreenText).should("be.disabled"); cy.findByTestId(this.#consentScreenText).should("be.disabled");
this.clickConsentSwitch(); this.clickConsentSwitch();
cy.get(this.#displayClientSwitch).should("not.be.disabled"); cy.findByTestId(this.#displayClientSwitch).should("not.be.disabled");
this.clickDisplayClientSwitch(); this.clickDisplayClientSwitch();
cy.get(this.#consentScreenText).should("not.be.disabled"); cy.findByTestId(this.#consentScreenText).should("not.be.disabled");
cy.get(this.#consentScreenText).click().type("Consent Screen Text"); cy.findByTestId(this.#consentScreenText).click();
cy.findByTestId(this.#consentScreenText).type("Consent Screen Text");
return this; return this;
} }

View file

@ -1,3 +1,4 @@
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
import { import {
Checkbox, Checkbox,
FormGroup, FormGroup,
@ -8,13 +9,12 @@ import {
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
import { FormAccess } from "../../components/form/FormAccess";
import { HelpItem } from "ui-shared"; import { HelpItem } from "ui-shared";
import { DefaultSwitchControl } from "../../components/SwitchControl";
import { FormAccess } from "../../components/form/FormAccess";
import { convertAttributeNameToForm } from "../../util"; import { convertAttributeNameToForm } from "../../util";
import { FormFields } from "../ClientDetails";
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled"; import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
import { FormFields } from "../ClientDetails";
type CapabilityConfigProps = { type CapabilityConfigProps = {
unWrap?: boolean; unWrap?: boolean;
@ -276,66 +276,20 @@ export const CapabilityConfig = ({
)} )}
{protocol === "saml" && ( {protocol === "saml" && (
<> <>
<FormGroup <DefaultSwitchControl
labelIcon={ name={convertAttributeNameToForm<FormFields>(
<HelpItem "attributes.saml.encrypt",
helpText={t("encryptAssertionsHelp")} )}
fieldLabelId="encryptAssertions"
/>
}
label={t("encryptAssertions")} label={t("encryptAssertions")}
fieldId="kc-encrypt" labelIcon={t("encryptAssertionsHelp")}
hasNoPaddingTop />
> <DefaultSwitchControl
<Controller name={convertAttributeNameToForm<FormFields>(
name={convertAttributeNameToForm<FormFields>( "attributes.saml.client.signature",
"attributes.saml.encrypt", )}
)}
control={control}
defaultValue={false}
render={({ field }) => (
<Switch
data-testid="encrypt"
id="kc-encrypt"
label={t("on")}
labelOff={t("off")}
isChecked={field.value}
onChange={field.onChange}
aria-label={t("encryptAssertions")}
/>
)}
/>
</FormGroup>
<FormGroup
labelIcon={
<HelpItem
helpText={t("clientSignatureHelp")}
fieldLabelId="clientSignature"
/>
}
label={t("clientSignature")} label={t("clientSignature")}
fieldId="kc-client-signature" labelIcon={t("clientSignatureHelp")}
hasNoPaddingTop />
>
<Controller
name={convertAttributeNameToForm<FormFields>(
"attributes.saml.client.signature",
)}
control={control}
defaultValue={false}
render={({ field }) => (
<Switch
data-testid="client-signature"
id="kc-client-signature"
label={t("on")}
labelOff={t("off")}
isChecked={field.value}
onChange={field.onChange}
aria-label={t("clientSignature")}
/>
)}
/>
</FormGroup>
</> </>
)} )}
</FormAccess> </FormAccess>

View file

@ -1,70 +1,28 @@
import {
FormGroup,
Select,
SelectOption,
SelectVariant,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { SelectControl } from "ui-shared";
import { FormAccess } from "../../components/form/FormAccess"; import { FormAccess } from "../../components/form/FormAccess";
import { HelpItem } from "ui-shared";
import { useLoginProviders } from "../../context/server-info/ServerInfoProvider"; import { useLoginProviders } from "../../context/server-info/ServerInfoProvider";
import { ClientDescription } from "../ClientDescription"; import { ClientDescription } from "../ClientDescription";
import { getProtocolName } from "../utils"; import { getProtocolName } from "../utils";
export const GeneralSettings = () => { export const GeneralSettings = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const {
control,
formState: { errors },
} = useFormContext();
const providers = useLoginProviders(); const providers = useLoginProviders();
const [open, isOpen] = useState(false);
return ( return (
<FormAccess isHorizontal role="manage-clients"> <FormAccess isHorizontal role="manage-clients">
<FormGroup <SelectControl
name="protocol"
label={t("clientType")} label={t("clientType")}
fieldId="kc-type" labelIcon={t("clientTypeHelp")}
validated={errors.protocol ? "error" : "default"} controller={{
labelIcon={ defaultValue: "",
<HelpItem helpText={t("clientTypeHelp")} fieldLabelId="clientType" /> }}
} options={providers.map((option) => ({
> key: option,
<Controller value: getProtocolName(t, option),
name="protocol" }))}
defaultValue="" />
control={control}
render={({ field }) => (
<Select
id="kc-type"
onToggle={isOpen}
onSelect={(_, value) => {
field.onChange(value.toString());
isOpen(false);
}}
selections={field.value}
variant={SelectVariant.single}
aria-label={t("selectEncryptionType")}
isOpen={open}
>
{providers.map((option) => (
<SelectOption
selected={option === field.value}
key={option}
value={option}
data-testid={`option-${option}`}
>
{getProtocolName(t, option)}
</SelectOption>
))}
</Select>
)}
/>
</FormGroup>
<ClientDescription hasConfigureAccess /> <ClientDescription hasConfigureAccess />
</FormAccess> </FormAccess>
); );

View file

@ -1,26 +1,16 @@
import { import { useFormContext } from "react-hook-form";
FormGroup,
Select,
SelectOption,
SelectVariant,
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { SelectControl, TextAreaControl } from "ui-shared";
import { DefaultSwitchControl } from "../../components/SwitchControl";
import { FormAccess } from "../../components/form/FormAccess"; import { FormAccess } from "../../components/form/FormAccess";
import { HelpItem } from "ui-shared";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { convertAttributeNameToForm } from "../../util"; import { convertAttributeNameToForm } from "../../util";
import { FormFields } from "../ClientDetails"; import { FormFields } from "../ClientDetails";
export const LoginSettingsPanel = ({ access }: { access?: boolean }) => { export const LoginSettingsPanel = ({ access }: { access?: boolean }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { register, control, watch } = useFormContext<FormFields>(); const { watch } = useFormContext<FormFields>();
const [loginThemeOpen, setLoginThemeOpen] = useState(false);
const loginThemes = useServerInfo().themes!["login"]; const loginThemes = useServerInfo().themes!["login"];
const consentRequired = watch("consentRequired"); const consentRequired = watch("consentRequired");
const displayOnConsentScreen: string = watch( const displayOnConsentScreen: string = watch(
@ -31,123 +21,40 @@ export const LoginSettingsPanel = ({ access }: { access?: boolean }) => {
return ( return (
<FormAccess isHorizontal fineGrainedAccess={access} role="manage-clients"> <FormAccess isHorizontal fineGrainedAccess={access} role="manage-clients">
<FormGroup <SelectControl
name="attributes.login_theme"
label={t("loginTheme")} label={t("loginTheme")}
labelIcon={ labelIcon={t("loginThemeHelp")}
<HelpItem helpText={t("loginThemeHelp")} fieldLabelId="loginTheme" /> controller={{
} defaultValue: "",
fieldId="loginTheme" }}
> options={[
<Controller { key: "", value: t("choose") },
name="attributes.login_theme" ...loginThemes.map(({ name }) => ({ key: name, value: name })),
defaultValue="" ]}
control={control} />
render={({ field }) => ( <DefaultSwitchControl
<Select name="consentRequired"
toggleId="loginTheme"
onToggle={setLoginThemeOpen}
onSelect={(_, value) => {
field.onChange(value.toString());
setLoginThemeOpen(false);
}}
selections={field.value || t("choose")}
variant={SelectVariant.single}
aria-label={t("loginTheme")}
isOpen={loginThemeOpen}
>
{[
<SelectOption key="empty" value="">
{t("choose")}
</SelectOption>,
...loginThemes.map((theme) => (
<SelectOption
selected={theme.name === field.value}
key={theme.name}
value={theme.name}
/>
)),
]}
</Select>
)}
/>
</FormGroup>
<FormGroup
label={t("consentRequired")} label={t("consentRequired")}
labelIcon={ labelIcon={t("consentRequiredHelp")}
<HelpItem />
helpText={t("consentRequiredHelp")} <DefaultSwitchControl
fieldLabelId="consentRequired" name={convertAttributeNameToForm<FormFields>(
/> "attributes.display.on.consent.screen",
} )}
fieldId="kc-consent"
hasNoPaddingTop
>
<Controller
name="consentRequired"
defaultValue={false}
control={control}
render={({ field }) => (
<Switch
id="kc-consent-switch"
label={t("on")}
labelOff={t("off")}
isChecked={field.value}
onChange={field.onChange}
aria-label={t("consentRequired")}
/>
)}
/>
</FormGroup>
<FormGroup
label={t("displayOnClient")} label={t("displayOnClient")}
labelIcon={ labelIcon={t("displayOnClientHelp")}
<HelpItem isDisabled={!consentRequired}
helpText={t("displayOnClientHelp")} stringify
fieldLabelId="displayOnClient" />
/> <TextAreaControl
} name={convertAttributeNameToForm<FormFields>(
fieldId="kc-display-on-client" "attributes.consent.screen.text",
hasNoPaddingTop )}
>
<Controller
name={convertAttributeNameToForm<FormFields>(
"attributes.display.on.consent.screen",
)}
defaultValue={false}
control={control}
render={({ field }) => (
<Switch
id="kc-display-on-client-switch"
label={t("on")}
labelOff={t("off")}
isChecked={field.value === "true"}
onChange={(value) => field.onChange("" + value)}
isDisabled={!consentRequired}
aria-label={t("displayOnClient")}
/>
)}
/>
</FormGroup>
<FormGroup
label={t("consentScreenText")} label={t("consentScreenText")}
labelIcon={ labelIcon={t("consentScreenTextHelp")}
<HelpItem isDisabled={!(consentRequired && displayOnConsentScreen === "true")}
helpText={t("consentScreenTextHelp")} />
fieldLabelId="consentScreenText"
/>
}
fieldId="kc-consent-screen-text"
>
<KeycloakTextArea
id="kc-consent-screen-text"
{...register(
convertAttributeNameToForm<FormFields>(
"attributes.consent.screen.text",
),
)}
isDisabled={!(consentRequired && displayOnConsentScreen === "true")}
/>
</FormGroup>
</FormAccess> </FormAccess>
); );
}; };