Use react-hook-form v7 for IDP section (#4072)

This commit is contained in:
Erik Jan de Wit 2022-12-21 12:39:24 -05:00 committed by GitHub
parent c6344dec60
commit f72d38f31a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 206 additions and 221 deletions

View file

@ -5,7 +5,7 @@ import {
Button, Button,
PageSection, PageSection,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form-v7";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom-v5-compat"; import { Link, useNavigate } from "react-router-dom-v5-compat";
@ -36,7 +36,7 @@ export default function AddIdentityProvider() {
const navigate = useNavigate(); const navigate = useNavigate();
const { realm } = useRealm(); const { realm } = useRealm();
const save = async (provider: IdentityProviderRepresentation) => { const onSubmit = async (provider: IdentityProviderRepresentation) => {
try { try {
await adminClient.identityProviders.create({ await adminClient.identityProviders.create({
...provider, ...provider,
@ -68,7 +68,7 @@ export default function AddIdentityProvider() {
<FormAccess <FormAccess
role="manage-identity-providers" role="manage-identity-providers"
isHorizontal isHorizontal
onSubmit={handleSubmit(save)} onSubmit={handleSubmit(onSubmit)}
> >
<FormProvider {...form}> <FormProvider {...form}>
<GeneralSettings id={providerId} /> <GeneralSettings id={providerId} />

View file

@ -1,25 +1,25 @@
import { useRouteMatch } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom-v5-compat";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
Button, Button,
PageSection, PageSection,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { FormProvider, useForm } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { useRouteMatch } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom-v5-compat";
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation"; import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { useAlerts } from "../../components/alert/Alerts";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient } from "../../context/auth/AdminClient";
import { OIDCGeneralSettings } from "./OIDCGeneralSettings";
import { OpenIdConnectSettings } from "./OpenIdConnectSettings";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import { OIDCAuthentication } from "./OIDCAuthentication";
import { useAlerts } from "../../components/alert/Alerts";
import { toIdentityProvider } from "../routes/IdentityProvider"; import { toIdentityProvider } from "../routes/IdentityProvider";
import { toIdentityProviders } from "../routes/IdentityProviders"; import { toIdentityProviders } from "../routes/IdentityProviders";
import { OIDCAuthentication } from "./OIDCAuthentication";
import { OIDCGeneralSettings } from "./OIDCGeneralSettings";
import { OpenIdConnectSettings } from "./OpenIdConnectSettings";
type DiscoveryIdentity = IdentityProviderRepresentation & { type DiscoveryIdentity = IdentityProviderRepresentation & {
discoveryEndpoint?: string; discoveryEndpoint?: string;
@ -44,7 +44,7 @@ export default function AddOpenIdConnect() {
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const { realm } = useRealm(); const { realm } = useRealm();
const save = async (provider: DiscoveryIdentity) => { const onSubmit = async (provider: DiscoveryIdentity) => {
delete provider.discoveryEndpoint; delete provider.discoveryEndpoint;
try { try {
await adminClient.identityProviders.create({ await adminClient.identityProviders.create({
@ -77,7 +77,7 @@ export default function AddOpenIdConnect() {
<FormAccess <FormAccess
role="manage-identity-providers" role="manage-identity-providers"
isHorizontal isHorizontal
onSubmit={handleSubmit(save)} onSubmit={handleSubmit(onSubmit)}
> >
<OIDCGeneralSettings id={id} /> <OIDCGeneralSettings id={id} />
<OpenIdConnectSettings /> <OpenIdConnectSettings />

View file

@ -1,23 +1,23 @@
import { Link, useNavigate } from "react-router-dom-v5-compat";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form";
import { import {
ActionGroup, ActionGroup,
AlertVariant, AlertVariant,
Button, Button,
PageSection, PageSection,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { FormProvider, useForm } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom-v5-compat";
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation"; import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { useAlerts } from "../../components/alert/Alerts";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { ViewHeader } from "../../components/view-header/ViewHeader"; import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient } from "../../context/auth/AdminClient";
import { SamlGeneralSettings } from "./SamlGeneralSettings";
import { SamlConnectSettings } from "./SamlConnectSettings";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import { useAlerts } from "../../components/alert/Alerts";
import { toIdentityProvider } from "../routes/IdentityProvider"; import { toIdentityProvider } from "../routes/IdentityProvider";
import { toIdentityProviders } from "../routes/IdentityProviders"; import { toIdentityProviders } from "../routes/IdentityProviders";
import { SamlConnectSettings } from "./SamlConnectSettings";
import { SamlGeneralSettings } from "./SamlGeneralSettings";
type DiscoveryIdentityProvider = IdentityProviderRepresentation & { type DiscoveryIdentityProvider = IdentityProviderRepresentation & {
discoveryEndpoint?: string; discoveryEndpoint?: string;
@ -40,7 +40,7 @@ export default function AddSamlConnect() {
const { addAlert } = useAlerts(); const { addAlert } = useAlerts();
const { realm } = useRealm(); const { realm } = useRealm();
const save = async (provider: DiscoveryIdentityProvider) => { const onSubmit = async (provider: DiscoveryIdentityProvider) => {
delete provider.discoveryEndpoint; delete provider.discoveryEndpoint;
try { try {
await adminClient.identityProviders.create({ await adminClient.identityProviders.create({
@ -74,7 +74,7 @@ export default function AddSamlConnect() {
<FormAccess <FormAccess
role="manage-identity-providers" role="manage-identity-providers"
isHorizontal isHorizontal
onSubmit={handleSubmit(save)} onSubmit={handleSubmit(onSubmit)}
> >
<SamlGeneralSettings id={id} /> <SamlGeneralSettings id={id} />
<SamlConnectSettings /> <SamlConnectSettings />

View file

@ -1,19 +1,19 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import { import {
FormGroup, FormGroup,
Select, Select,
SelectOption, SelectOption,
SelectVariant, SelectVariant,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import type AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation"; import type AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
import { useFetch, useAdminClient } from "../../context/auth/AdminClient"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import type { FieldProps } from "../component/FormGroupField";
import { SwitchField } from "../component/SwitchField"; import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import type { FieldProps } from "../component/FormGroupField";
const LoginFlow = ({ const LoginFlow = ({
field, field,
@ -49,16 +49,16 @@ const LoginFlow = ({
name={field} name={field}
defaultValue={defaultValue} defaultValue={defaultValue}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId={label} toggleId={label}
required required
onToggle={() => setOpen(!open)} onToggle={() => setOpen(!open)}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value as string); field.onChange(value as string);
setOpen(false); setOpen(false);
}} }}
selections={value || t("common:none")} selections={field.value || t("common:none")}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t(label)} aria-label={t(label)}
isOpen={open} isOpen={open}
@ -77,7 +77,7 @@ const LoginFlow = ({
<> <>
{flows?.map((option) => ( {flows?.map((option) => (
<SelectOption <SelectOption
selected={option.alias === value} selected={option.alias === field.value}
key={option.id} key={option.id}
value={option.alias} value={option.alias}
> >
@ -155,24 +155,24 @@ export const AdvancedSettings = ({ isOIDC, isSAML }: AdvancedSettingsProps) => {
name="config.syncMode" name="config.syncMode"
defaultValue={syncModes[0].toUpperCase()} defaultValue={syncModes[0].toUpperCase()}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="syncMode" toggleId="syncMode"
required required
direction="up" direction="up"
onToggle={() => setSyncModeOpen(!syncModeOpen)} onToggle={() => setSyncModeOpen(!syncModeOpen)}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value as string); field.onChange(value as string);
setSyncModeOpen(false); setSyncModeOpen(false);
}} }}
selections={t(`syncModes.${value.toLowerCase()}`)} selections={t(`syncModes.${field.value.toLowerCase()}`)}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t("syncMode")} aria-label={t("syncMode")}
isOpen={syncModeOpen} isOpen={syncModeOpen}
> >
{syncModes.map((option) => ( {syncModes.map((option) => (
<SelectOption <SelectOption
selected={option === value} selected={option === field.value}
key={option} key={option}
value={option.toUpperCase()} value={option.toUpperCase()}
> >

View file

@ -1,6 +1,3 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { import {
ExpandableSection, ExpandableSection,
FormGroup, FormGroup,
@ -10,10 +7,15 @@ import {
SelectVariant, SelectVariant,
ValidatedOptions, ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import IdentityProviderRepresentation from "libs/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { SwitchField } from "../component/SwitchField"; import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import "./discovery-settings.css"; import "./discovery-settings.css";
@ -29,7 +31,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
register, register,
control, control,
formState: { errors }, formState: { errors },
} = useFormContext(); } = useFormContext<IdentityProviderRepresentation>();
const [namedPolicyDropdownOpen, setNamedPolicyDropdownOpen] = useState(false); const [namedPolicyDropdownOpen, setNamedPolicyDropdownOpen] = useState(false);
const [principalTypeDropdownOpen, setPrincipalTypeDropdownOpen] = const [principalTypeDropdownOpen, setPrincipalTypeDropdownOpen] =
useState(false); useState(false);
@ -50,7 +52,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name: "config.validateSignature", name: "config.validateSignature",
}); });
const principalType = useWatch<string>({ const principalType = useWatch({
control, control,
name: "config.principalType", name: "config.principalType",
}); });
@ -68,11 +70,9 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
} }
> >
<KeycloakTextInput <KeycloakTextInput
type="text"
name="config.entityId"
data-testid="serviceProviderEntityId" data-testid="serviceProviderEntityId"
id="kc-saml-service-provider-entity-id" id="kc-saml-service-provider-entity-id"
ref={register()} {...register("config.entityId")}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
@ -86,11 +86,9 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
} }
> >
<KeycloakTextInput <KeycloakTextInput
type="text"
name="config.idpEntityId"
data-testid="identityProviderEntityId" data-testid="identityProviderEntityId"
id="kc-identity-provider-entity-id" id="kc-identity-provider-entity-id"
ref={register()} {...register("config.idpEntityId")}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
@ -114,14 +112,13 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
type="url" type="url"
data-testid="sso-service-url" data-testid="sso-service-url"
id="kc-sso-service-url" id="kc-sso-service-url"
name="config.singleSignOnServiceUrl"
ref={register({ required: true })}
validated={ validated={
errors.config?.singleSignOnServiceUrl errors.config?.singleSignOnServiceUrl
? ValidatedOptions.error ? ValidatedOptions.error
: ValidatedOptions.default : ValidatedOptions.default
} }
isReadOnly={readOnly} isReadOnly={readOnly}
{...register("config.singleSignOnServiceUrl", { required: true })}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
@ -144,9 +141,8 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
<KeycloakTextInput <KeycloakTextInput
type="url" type="url"
id="single-logout-service-url" id="single-logout-service-url"
name="config.singleLogoutServiceUrl"
ref={register}
isReadOnly={readOnly} isReadOnly={readOnly}
{...register("config.singleLogoutServiceUrl")}
/> />
</FormGroup> </FormGroup>
<SwitchField <SwitchField
@ -170,16 +166,16 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.nameIDPolicyFormat" name="config.nameIDPolicyFormat"
defaultValue={t("persistent")} defaultValue={t("persistent")}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="kc-nameIdPolicyFormat" toggleId="kc-nameIdPolicyFormat"
onToggle={(isExpanded) => setNamedPolicyDropdownOpen(isExpanded)} onToggle={(isExpanded) => setNamedPolicyDropdownOpen(isExpanded)}
isOpen={namedPolicyDropdownOpen} isOpen={namedPolicyDropdownOpen}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value as string); field.onChange(value as string);
setNamedPolicyDropdownOpen(false); setNamedPolicyDropdownOpen(false);
}} }}
selections={value} selections={field.value}
variant={SelectVariant.single} variant={SelectVariant.single}
isDisabled={readOnly} isDisabled={readOnly}
> >
@ -249,7 +245,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.principalType" name="config.principalType"
defaultValue={t("subjectNameId")} defaultValue={t("subjectNameId")}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="kc-principalType" toggleId="kc-principalType"
onToggle={(isExpanded) => onToggle={(isExpanded) =>
@ -257,10 +253,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
} }
isOpen={principalTypeDropdownOpen} isOpen={principalTypeDropdownOpen}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value.toString()); field.onChange(value.toString());
setPrincipalTypeDropdownOpen(false); setPrincipalTypeDropdownOpen(false);
}} }}
selections={value} selections={field.value}
variant={SelectVariant.single} variant={SelectVariant.single}
isDisabled={readOnly} isDisabled={readOnly}
> >
@ -300,12 +296,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
fieldId="principalAttribute" fieldId="principalAttribute"
> >
<KeycloakTextInput <KeycloakTextInput
type="text"
id="principalAttribute" id="principalAttribute"
data-testid="principalAttribute" data-testid="principalAttribute"
name="config.principalAttribute"
ref={register}
isReadOnly={readOnly} isReadOnly={readOnly}
{...register("config.principalAttribute")}
/> />
</FormGroup> </FormGroup>
)} )}
@ -355,7 +349,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.signatureAlgorithm" name="config.signatureAlgorithm"
defaultValue="RSA_SHA256" defaultValue="RSA_SHA256"
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="kc-signatureAlgorithm" toggleId="kc-signatureAlgorithm"
onToggle={(isExpanded) => onToggle={(isExpanded) =>
@ -363,10 +357,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
} }
isOpen={signatureAlgorithmDropdownOpen} isOpen={signatureAlgorithmDropdownOpen}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value.toString()); field.onChange(value.toString());
setSignatureAlgorithmDropdownOpen(false); setSignatureAlgorithmDropdownOpen(false);
}} }}
selections={value} selections={field.value}
variant={SelectVariant.single} variant={SelectVariant.single}
isDisabled={readOnly} isDisabled={readOnly}
> >
@ -394,7 +388,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.xmlSigKeyInfoKeyNameTransformer" name="config.xmlSigKeyInfoKeyNameTransformer"
defaultValue={t("keyID")} defaultValue={t("keyID")}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="kc-samlSignatureKeyName" toggleId="kc-samlSignatureKeyName"
onToggle={(isExpanded) => onToggle={(isExpanded) =>
@ -402,10 +396,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
} }
isOpen={samlSignatureKeyNameDropdownOpen} isOpen={samlSignatureKeyNameDropdownOpen}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value.toString()); field.onChange(value.toString());
setSamlSignatureKeyNameDropdownOpen(false); setSamlSignatureKeyNameDropdownOpen(false);
}} }}
selections={value} selections={field.value}
variant={SelectVariant.single} variant={SelectVariant.single}
isDisabled={readOnly} isDisabled={readOnly}
> >
@ -477,8 +471,8 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.allowedClockSkew" name="config.allowedClockSkew"
defaultValue={0} defaultValue={0}
control={control} control={control}
render={({ onChange, value }) => { render={({ field }) => {
const v = Number(value); const v = Number(field.value);
return ( return (
<NumberInput <NumberInput
data-testid="allowedClockSkew" data-testid="allowedClockSkew"
@ -487,13 +481,13 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
max={2147483} max={2147483}
value={v} value={v}
readOnly readOnly
onPlus={() => onChange(v + 1)} onPlus={() => field.onChange(v + 1)}
onMinus={() => onChange(v - 1)} onMinus={() => field.onChange(v - 1)}
onChange={(event) => { onChange={(event) => {
const value = Number( const value = Number(
(event.target as HTMLInputElement).value (event.target as HTMLInputElement).value
); );
onChange(value < 0 ? 0 : value); field.onChange(value < 0 ? 0 : value);
}} }}
/> />
); );
@ -516,8 +510,8 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.attributeConsumingServiceIndex" name="config.attributeConsumingServiceIndex"
defaultValue={0} defaultValue={0}
control={control} control={control}
render={({ onChange, value }) => { render={({ field }) => {
const v = Number(value); const v = Number(field.value);
return ( return (
<NumberInput <NumberInput
data-testid="attributeConsumingServiceIndex" data-testid="attributeConsumingServiceIndex"
@ -526,13 +520,13 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
max={2147483} max={2147483}
value={v} value={v}
readOnly readOnly
onPlus={() => onChange(v + 1)} onPlus={() => field.onChange(v + 1)}
onMinus={() => onChange(v - 1)} onMinus={() => field.onChange(v - 1)}
onChange={(event) => { onChange={(event) => {
const value = Number( const value = Number(
(event.target as HTMLInputElement).value (event.target as HTMLInputElement).value
); );
onChange(value < 0 ? 0 : value); field.onChange(value < 0 ? 0 : value);
}} }}
/> />
); );
@ -552,12 +546,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
helperTextInvalid={t("common:required")} helperTextInvalid={t("common:required")}
> >
<KeycloakTextInput <KeycloakTextInput
type="text"
id="attributeConsumingServiceName" id="attributeConsumingServiceName"
data-testid="attributeConsumingServiceName" data-testid="attributeConsumingServiceName"
name="config.attributeConsumingServiceName"
ref={register}
isReadOnly={readOnly} isReadOnly={readOnly}
{...register("config.attributeConsumingServiceName")}
/> />
</FormGroup> </FormGroup>
</div> </div>

View file

@ -14,7 +14,7 @@ import {
ToolbarItem, ToolbarItem,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useState } from "react"; import { useState } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form"; import { Controller, FormProvider, useForm } from "react-hook-form-v7";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom-v5-compat"; import { Link, useNavigate } from "react-router-dom-v5-compat";
@ -387,10 +387,10 @@ export default function DetailSettings() {
name="enabled" name="enabled"
control={form.control} control={form.control}
defaultValue={true} defaultValue={true}
render={({ onChange, value }) => ( render={({ field }) => (
<Header <Header
value={value} value={field.value || false}
onChange={onChange} onChange={field.onChange}
save={save} save={save}
toggleDeleteDialog={toggleDeleteDialog} toggleDeleteDialog={toggleDeleteDialog}
/> />

View file

@ -1,19 +1,20 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { import {
ExpandableSection, ExpandableSection,
FormGroup, FormGroup,
ValidatedOptions,
Select, Select,
SelectOption, SelectOption,
SelectVariant, SelectVariant,
ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import IdentityProviderRepresentation from "libs/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { SwitchField } from "../component/SwitchField"; import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import "./discovery-settings.css"; import "./discovery-settings.css";
@ -30,7 +31,7 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
register, register,
control, control,
formState: { errors }, formState: { errors },
} = useFormContext(); } = useFormContext<IdentityProviderRepresentation>();
const validateSignature = useWatch({ const validateSignature = useWatch({
control, control,
@ -62,14 +63,13 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
type="url" type="url"
data-testid="authorizationUrl" data-testid="authorizationUrl"
id="kc-authorization-url" id="kc-authorization-url"
name="config.authorizationUrl"
ref={register({ required: true })}
validated={ validated={
errors.config?.authorizationUrl errors.config?.authorizationUrl
? ValidatedOptions.error ? ValidatedOptions.error
: ValidatedOptions.default : ValidatedOptions.default
} }
isReadOnly={readOnly} isReadOnly={readOnly}
{...register("config.authorizationUrl", { required: true })}
/> />
</FormGroup> </FormGroup>
@ -88,14 +88,13 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
type="url" type="url"
id="tokenUrl" id="tokenUrl"
data-testid="tokenUrl" data-testid="tokenUrl"
name="config.tokenUrl"
ref={register({ required: true })}
validated={ validated={
errors.config?.tokenUrl errors.config?.tokenUrl
? ValidatedOptions.error ? ValidatedOptions.error
: ValidatedOptions.default : ValidatedOptions.default
} }
isReadOnly={readOnly} isReadOnly={readOnly}
{...register("config.tokenUrl", { required: true })}
/> />
</FormGroup> </FormGroup>
<TextField <TextField
@ -152,24 +151,24 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
name="config.pkceMethod" name="config.pkceMethod"
defaultValue={PKCE_METHODS[0]} defaultValue={PKCE_METHODS[0]}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="pkceMethod" toggleId="pkceMethod"
required required
direction="down" direction="down"
onToggle={() => setPkceMethodOpen(!pkceMethodOpen)} onToggle={() => setPkceMethodOpen(!pkceMethodOpen)}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value as string); field.onChange(value as string);
setPkceMethodOpen(false); setPkceMethodOpen(false);
}} }}
selections={t(`${value}`)} selections={t(`${field.value}`)}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t("pkceMethod")} aria-label={t("pkceMethod")}
isOpen={pkceMethodOpen} isOpen={pkceMethodOpen}
> >
{PKCE_METHODS.map((option) => ( {PKCE_METHODS.map((option) => (
<SelectOption <SelectOption
selected={option === value} selected={option === field.value}
key={option} key={option}
value={option} value={option}
> >

View file

@ -1,6 +1,3 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import { import {
ExpandableSection, ExpandableSection,
Form, Form,
@ -10,11 +7,14 @@ import {
SelectOption, SelectOption,
SelectVariant, SelectVariant,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { FormGroupField } from "../component/FormGroupField";
import { SwitchField } from "../component/SwitchField"; import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";
import { FormGroupField } from "../component/FormGroupField";
import { HelpItem } from "../../components/help-enabler/HelpItem";
const promptOptions = { const promptOptions = {
unspecified: "", unspecified: "",
@ -52,22 +52,26 @@ export const ExtendedNonDiscoverySettings = () => {
name="config.prompt" name="config.prompt"
defaultValue="" defaultValue=""
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="prompt" toggleId="prompt"
required required
onToggle={() => setPromptOpen(!promptOpen)} onToggle={() => setPromptOpen(!promptOpen)}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value as string); field.onChange(value as string);
setPromptOpen(false); setPromptOpen(false);
}} }}
selections={value || t(`prompts.unspecified`)} selections={field.value || t(`prompts.unspecified`)}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t("prompt")} aria-label={t("prompt")}
isOpen={promptOpen} isOpen={promptOpen}
> >
{Object.entries(promptOptions).map(([key, val]) => ( {Object.entries(promptOptions).map(([key, val]) => (
<SelectOption selected={val === value} key={key} value={val}> <SelectOption
selected={val === field.value}
key={key}
value={val}
>
{t(`prompts.${key}`)} {t(`prompts.${key}`)}
</SelectOption> </SelectOption>
))} ))}
@ -93,8 +97,8 @@ export const ExtendedNonDiscoverySettings = () => {
name="config.allowedClockSkew" name="config.allowedClockSkew"
defaultValue={0} defaultValue={0}
control={control} control={control}
render={({ onChange, value }) => { render={({ field }) => {
const v = Number(value); const v = Number(field.value);
return ( return (
<NumberInput <NumberInput
data-testid="allowedClockSkew" data-testid="allowedClockSkew"
@ -103,13 +107,13 @@ export const ExtendedNonDiscoverySettings = () => {
max={2147483} max={2147483}
value={v} value={v}
readOnly readOnly
onPlus={() => onChange(v + 1)} onPlus={() => field.onChange(v + 1)}
onMinus={() => onChange(v - 1)} onMinus={() => field.onChange(v - 1)}
onChange={(event) => { onChange={(event) => {
const value = Number( const value = Number(
(event.target as HTMLInputElement).value (event.target as HTMLInputElement).value
); );
onChange(value < 0 ? 0 : value); field.onChange(value < 0 ? 0 : value);
}} }}
/> />
); );

View file

@ -1,15 +1,15 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { import {
FormGroup, FormGroup,
Select, Select,
SelectOption, SelectOption,
SelectVariant, SelectVariant,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { ClientIdSecret } from "../component/ClientIdSecret";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { ClientIdSecret } from "../component/ClientIdSecret";
const clientAuthentications = [ const clientAuthentications = [
"client_secret_post", "client_secret_post",
@ -45,23 +45,23 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
name="config.clientAuthMethod" name="config.clientAuthMethod"
defaultValue={clientAuthentications[0]} defaultValue={clientAuthentications[0]}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="clientAuthentication" toggleId="clientAuthentication"
required required
onToggle={() => setOpenClientAuth(!openClientAuth)} onToggle={() => setOpenClientAuth(!openClientAuth)}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value as string); field.onChange(value as string);
setOpenClientAuth(false); setOpenClientAuth(false);
}} }}
selections={value} selections={field.value}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t("clientAuthentication")} aria-label={t("clientAuthentication")}
isOpen={openClientAuth} isOpen={openClientAuth}
> >
{clientAuthentications.map((option) => ( {clientAuthentications.map((option) => (
<SelectOption <SelectOption
selected={option === value} selected={option === field.value}
key={option} key={option}
value={option} value={option}
> >

View file

@ -1,13 +1,13 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup, ValidatedOptions } from "@patternfly/react-core"; import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom-v5-compat"; import { useParams } from "react-router-dom-v5-compat";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { DisplayOrder } from "../component/DisplayOrder";
import { RedirectUrl } from "../component/RedirectUrl"; import { RedirectUrl } from "../component/RedirectUrl";
import { TextField } from "../component/TextField"; import { TextField } from "../component/TextField";
import { DisplayOrder } from "../component/DisplayOrder";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import type { IdentityProviderParams } from "../routes/IdentityProvider"; import type { IdentityProviderParams } from "../routes/IdentityProvider";
export const OIDCGeneralSettings = ({ id }: { id: string }) => { export const OIDCGeneralSettings = ({ id }: { id: string }) => {
@ -41,14 +41,12 @@ export const OIDCGeneralSettings = ({ id }: { id: string }) => {
<KeycloakTextInput <KeycloakTextInput
isReadOnly={tab === "settings"} isReadOnly={tab === "settings"}
isRequired isRequired
type="text"
id="alias" id="alias"
data-testid="alias" data-testid="alias"
name="alias"
validated={ validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default errors.alias ? ValidatedOptions.error : ValidatedOptions.default
} }
ref={register({ required: true })} {...register("alias", { required: true })}
/> />
</FormGroup> </FormGroup>

View file

@ -1,15 +1,15 @@
import { useFormContext } from "react-hook-form";
import { FormGroup, Title } from "@patternfly/react-core"; import { FormGroup, Title } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAdminClient } from "../../context/auth/AdminClient"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload"; import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
import { useAdminClient } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import { DiscoverySettings } from "./DiscoverySettings";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { addTrailingSlash } from "../../util"; import { addTrailingSlash } from "../../util";
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders"; import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { DiscoverySettings } from "./DiscoverySettings";
export const OpenIdConnectSettings = () => { export const OpenIdConnectSettings = () => {
const { t } = useTranslation("identity-providers"); const { t } = useTranslation("identity-providers");

View file

@ -1,15 +1,15 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import { import {
FormGroup, FormGroup,
Select, Select,
SelectOption, SelectOption,
SelectVariant, SelectVariant,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
const comparisonValues = ["exact", "minimum", "maximum", "better"]; const comparisonValues = ["exact", "minimum", "maximum", "better"];
@ -33,24 +33,24 @@ export const ReqAuthnConstraints = () => {
name="config.authnContextComparisonType" name="config.authnContextComparisonType"
defaultValue={comparisonValues[0]} defaultValue={comparisonValues[0]}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Select <Select
toggleId="comparison" toggleId="comparison"
required required
direction="up" direction="up"
onToggle={(isExpanded) => setComparisonOpen(isExpanded)} onToggle={(isExpanded) => setComparisonOpen(isExpanded)}
onSelect={(_, value) => { onSelect={(_, value) => {
onChange(value.toString()); field.onChange(value.toString());
setComparisonOpen(false); setComparisonOpen(false);
}} }}
selections={value} selections={field.value}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t("comparison")} aria-label={t("comparison")}
isOpen={comparisonOpen} isOpen={comparisonOpen}
> >
{comparisonValues.map((option) => ( {comparisonValues.map((option) => (
<SelectOption <SelectOption
selected={option === value} selected={option === field.value}
key={option} key={option}
value={option} value={option}
> >

View file

@ -1,19 +1,23 @@
import { useFormContext } from "react-hook-form";
import { FormGroup, Title } from "@patternfly/react-core"; import { FormGroup, Title } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useTranslation } from "react-i18next";
import { useAdminClient } from "../../context/auth/AdminClient";
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation"; import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useAdminClient } from "../../context/auth/AdminClient";
import { FileUploadForm } from "../../components/json-file-upload/FileUploadForm"; import { FileUploadForm } from "../../components/json-file-upload/FileUploadForm";
import { useRealm } from "../../context/realm-context/RealmContext";
import { DescriptorSettings } from "./DescriptorSettings";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useRealm } from "../../context/realm-context/RealmContext";
import environment from "../../environment"; import environment from "../../environment";
import { addTrailingSlash } from "../../util"; import { addTrailingSlash } from "../../util";
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders"; import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { DescriptorSettings } from "./DescriptorSettings";
type FormFields = IdentityProviderRepresentation & {
discoveryError: string;
};
export const SamlConnectSettings = () => { export const SamlConnectSettings = () => {
const { t } = useTranslation("identity-providers"); const { t } = useTranslation("identity-providers");
@ -27,7 +31,7 @@ export const SamlConnectSettings = () => {
setError, setError,
clearErrors, clearErrors,
formState: { errors }, formState: { errors },
} = useFormContext(); } = useFormContext<FormFields>();
const setupForm = (result: IdentityProviderRepresentation) => { const setupForm = (result: IdentityProviderRepresentation) => {
Object.entries(result).map(([key, value]) => Object.entries(result).map(([key, value]) =>
@ -92,13 +96,11 @@ export const SamlConnectSettings = () => {
validated={errors.config?.entityId ? "error" : "default"} validated={errors.config?.entityId ? "error" : "default"}
> >
<KeycloakTextInput <KeycloakTextInput
type="text"
name="config.entityId"
data-testid="serviceProviderEntityId" data-testid="serviceProviderEntityId"
id="kc-service-provider-entity-id" id="kc-service-provider-entity-id"
ref={register({ required: true })}
validated={errors.config?.entityId ? "error" : "default"} validated={errors.config?.entityId ? "error" : "default"}
defaultValue={`${environment.authServerUrl}/realms/${realm}`} defaultValue={`${environment.authServerUrl}/realms/${realm}`}
{...register("config.entityId", { required: true })}
/> />
</FormGroup> </FormGroup>

View file

@ -1,15 +1,15 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup, ValidatedOptions } from "@patternfly/react-core"; import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { RedirectUrl } from "../component/RedirectUrl";
import { TextField } from "../component/TextField";
import { DisplayOrder } from "../component/DisplayOrder";
import { FormattedLink } from "../../components/external-link/FormattedLink"; import { FormattedLink } from "../../components/external-link/FormattedLink";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useRealm } from "../../context/realm-context/RealmContext"; import { useRealm } from "../../context/realm-context/RealmContext";
import environment from "../../environment"; import environment from "../../environment";
import { DisplayOrder } from "../component/DisplayOrder";
import { RedirectUrl } from "../component/RedirectUrl";
import { TextField } from "../component/TextField";
import "./saml-general-settings.css"; import "./saml-general-settings.css";
@ -54,15 +54,13 @@ export const SamlGeneralSettings = ({
> >
<KeycloakTextInput <KeycloakTextInput
isRequired isRequired
type="text"
id="alias" id="alias"
data-testid="alias" data-testid="alias"
name="alias"
isReadOnly={isAliasReadonly} isReadOnly={isAliasReadonly}
validated={ validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default errors.alias ? ValidatedOptions.error : ValidatedOptions.default
} }
ref={register({ required: true })} {...register("alias", { required: true })}
/> />
</FormGroup> </FormGroup>

View file

@ -1,10 +1,11 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup, ValidatedOptions } from "@patternfly/react-core"; import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import IdentityProviderRepresentation from "libs/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { PasswordInput } from "../../components/password-input/PasswordInput";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { PasswordInput } from "../../components/password-input/PasswordInput";
export const ClientIdSecret = ({ export const ClientIdSecret = ({
secretRequired = true, secretRequired = true,
@ -18,7 +19,7 @@ export const ClientIdSecret = ({
const { const {
register, register,
formState: { errors }, formState: { errors },
} = useFormContext(); } = useFormContext<IdentityProviderRepresentation>();
return ( return (
<> <>
@ -41,11 +42,9 @@ export const ClientIdSecret = ({
> >
<KeycloakTextInput <KeycloakTextInput
isRequired isRequired
type="text"
id="kc-client-id" id="kc-client-id"
data-testid="clientId" data-testid="clientId"
name="config.clientId" {...register("config.clientId", { required: true })}
ref={register({ required: true })}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
@ -65,23 +64,20 @@ export const ClientIdSecret = ({
} }
helperTextInvalid={t("common:required")} helperTextInvalid={t("common:required")}
> >
{create && ( {create ? (
<PasswordInput <PasswordInput
isRequired={secretRequired} isRequired={secretRequired}
id="kc-client-secret" id="kc-client-secret"
data-testid="clientSecret" data-testid="clientSecret"
name="config.clientSecret" {...register("config.clientSecret", { required: secretRequired })}
ref={register({ required: secretRequired })}
/> />
)} ) : (
{!create && (
<KeycloakTextInput <KeycloakTextInput
isRequired={secretRequired} isRequired={secretRequired}
type="password" type="password"
id="kc-client-secret" id="kc-client-secret"
data-testid="clientSecret" data-testid="clientSecret"
name="config.clientSecret" {...register("config.clientSecret", { required: secretRequired })}
ref={register({ required: secretRequired })}
/> />
)} )}
</FormGroup> </FormGroup>

View file

@ -1,12 +1,12 @@
import { ReactNode, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup, Switch } from "@patternfly/react-core"; import { FormGroup, Switch } from "@patternfly/react-core";
import { ReactNode, useEffect, useState } from "react";
import { useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import environment from "../../environment";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useAdminClient } from "../../context/auth/AdminClient"; import { useAdminClient } from "../../context/auth/AdminClient";
import environment from "../../environment";
type DiscoveryEndpointFieldProps = { type DiscoveryEndpointFieldProps = {
id: string; id: string;
@ -130,7 +130,6 @@ export const DiscoveryEndpointField = ({
> >
<KeycloakTextInput <KeycloakTextInput
type="url" type="url"
name="discoveryEndpoint"
data-testid="discoveryEndpoint" data-testid="discoveryEndpoint"
id="kc-discovery-endpoint" id="kc-discovery-endpoint"
placeholder={ placeholder={
@ -138,7 +137,6 @@ export const DiscoveryEndpointField = ({
? "https://hostname/auth/realms/master/.well-known/openid-configuration" ? "https://hostname/auth/realms/master/.well-known/openid-configuration"
: "" : ""
} }
onBlur={() => setDiscovering(true)}
validated={ validated={
errors.discoveryError || errors.discoveryEndpoint errors.discoveryError || errors.discoveryEndpoint
? "error" ? "error"
@ -151,7 +149,10 @@ export const DiscoveryEndpointField = ({
? environment.resourceUrl + "/discovery-load-indicator.svg" ? environment.resourceUrl + "/discovery-load-indicator.svg"
: "" : ""
} }
ref={register({ required: true })} {...register("discoveryEndpoint", {
required: true,
onBlur: () => setDiscovering(true),
})}
/> />
</FormGroup> </FormGroup>
)} )}

View file

@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import { FormGroup, TextInput } from "@patternfly/react-core"; import { FormGroup, TextInput } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
@ -24,16 +24,16 @@ export const DisplayOrder = () => {
name="config.guiOrder" name="config.guiOrder"
control={control} control={control}
defaultValue="" defaultValue=""
render={({ onChange, value }) => ( render={({ field }) => (
<TextInput <TextInput
id="kc-display-order" id="kc-display-order"
type="number" type="number"
value={value} value={field.value}
data-testid="displayOrder" data-testid="displayOrder"
min={0} min={0}
onChange={(value) => { onChange={(value) => {
const num = Number(value); const num = Number(value);
onChange(value === "" ? value : num < 0 ? 0 : num); field.onChange(value === "" ? value : num < 0 ? 0 : num);
}} }}
/> />
)} )}

View file

@ -1,6 +1,8 @@
import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core"; import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form"; import IdentityProviderRepresentation from "libs/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
@ -47,8 +49,7 @@ const FacebookFields = () => {
> >
<KeycloakTextInput <KeycloakTextInput
id="facebookFetchedFields" id="facebookFetchedFields"
name="config.fetchedFields" {...register("config.fetchedFields")}
ref={register()}
/> />
</FormGroup> </FormGroup>
); );
@ -73,8 +74,7 @@ const GithubFields = () => {
<KeycloakTextInput <KeycloakTextInput
id="baseUrl" id="baseUrl"
type="url" type="url"
name="config.baseUrl" {...register("config.baseUrl")}
ref={register()}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
@ -90,8 +90,7 @@ const GithubFields = () => {
<KeycloakTextInput <KeycloakTextInput
id="apiUrl" id="apiUrl"
type="url" type="url"
name="config.apiUrl" {...register("config.apiUrl")}
ref={register()}
/> />
</FormGroup> </FormGroup>
</> </>
@ -116,8 +115,7 @@ const GoogleFields = () => {
> >
<KeycloakTextInput <KeycloakTextInput
id="googleHostedDomain" id="googleHostedDomain"
name="config.hostedDomain" {...register("config.hostedDomain")}
ref={register()}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
@ -134,13 +132,13 @@ const GoogleFields = () => {
name="config.userIp" name="config.userIp"
defaultValue="false" defaultValue="false"
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Switch <Switch
id="googleUserIp" id="googleUserIp"
label={t("common:on")} label={t("common:on")}
labelOff={t("common:off")} labelOff={t("common:off")}
isChecked={value === "true"} isChecked={field.value === "true"}
onChange={(value) => onChange(value.toString())} onChange={(value) => field.onChange(value.toString())}
aria-label={t("google.userIp")} aria-label={t("google.userIp")}
/> />
)} )}
@ -160,13 +158,13 @@ const GoogleFields = () => {
name="config.offlineAccess" name="config.offlineAccess"
defaultValue="false" defaultValue="false"
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Switch <Switch
id="googleOfflineAccess" id="googleOfflineAccess"
label={t("common:on")} label={t("common:on")}
labelOff={t("common:off")} labelOff={t("common:off")}
isChecked={value === "true"} isChecked={field.value === "true"}
onChange={(value) => onChange(value.toString())} onChange={(value) => field.onChange(value.toString())}
aria-label={t("google.offlineAccess")} aria-label={t("google.offlineAccess")}
/> />
)} )}
@ -181,7 +179,7 @@ const OpenshiftFields = () => {
const { const {
register, register,
formState: { errors }, formState: { errors },
} = useFormContext(); } = useFormContext<IdentityProviderRepresentation>();
return ( return (
<FormGroup <FormGroup
@ -204,9 +202,8 @@ const OpenshiftFields = () => {
<KeycloakTextInput <KeycloakTextInput
id="baseUrl" id="baseUrl"
type="url" type="url"
name="config.baseUrl"
ref={register({ required: true })}
isRequired isRequired
{...register("config.baseUrl", { required: true })}
/> />
</FormGroup> </FormGroup>
); );
@ -231,13 +228,13 @@ const PaypalFields = () => {
name="config.sandbox" name="config.sandbox"
defaultValue="false" defaultValue="false"
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Switch <Switch
id="paypalSandbox" id="paypalSandbox"
label={t("common:on")} label={t("common:on")}
labelOff={t("common:off")} labelOff={t("common:off")}
isChecked={value === "true"} isChecked={field.value === "true"}
onChange={(value) => onChange(value.toString())} onChange={(value) => field.onChange(value.toString())}
aria-label={t("paypal.sandbox")} aria-label={t("paypal.sandbox")}
/> />
)} )}
@ -251,7 +248,7 @@ const StackoverflowFields = () => {
const { const {
register, register,
formState: { errors }, formState: { errors },
} = useFormContext(); } = useFormContext<IdentityProviderRepresentation>();
return ( return (
<FormGroup <FormGroup
@ -271,9 +268,8 @@ const StackoverflowFields = () => {
> >
<KeycloakTextInput <KeycloakTextInput
id="stackoverflowKey" id="stackoverflowKey"
name="config.key"
ref={register({ required: true })}
isRequired isRequired
{...register("config.key", { required: true })}
/> />
</FormGroup> </FormGroup>
); );
@ -296,8 +292,7 @@ const LinkedInFields = () => {
> >
<KeycloakTextInput <KeycloakTextInput
id="profileProjection" id="profileProjection"
name="config.profileProjection" {...register("config.profileProjection")}
ref={register}
/> />
</FormGroup> </FormGroup>
); );

View file

@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import { Switch } from "@patternfly/react-core"; import { Switch } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { FieldProps, FormGroupField } from "./FormGroupField"; import { FieldProps, FormGroupField } from "./FormGroupField";
@ -24,16 +24,18 @@ export const SwitchField = ({
name={field} name={field}
defaultValue={fieldType === "string" ? "false" : false} defaultValue={fieldType === "string" ? "false" : false}
control={control} control={control}
render={({ onChange, value }) => ( render={({ field }) => (
<Switch <Switch
id={label} id={label}
label={t("common:on")} label={t("common:on")}
labelOff={t("common:off")} labelOff={t("common:off")}
isChecked={ isChecked={
fieldType === "string" ? value === "true" : (value as boolean) fieldType === "string"
? field.value === "true"
: (field.value as boolean)
} }
onChange={(value) => onChange={(value) =>
onChange(fieldType === "string" ? "" + value : value) field.onChange(fieldType === "string" ? "" + value : value)
} }
isDisabled={isReadOnly} isDisabled={isReadOnly}
aria-label={label} aria-label={label}

View file

@ -1,4 +1,4 @@
import { useFormContext } from "react-hook-form"; import { useFormContext } from "react-hook-form-v7";
import { FieldProps, FormGroupField } from "./FormGroupField"; import { FieldProps, FormGroupField } from "./FormGroupField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
@ -8,12 +8,10 @@ export const TextField = ({ label, field, isReadOnly = false }: FieldProps) => {
return ( return (
<FormGroupField label={label}> <FormGroupField label={label}>
<KeycloakTextInput <KeycloakTextInput
type="text"
id={label} id={label}
data-testid={label} data-testid={label}
name={field}
ref={register}
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
{...register(field)}
/> />
</FormGroupField> </FormGroupField>
); );