diff --git a/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/client_scopes/CreateClientScopePage.ts b/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/client_scopes/CreateClientScopePage.ts index 336ee7fe71..243fc625ea 100644 --- a/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/client_scopes/CreateClientScopePage.ts +++ b/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/client_scopes/CreateClientScopePage.ts @@ -21,18 +21,17 @@ export default class CreateClientScopePage extends CommonPage { this.settingsTab = ".pf-c-tabs__item:nth-child(1)"; this.mappersTab = ".pf-c-tabs__item:nth-child(2)"; - this.clientScopeNameInput = "#kc-name"; - this.clientScopeNameError = "#kc-name-helper"; - this.clientScopeDescriptionInput = "#kc-description"; + this.clientScopeNameInput = "name"; + this.clientScopeNameError = "#name-helper"; + this.clientScopeDescriptionInput = "description"; this.clientScopeTypeDrpDwn = "#kc-protocol"; this.clientScopeTypeList = "#kc-protocol + ul"; - this.displayOnConsentInput = '[id="kc-display-on-consent-screen"]'; + this.displayOnConsentInput = "attributes.display🍺on🍺consent🍺screen"; this.displayOnConsentSwitch = - this.displayOnConsentInput + " + .pf-c-switch__toggle"; - this.consentScreenTextInput = "#kc-consent-screen-text"; - this.includeInTokenSwitch = - '[id="includeInTokenScope"] + .pf-c-switch__toggle'; - this.displayOrderInput = "#kc-gui-order"; + '[for="attributes.display🍺on🍺consent🍺screen"] .pf-c-switch__toggle'; + this.consentScreenTextInput = "attributes.consent🍺screen🍺text"; + this.includeInTokenSwitch = "#attributes.include🍺in🍺token🍺scope-on"; + this.displayOrderInput = "attributes.gui🍺order"; this.saveBtn = '[type="submit"]'; this.cancelBtn = '[type="button"]'; @@ -45,22 +44,22 @@ export default class CreateClientScopePage extends CommonPage { consentScreenText = "", displayOrder = "", ) { - cy.get(this.clientScopeNameInput).clear(); + cy.findByTestId(this.clientScopeNameInput).clear(); if (name) { - cy.get(this.clientScopeNameInput).type(name); + cy.findByTestId(this.clientScopeNameInput).type(name); } if (description) { - cy.get(this.clientScopeDescriptionInput).type(description); + cy.findByTestId(this.clientScopeDescriptionInput).type(description); } if (consentScreenText) { - cy.get(this.consentScreenTextInput).type(consentScreenText); + cy.findByTestId(this.consentScreenTextInput).type(consentScreenText); } if (displayOrder) { - cy.get(this.displayOrderInput).type(displayOrder); + cy.findByTestId(this.displayOrderInput).type(displayOrder); } return this; @@ -74,11 +73,11 @@ export default class CreateClientScopePage extends CommonPage { } getSwitchDisplayOnConsentScreenInput() { - return cy.get(this.displayOnConsentInput); + return cy.findByTestId(this.displayOnConsentInput); } getConsentScreenTextInput() { - return cy.get(this.consentScreenTextInput); + return cy.findByTestId(this.consentScreenTextInput); } switchDisplayOnConsentScreen() { diff --git a/js/apps/admin-ui/src/client-scopes/details/MappingDetails.tsx b/js/apps/admin-ui/src/client-scopes/details/MappingDetails.tsx index 7102883422..d372ef76e4 100644 --- a/js/apps/admin-ui/src/client-scopes/details/MappingDetails.tsx +++ b/js/apps/admin-ui/src/client-scopes/details/MappingDetails.tsx @@ -8,13 +8,12 @@ import { DropdownItem, FormGroup, PageSection, - ValidatedOptions, } from "@patternfly/react-core"; import { useState } from "react"; import { FormProvider, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { Link, useMatch, useNavigate } from "react-router-dom"; -import { HelpItem } from "ui-shared"; +import { KeycloakTextInput, TextControl } from "ui-shared"; import { adminClient } from "../../admin-client"; import { toClient } from "../../clients/routes/Client"; @@ -22,7 +21,6 @@ import { useAlerts } from "../../components/alert/Alerts"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { DynamicComponents } from "../../components/dynamic/DynamicComponents"; import { FormAccess } from "../../components/form/FormAccess"; -import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { ViewHeader } from "../../components/view-header/ViewHeader"; import { useRealm } from "../../context/realm-context/RealmContext"; import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; @@ -38,12 +36,7 @@ export default function MappingDetails() { const { id, mapperId } = useParams(); const form = useForm(); - const { - register, - setValue, - formState: { errors }, - handleSubmit, - } = form; + const { setValue, handleSubmit } = form; const [mapping, setMapping] = useState(); const [config, setConfig] = useState<{ protocol?: string; @@ -200,59 +193,45 @@ export default function MappingDetails() { } /> - - - - - - } - fieldId="name" - isRequired - validated={ - errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("required")} + + - + + + - - - - - - - - + + + + + + ); diff --git a/js/apps/admin-ui/src/client-scopes/details/ScopeForm.tsx b/js/apps/admin-ui/src/client-scopes/details/ScopeForm.tsx index 05e7d19054..8caf0f0af6 100644 --- a/js/apps/admin-ui/src/client-scopes/details/ScopeForm.tsx +++ b/js/apps/admin-ui/src/client-scopes/details/ScopeForm.tsx @@ -1,30 +1,18 @@ import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation"; -import { - ActionGroup, - Button, - FormGroup, - Select, - SelectOption, - SelectVariant, - Switch, - ValidatedOptions, -} from "@patternfly/react-core"; -import { useEffect, useState } from "react"; -import { Controller, FormProvider, useForm, useWatch } from "react-hook-form"; +import { ActionGroup, Button, SelectVariant } from "@patternfly/react-core"; +import { useEffect } from "react"; +import { FormProvider, useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; -import { HelpItem, TextControl } from "ui-shared"; +import { SelectControl, TextAreaControl, TextControl } from "ui-shared"; import { getProtocolName } from "../../clients/utils"; import { DefaultSwitchControl } from "../../components/SwitchControl"; import { ClientScopeDefaultOptionalType, allClientScopeTypes, - clientScopeTypesSelectOptions, } from "../../components/client-scope/ClientScopeTypes"; import { FormAccess } from "../../components/form/FormAccess"; -import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea"; -import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { useRealm } from "../../context/realm-context/RealmContext"; import { useLoginProviders } from "../../context/server-info/ServerInfoProvider"; import { convertAttributeNameToForm, convertToFormValues } from "../../util"; @@ -40,19 +28,16 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => { const { t } = useTranslation(); const form = useForm({ mode: "onChange" }); const { - register, control, handleSubmit, setValue, - formState: { errors, isDirty, isValid }, + formState: { isDirty, isValid }, } = form; const { realm } = useRealm(); const providers = useLoginProviders(); const isFeatureEnabled = useIsFeatureEnabled(); const isDynamicScopesEnabled = isFeatureEnabled(Feature.DynamicScopes); - const [open, isOpen] = useState(false); - const [openType, setOpenType] = useState(false); const displayOnConsentScreen: string = useWatch({ control, @@ -87,270 +72,140 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => { onSubmit={handleSubmit(save)} isHorizontal > - - } - fieldId="kc-name" - validated={ - errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("required")} - isRequired - > - { - if (isDynamicScopesEnabled) { - setDynamicRegex(e.target.value, true); - } + + { + if (isDynamicScopesEnabled) + setDynamicRegex(e.target.validated, true); + }, + }} /> - - {isDynamicScopesEnabled && ( - - ( - "attributes.is.dynamic.scope", - )} - label={t("dynamicScope")} - labelIcon={t("dynamicScopeHelp")} - onChange={(value) => { - setDynamicRegex(value ? form.getValues("name") || "" : "", value); - }} - stringify - /> - {dynamicScope === "true" && ( - + ( - "attributes.dynamic.scope.regexp", + "attributes.is.dynamic.scope", )} - label={t("dynamicScopeFormat")} - labelIcon={t("dynamicScopeFormatHelp")} - isDisabled - /> - )} - - )} - - } - fieldId="kc-description" - validated={ - errors.description ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("maxLength", { length: 255 })} - > - - - - } - fieldId="kc-type" - > - ( - - )} - /> - - {!clientScope && ( - - } - fieldId="kc-protocol" - > - ( - + stringify + /> + {dynamicScope === "true" && ( + ( + "attributes.dynamic.scope.regexp", + )} + label={t("dynamicScopeFormat")} + labelIcon={t("dynamicScopeFormatHelp")} + isDisabled + /> )} + + )} + + ({ + key, + value: t(`clientScopeType.${key}`), + }))} + /> + {!clientScope && ( + ({ + key: option, + value: getProtocolName(t, option), + }))} /> - - )} - - } - fieldId="kc-display-on-consent-screen" - > - ( "attributes.display.on.consent.screen", )} - control={control} defaultValue={displayOnConsentScreen} - render={({ field }) => ( - field.onChange(value.toString())} - /> - )} + label={t("displayOnConsentScreen")} + labelIcon={t("displayOnConsentScreenHelp")} + stringify /> - - {displayOnConsentScreen === "true" && ( - - } - fieldId="kc-consent-screen-text" - > - ( - "attributes.consent.screen.text", - ), + {displayOnConsentScreen === "true" && ( + ( + "attributes.consent.screen.text", )} + label={t("consentScreenText")} + labelIcon={t("consentScreenTextHelp")} /> - - )} - - } - fieldId="kc-include-in-token-scope" - > - ( "attributes.include.in.token.scope", )} - control={control} - defaultValue="true" - render={({ field }) => ( - field.onChange(value.toString())} - /> - )} + label={t("includeInTokenScope")} + labelIcon={t("includeInTokenScopeHelp")} + stringify /> - - - } - fieldId="kc-gui-order" - > - ( "attributes.gui.order", )} - defaultValue="" - control={control} - render={({ field }) => ( - - )} + label={t("guiOrder")} + labelIcon={t("guiOrderHelp")} + type="number" + min={0} /> - - - - - + + + + + ); }; diff --git a/js/libs/ui-shared/src/controls/FormLabel.tsx b/js/libs/ui-shared/src/controls/FormLabel.tsx index c584a1ad88..c2f043d103 100644 --- a/js/libs/ui-shared/src/controls/FormLabel.tsx +++ b/js/libs/ui-shared/src/controls/FormLabel.tsx @@ -1,9 +1,13 @@ -import { FormGroup, ValidatedOptions } from "@patternfly/react-core"; +import { + FormGroup, + FormGroupProps, + ValidatedOptions, +} from "@patternfly/react-core"; import { PropsWithChildren } from "react"; import { FieldError, FieldValues, Merge } from "react-hook-form"; import { HelpItem } from "./HelpItem"; -export type FormLabelProps = { +export type FieldProps = { label?: string; name: string; labelIcon?: string; @@ -11,6 +15,8 @@ export type FormLabelProps = { isRequired: boolean; }; +type FormLabelProps = FieldProps & Omit; + export const FormLabel = ({ name, label, diff --git a/js/libs/ui-shared/src/controls/SwitchControl.tsx b/js/libs/ui-shared/src/controls/SwitchControl.tsx index 7f16887802..509d73b493 100644 --- a/js/libs/ui-shared/src/controls/SwitchControl.tsx +++ b/js/libs/ui-shared/src/controls/SwitchControl.tsx @@ -32,6 +32,7 @@ export const SwitchControl = < const { control } = useFormContext(); return (