convert to ui-shared (#27708)

* convert to ui-shared

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* review comments

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* added default value for variant

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* remove class

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* spread rest of the properties

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

---------

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
Erik Jan de Wit 2024-03-12 11:50:34 +01:00 committed by GitHub
parent d2a7e87967
commit f2cc4cbce0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 123 additions and 259 deletions

View file

@ -5,7 +5,7 @@ export default class CreateProviderPage {
#clientSecretField = "clientSecret";
#displayName = "displayName";
#discoveryEndpoint = "discoveryEndpoint";
#authorizationUrl = "authorizationUrl";
#authorizationUrl = "config.authorizationUrl";
#addButton = "createProvider";
#saveButton = "idp-details-save";
#ssoServiceUrl = "sso-service-url";

View file

@ -79,10 +79,10 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
#saveBtn = "idp-details-save";
#revertBtn = "idp-details-revert";
#validateSignature = "#validateSignature";
#jwksSwitch = "#useJwksUrl";
#jwksUrl = "jwksUrl";
#pkceSwitch = "#pkceEnabled";
#validateSignature = "#config\\.validateSignature";
#jwksSwitch = "#config\\.useJwksUrl";
#jwksUrl = "config.jwksUrl";
#pkceSwitch = "#config\\.pkceEnabled";
#pkceMethod = "#pkceMethod";
#clientAuth = "#clientAuthentication";
#clientAssertionSigningAlg = "#clientAssertionSigningAlg";
@ -347,9 +347,8 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
public assertOIDCUrl(url: string) {
cy.findByTestId("jump-link-openid-connect-settings").click();
cy.findByTestId(url + "Url")
.clear()
.type("invalidUrl");
cy.findByTestId(`config.${url}Url`).clear();
cy.findByTestId(`config.${url}Url`).type("invalidUrl");
this.clickSaveBtn();
masthead.checkNotificationMessage(
"Could not update the provider The url [" + url + "_url] is malformed",

View file

@ -1,22 +1,10 @@
import IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import {
ExpandableSection,
FormGroup,
Select,
SelectOption,
SelectVariant,
ValidatedOptions,
} from "@patternfly/react-core";
import { ExpandableSection } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "ui-shared";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { FormGroupField } from "../component/FormGroupField";
import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField";
import { SelectControl, TextAreaControl, TextControl } from "ui-shared";
import { DefaultSwitchControl } from "../../components/SwitchControl";
import "./discovery-settings.css";
@ -28,12 +16,7 @@ type DiscoverySettingsProps = {
const Fields = ({ readOnly }: DiscoverySettingsProps) => {
const { t } = useTranslation();
const [pkceMethodOpen, setPkceMethodOpen] = useState(false);
const {
register,
control,
formState: { errors },
} = useFormContext<IdentityProviderRepresentation>();
const { control } = useFormContext<IdentityProviderRepresentation>();
const validateSignature = useWatch({
control,
@ -50,152 +33,93 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
return (
<div className="pf-c-form pf-m-horizontal">
<FormGroup
<TextControl
name="config.authorizationUrl"
label={t("authorizationUrl")}
fieldId="kc-authorization-url"
isRequired
validated={
errors.config?.authorizationUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("required")}
>
<KeycloakTextInput
type="url"
data-testid="authorizationUrl"
id="kc-authorization-url"
validated={
errors.config?.authorizationUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
isReadOnly={readOnly}
{...register("config.authorizationUrl", { required: true })}
/>
</FormGroup>
<FormGroup
type="url"
readOnly={readOnly}
rules={{
required: t("required"),
}}
/>
<TextControl
name="config.tokenUrl"
label={t("tokenUrl")}
fieldId="tokenUrl"
isRequired
validated={
errors.config?.tokenUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
helperTextInvalid={t("required")}
>
<KeycloakTextInput
type="url"
id="tokenUrl"
data-testid="tokenUrl"
validated={
errors.config?.tokenUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
isReadOnly={readOnly}
{...register("config.tokenUrl", { required: true })}
/>
</FormGroup>
<TextField
field="config.logoutUrl"
label="logoutUrl"
isReadOnly={readOnly}
type="url"
readOnly={readOnly}
rules={{
required: t("required"),
}}
/>
<TextField
field="config.userInfoUrl"
label="userInfoUrl"
isReadOnly={readOnly}
<TextControl
name="config.logoutUrl"
label={t("logoutUrl")}
readOnly={readOnly}
/>
<TextField field="config.issuer" label="issuer" isReadOnly={readOnly} />
<SwitchField
field="config.validateSignature"
label="validateSignature"
isReadOnly={readOnly}
<TextControl
name="config.userInfoUrl"
label={t("userInfoUrl")}
readOnly={readOnly}
/>
<TextControl
name="config.issuer"
label={t("issuer")}
readOnly={readOnly}
/>
<DefaultSwitchControl
name="config.validateSignature"
label={t("validateSignature")}
isDisabled={readOnly}
stringify
/>
{validateSignature === "true" && (
<>
<SwitchField
field="config.useJwksUrl"
label="useJwksUrl"
data-testid="useJwksUrl"
isReadOnly={readOnly}
<DefaultSwitchControl
name="config.useJwksUrl"
label={t("useJwksUrl")}
isDisabled={readOnly}
stringify
/>
{useJwks === "true" ? (
<TextField
field="config.jwksUrl"
label="jwksUrl"
isReadOnly={readOnly}
<TextAreaControl
name="config.jwksUrl"
label={t("jwksUrl")}
readOnly={readOnly}
/>
) : (
<>
<FormGroupField label="validatingPublicKey">
<KeycloakTextArea
data-testid="validatingPublicKey"
aria-label={t("validatingPublicKey")}
{...register("config.publicKeySignatureVerifier")}
/>
</FormGroupField>
<TextField
field="config.publicKeySignatureVerifierKeyId"
label="validatingPublicKeyId"
isReadOnly={readOnly}
<TextControl
name="config.publicKeySignatureVerifier"
label="validatingPublicKey"
/>
<TextControl
name="config.publicKeySignatureVerifierKeyId"
label={t("validatingPublicKeyId")}
readOnly={readOnly}
/>
</>
)}
</>
)}
<SwitchField
field="config.pkceEnabled"
label="pkceEnabled"
isReadOnly={readOnly}
<DefaultSwitchControl
name="config.pkceEnabled"
label={t("pkceEnabled")}
isDisabled={readOnly}
stringify
/>
{isPkceEnabled === "true" && (
<FormGroup
className="pf-u-pb-3xl"
<SelectControl
name="config.pkceMethod"
label={t("pkceMethod")}
labelIcon={
<HelpItem
helpText={t("pkceMethodHelp")}
fieldLabelId="pkceMethod"
/>
}
fieldId="pkceMethod"
>
<Controller
name="config.pkceMethod"
defaultValue={PKCE_METHODS[0]}
control={control}
render={({ field }) => (
<Select
toggleId="pkceMethod"
required
direction="down"
onToggle={() => setPkceMethodOpen(!pkceMethodOpen)}
onSelect={(_, value) => {
field.onChange(value as string);
setPkceMethodOpen(false);
}}
selections={t(`${field.value}`)}
variant={SelectVariant.single}
aria-label={t("pkceMethod")}
isOpen={pkceMethodOpen}
>
{PKCE_METHODS.map((option) => (
<SelectOption
selected={option === field.value}
key={option}
value={option}
>
{t(`${option}`)}
</SelectOption>
))}
</Select>
)}
/>
</FormGroup>
labelIcon={t("pkceMethodHelp")}
controller={{
defaultValue: PKCE_METHODS[0],
}}
options={PKCE_METHODS.map((option) => ({
key: option,
value: t(`${option}`),
}))}
/>
)}
</div>
);

View file

@ -1,54 +1,33 @@
import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { useWatch, useFormContext } from "react-hook-form";
import { useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
import { HelpItem } from "ui-shared";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { TextControl } from "ui-shared";
import { DisplayOrder } from "../component/DisplayOrder";
import { RedirectUrl } from "../component/RedirectUrl";
import { TextField } from "../component/TextField";
import type { IdentityProviderParams } from "../routes/IdentityProvider";
export const OIDCGeneralSettings = () => {
const { t } = useTranslation();
const { tab } = useParams<IdentityProviderParams>();
const {
register,
control,
formState: { errors },
} = useFormContext();
const { control } = useFormContext();
const alias = useWatch({ control, name: "alias" });
return (
<>
<RedirectUrl id={alias} />
<FormGroup
<TextControl
name="alias"
label={t("alias")}
labelIcon={<HelpItem helpText={t("aliasHelp")} fieldLabelId="alias" />}
fieldId="alias"
isRequired
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
helperTextInvalid={t("required")}
>
<KeycloakTextInput
isReadOnly={tab === "settings"}
isRequired
id="alias"
data-testid="alias"
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
{...register("alias", { required: true })}
/>
</FormGroup>
labelIcon={t("aliasHelp")}
readOnly={tab === "settings"}
rules={{
required: t("required"),
}}
/>
<TextField field="displayName" label="displayName" />
<TextControl name="displayName" label={t("displayName")} />
<DisplayOrder />
</>
);

View file

@ -3,11 +3,9 @@ import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client
import { FormGroup, Title } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "ui-shared";
import { HelpItem, TextControl } from "ui-shared";
import { adminClient } from "../../admin-client";
import { FileUploadForm } from "../../components/json-file-upload/FileUploadForm";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useRealm } from "../../context/realm-context/RealmContext";
import environment from "../../environment";
import { addTrailingSlash } from "../../util";
@ -26,7 +24,6 @@ export const SamlConnectSettings = () => {
const { realm } = useRealm();
const {
setValue,
register,
setError,
clearErrors,
formState: { errors },
@ -81,27 +78,15 @@ export const SamlConnectSettings = () => {
{t("samlSettings")}
</Title>
<FormGroup
<TextControl
name="config.entityId"
label={t("serviceProviderEntityId")}
fieldId="kc-service-provider-entity-id"
labelIcon={
<HelpItem
helpText={t("serviceProviderEntityIdHelp")}
fieldLabelId="serviceProviderEntityId"
/>
}
isRequired
helperTextInvalid={t("required")}
validated={errors.config?.entityId ? "error" : "default"}
>
<KeycloakTextInput
data-testid="serviceProviderEntityId"
id="kc-service-provider-entity-id"
validated={errors.config?.entityId ? "error" : "default"}
defaultValue={`${environment.authServerUrl}/realms/${realm}`}
{...register("config.entityId", { required: true })}
/>
</FormGroup>
labelIcon={t("serviceProviderEntityIdHelp")}
defaultValue={`${environment.authServerUrl}/realms/${realm}`}
rules={{
required: t("required"),
}}
/>
<DiscoveryEndpointField
id="saml"

View file

@ -1,15 +1,12 @@
import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { useWatch, useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem, TextControl } from "ui-shared";
import { FormattedLink } from "../../components/external-link/FormattedLink";
import { HelpItem } from "ui-shared";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useRealm } from "../../context/realm-context/RealmContext";
import environment from "../../environment";
import { DisplayOrder } from "../component/DisplayOrder";
import { RedirectUrl } from "../component/RedirectUrl";
import { TextField } from "../component/TextField";
import "./saml-general-settings.css";
@ -23,47 +20,26 @@ export const SamlGeneralSettings = ({
const { t } = useTranslation();
const { realm } = useRealm();
const {
register,
control,
formState: { errors },
} = useFormContext();
const { control } = useFormContext();
const alias = useWatch({ control, name: "alias" });
return (
<>
<RedirectUrl id={alias} />
<FormGroup
<TextControl
name="alias"
label={t("alias")}
labelIcon={<HelpItem helpText={t("aliasHelp")} fieldLabelId="alias" />}
fieldId="alias"
isRequired
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
helperTextInvalid={t("required")}
>
<KeycloakTextInput
isRequired
id="alias"
data-testid="alias"
isReadOnly={isAliasReadonly}
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
{...register("alias", { required: true })}
/>
</FormGroup>
<TextField
field="displayName"
label="displayName"
data-testid="displayName"
labelIcon={t("aliasHelp")}
readOnly={isAliasReadonly}
rules={{
required: t("required"),
}}
/>
<TextControl name="displayName" label={t("displayName")} />
<DisplayOrder />
{isAliasReadonly ? (
{isAliasReadonly && (
<FormGroup
label={t("endpoints")}
fieldId="endpoints"
@ -78,7 +54,7 @@ export const SamlGeneralSettings = ({
isInline
/>
</FormGroup>
) : null}
)}
</>
);
};

View file

@ -44,7 +44,7 @@ export const SelectControl = <
label,
options,
controller,
variant,
variant = SelectVariant.single,
labelIcon,
...rest
}: SelectControlProps<T, P>) => {

View file

@ -1,4 +1,4 @@
import { ValidatedOptions } from "@patternfly/react-core";
import { TextAreaProps, ValidatedOptions } from "@patternfly/react-core";
import {
FieldPath,
FieldValues,
@ -13,11 +13,12 @@ import { KeycloakTextArea } from "./keycloak-text-area/KeycloakTextArea";
export type TextAreaControlProps<
T extends FieldValues,
P extends FieldPath<T> = FieldPath<T>,
> = UseControllerProps<T, P> & {
label: string;
labelIcon?: string;
isDisabled?: boolean;
};
> = UseControllerProps<T, P> &
TextAreaProps & {
label: string;
labelIcon?: string;
isDisabled?: boolean;
};
export const TextAreaControl = <
T extends FieldValues,