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,
PageSection,
} 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 { Link, useNavigate } from "react-router-dom-v5-compat";
@ -36,7 +36,7 @@ export default function AddIdentityProvider() {
const navigate = useNavigate();
const { realm } = useRealm();
const save = async (provider: IdentityProviderRepresentation) => {
const onSubmit = async (provider: IdentityProviderRepresentation) => {
try {
await adminClient.identityProviders.create({
...provider,
@ -68,7 +68,7 @@ export default function AddIdentityProvider() {
<FormAccess
role="manage-identity-providers"
isHorizontal
onSubmit={handleSubmit(save)}
onSubmit={handleSubmit(onSubmit)}
>
<FormProvider {...form}>
<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 {
ActionGroup,
AlertVariant,
Button,
PageSection,
} 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 { useAlerts } from "../../components/alert/Alerts";
import { FormAccess } from "../../components/form-access/FormAccess";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useAdminClient } from "../../context/auth/AdminClient";
import { OIDCGeneralSettings } from "./OIDCGeneralSettings";
import { OpenIdConnectSettings } from "./OpenIdConnectSettings";
import { useRealm } from "../../context/realm-context/RealmContext";
import { OIDCAuthentication } from "./OIDCAuthentication";
import { useAlerts } from "../../components/alert/Alerts";
import { toIdentityProvider } from "../routes/IdentityProvider";
import { toIdentityProviders } from "../routes/IdentityProviders";
import { OIDCAuthentication } from "./OIDCAuthentication";
import { OIDCGeneralSettings } from "./OIDCGeneralSettings";
import { OpenIdConnectSettings } from "./OpenIdConnectSettings";
type DiscoveryIdentity = IdentityProviderRepresentation & {
discoveryEndpoint?: string;
@ -44,7 +44,7 @@ export default function AddOpenIdConnect() {
const { addAlert, addError } = useAlerts();
const { realm } = useRealm();
const save = async (provider: DiscoveryIdentity) => {
const onSubmit = async (provider: DiscoveryIdentity) => {
delete provider.discoveryEndpoint;
try {
await adminClient.identityProviders.create({
@ -77,7 +77,7 @@ export default function AddOpenIdConnect() {
<FormAccess
role="manage-identity-providers"
isHorizontal
onSubmit={handleSubmit(save)}
onSubmit={handleSubmit(onSubmit)}
>
<OIDCGeneralSettings id={id} />
<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 {
ActionGroup,
AlertVariant,
Button,
PageSection,
} 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 { useAlerts } from "../../components/alert/Alerts";
import { FormAccess } from "../../components/form-access/FormAccess";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useAdminClient } from "../../context/auth/AdminClient";
import { SamlGeneralSettings } from "./SamlGeneralSettings";
import { SamlConnectSettings } from "./SamlConnectSettings";
import { useRealm } from "../../context/realm-context/RealmContext";
import { useAlerts } from "../../components/alert/Alerts";
import { toIdentityProvider } from "../routes/IdentityProvider";
import { toIdentityProviders } from "../routes/IdentityProviders";
import { SamlConnectSettings } from "./SamlConnectSettings";
import { SamlGeneralSettings } from "./SamlGeneralSettings";
type DiscoveryIdentityProvider = IdentityProviderRepresentation & {
discoveryEndpoint?: string;
@ -40,7 +40,7 @@ export default function AddSamlConnect() {
const { addAlert } = useAlerts();
const { realm } = useRealm();
const save = async (provider: DiscoveryIdentityProvider) => {
const onSubmit = async (provider: DiscoveryIdentityProvider) => {
delete provider.discoveryEndpoint;
try {
await adminClient.identityProviders.create({
@ -74,7 +74,7 @@ export default function AddSamlConnect() {
<FormAccess
role="manage-identity-providers"
isHorizontal
onSubmit={handleSubmit(save)}
onSubmit={handleSubmit(onSubmit)}
>
<SamlGeneralSettings id={id} />
<SamlConnectSettings />

View file

@ -1,19 +1,19 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import {
FormGroup,
Select,
SelectOption,
SelectVariant,
} 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 { 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 { TextField } from "../component/TextField";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import type { FieldProps } from "../component/FormGroupField";
const LoginFlow = ({
field,
@ -49,16 +49,16 @@ const LoginFlow = ({
name={field}
defaultValue={defaultValue}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId={label}
required
onToggle={() => setOpen(!open)}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setOpen(false);
}}
selections={value || t("common:none")}
selections={field.value || t("common:none")}
variant={SelectVariant.single}
aria-label={t(label)}
isOpen={open}
@ -77,7 +77,7 @@ const LoginFlow = ({
<>
{flows?.map((option) => (
<SelectOption
selected={option.alias === value}
selected={option.alias === field.value}
key={option.id}
value={option.alias}
>
@ -155,24 +155,24 @@ export const AdvancedSettings = ({ isOIDC, isSAML }: AdvancedSettingsProps) => {
name="config.syncMode"
defaultValue={syncModes[0].toUpperCase()}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="syncMode"
required
direction="up"
onToggle={() => setSyncModeOpen(!syncModeOpen)}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setSyncModeOpen(false);
}}
selections={t(`syncModes.${value.toLowerCase()}`)}
selections={t(`syncModes.${field.value.toLowerCase()}`)}
variant={SelectVariant.single}
aria-label={t("syncMode")}
isOpen={syncModeOpen}
>
{syncModes.map((option) => (
<SelectOption
selected={option === value}
selected={option === field.value}
key={option}
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 {
ExpandableSection,
FormGroup,
@ -10,10 +7,15 @@ import {
SelectVariant,
ValidatedOptions,
} 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 { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { SwitchField } from "../component/SwitchField";
import { TextField } from "../component/TextField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import "./discovery-settings.css";
@ -29,7 +31,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
register,
control,
formState: { errors },
} = useFormContext();
} = useFormContext<IdentityProviderRepresentation>();
const [namedPolicyDropdownOpen, setNamedPolicyDropdownOpen] = useState(false);
const [principalTypeDropdownOpen, setPrincipalTypeDropdownOpen] =
useState(false);
@ -50,7 +52,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name: "config.validateSignature",
});
const principalType = useWatch<string>({
const principalType = useWatch({
control,
name: "config.principalType",
});
@ -68,11 +70,9 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
}
>
<KeycloakTextInput
type="text"
name="config.entityId"
data-testid="serviceProviderEntityId"
id="kc-saml-service-provider-entity-id"
ref={register()}
{...register("config.entityId")}
/>
</FormGroup>
<FormGroup
@ -86,11 +86,9 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
}
>
<KeycloakTextInput
type="text"
name="config.idpEntityId"
data-testid="identityProviderEntityId"
id="kc-identity-provider-entity-id"
ref={register()}
{...register("config.idpEntityId")}
/>
</FormGroup>
<FormGroup
@ -114,14 +112,13 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
type="url"
data-testid="sso-service-url"
id="kc-sso-service-url"
name="config.singleSignOnServiceUrl"
ref={register({ required: true })}
validated={
errors.config?.singleSignOnServiceUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
isReadOnly={readOnly}
{...register("config.singleSignOnServiceUrl", { required: true })}
/>
</FormGroup>
<FormGroup
@ -144,9 +141,8 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
<KeycloakTextInput
type="url"
id="single-logout-service-url"
name="config.singleLogoutServiceUrl"
ref={register}
isReadOnly={readOnly}
{...register("config.singleLogoutServiceUrl")}
/>
</FormGroup>
<SwitchField
@ -170,16 +166,16 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.nameIDPolicyFormat"
defaultValue={t("persistent")}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="kc-nameIdPolicyFormat"
onToggle={(isExpanded) => setNamedPolicyDropdownOpen(isExpanded)}
isOpen={namedPolicyDropdownOpen}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setNamedPolicyDropdownOpen(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
isDisabled={readOnly}
>
@ -249,7 +245,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.principalType"
defaultValue={t("subjectNameId")}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="kc-principalType"
onToggle={(isExpanded) =>
@ -257,10 +253,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
}
isOpen={principalTypeDropdownOpen}
onSelect={(_, value) => {
onChange(value.toString());
field.onChange(value.toString());
setPrincipalTypeDropdownOpen(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
isDisabled={readOnly}
>
@ -300,12 +296,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
fieldId="principalAttribute"
>
<KeycloakTextInput
type="text"
id="principalAttribute"
data-testid="principalAttribute"
name="config.principalAttribute"
ref={register}
isReadOnly={readOnly}
{...register("config.principalAttribute")}
/>
</FormGroup>
)}
@ -355,7 +349,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.signatureAlgorithm"
defaultValue="RSA_SHA256"
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="kc-signatureAlgorithm"
onToggle={(isExpanded) =>
@ -363,10 +357,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
}
isOpen={signatureAlgorithmDropdownOpen}
onSelect={(_, value) => {
onChange(value.toString());
field.onChange(value.toString());
setSignatureAlgorithmDropdownOpen(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
isDisabled={readOnly}
>
@ -394,7 +388,7 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.xmlSigKeyInfoKeyNameTransformer"
defaultValue={t("keyID")}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="kc-samlSignatureKeyName"
onToggle={(isExpanded) =>
@ -402,10 +396,10 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
}
isOpen={samlSignatureKeyNameDropdownOpen}
onSelect={(_, value) => {
onChange(value.toString());
field.onChange(value.toString());
setSamlSignatureKeyNameDropdownOpen(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
isDisabled={readOnly}
>
@ -477,8 +471,8 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
name="config.allowedClockSkew"
defaultValue={0}
control={control}
render={({ onChange, value }) => {
const v = Number(value);
render={({ field }) => {
const v = Number(field.value);
return (
<NumberInput
data-testid="allowedClockSkew"
@ -487,13 +481,13 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
max={2147483}
value={v}
readOnly
onPlus={() => onChange(v + 1)}
onMinus={() => onChange(v - 1)}
onPlus={() => field.onChange(v + 1)}
onMinus={() => field.onChange(v - 1)}
onChange={(event) => {
const value = Number(
(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"
defaultValue={0}
control={control}
render={({ onChange, value }) => {
const v = Number(value);
render={({ field }) => {
const v = Number(field.value);
return (
<NumberInput
data-testid="attributeConsumingServiceIndex"
@ -526,13 +520,13 @@ const Fields = ({ readOnly }: DescriptorSettingsProps) => {
max={2147483}
value={v}
readOnly
onPlus={() => onChange(v + 1)}
onMinus={() => onChange(v - 1)}
onPlus={() => field.onChange(v + 1)}
onMinus={() => field.onChange(v - 1)}
onChange={(event) => {
const value = Number(
(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")}
>
<KeycloakTextInput
type="text"
id="attributeConsumingServiceName"
data-testid="attributeConsumingServiceName"
name="config.attributeConsumingServiceName"
ref={register}
isReadOnly={readOnly}
{...register("config.attributeConsumingServiceName")}
/>
</FormGroup>
</div>

View file

@ -14,7 +14,7 @@ import {
ToolbarItem,
} from "@patternfly/react-core";
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 { useHistory } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom-v5-compat";
@ -387,10 +387,10 @@ export default function DetailSettings() {
name="enabled"
control={form.control}
defaultValue={true}
render={({ onChange, value }) => (
render={({ field }) => (
<Header
value={value}
onChange={onChange}
value={field.value || false}
onChange={field.onChange}
save={save}
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 {
ExpandableSection,
FormGroup,
ValidatedOptions,
Select,
SelectOption,
SelectVariant,
ValidatedOptions,
} 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 { TextField } from "../component/TextField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import "./discovery-settings.css";
@ -30,7 +31,7 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
register,
control,
formState: { errors },
} = useFormContext();
} = useFormContext<IdentityProviderRepresentation>();
const validateSignature = useWatch({
control,
@ -62,14 +63,13 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
type="url"
data-testid="authorizationUrl"
id="kc-authorization-url"
name="config.authorizationUrl"
ref={register({ required: true })}
validated={
errors.config?.authorizationUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
isReadOnly={readOnly}
{...register("config.authorizationUrl", { required: true })}
/>
</FormGroup>
@ -88,14 +88,13 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
type="url"
id="tokenUrl"
data-testid="tokenUrl"
name="config.tokenUrl"
ref={register({ required: true })}
validated={
errors.config?.tokenUrl
? ValidatedOptions.error
: ValidatedOptions.default
}
isReadOnly={readOnly}
{...register("config.tokenUrl", { required: true })}
/>
</FormGroup>
<TextField
@ -152,24 +151,24 @@ const Fields = ({ readOnly }: DiscoverySettingsProps) => {
name="config.pkceMethod"
defaultValue={PKCE_METHODS[0]}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="pkceMethod"
required
direction="down"
onToggle={() => setPkceMethodOpen(!pkceMethodOpen)}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setPkceMethodOpen(false);
}}
selections={t(`${value}`)}
selections={t(`${field.value}`)}
variant={SelectVariant.single}
aria-label={t("pkceMethod")}
isOpen={pkceMethodOpen}
>
{PKCE_METHODS.map((option) => (
<SelectOption
selected={option === value}
selected={option === field.value}
key={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 {
ExpandableSection,
Form,
@ -10,11 +7,14 @@ import {
SelectOption,
SelectVariant,
} 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 { TextField } from "../component/TextField";
import { FormGroupField } from "../component/FormGroupField";
import { HelpItem } from "../../components/help-enabler/HelpItem";
const promptOptions = {
unspecified: "",
@ -52,22 +52,26 @@ export const ExtendedNonDiscoverySettings = () => {
name="config.prompt"
defaultValue=""
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="prompt"
required
onToggle={() => setPromptOpen(!promptOpen)}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setPromptOpen(false);
}}
selections={value || t(`prompts.unspecified`)}
selections={field.value || t(`prompts.unspecified`)}
variant={SelectVariant.single}
aria-label={t("prompt")}
isOpen={promptOpen}
>
{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}`)}
</SelectOption>
))}
@ -93,8 +97,8 @@ export const ExtendedNonDiscoverySettings = () => {
name="config.allowedClockSkew"
defaultValue={0}
control={control}
render={({ onChange, value }) => {
const v = Number(value);
render={({ field }) => {
const v = Number(field.value);
return (
<NumberInput
data-testid="allowedClockSkew"
@ -103,13 +107,13 @@ export const ExtendedNonDiscoverySettings = () => {
max={2147483}
value={v}
readOnly
onPlus={() => onChange(v + 1)}
onMinus={() => onChange(v - 1)}
onPlus={() => field.onChange(v + 1)}
onMinus={() => field.onChange(v - 1)}
onChange={(event) => {
const value = Number(
(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 {
FormGroup,
Select,
SelectOption,
SelectVariant,
} 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 { ClientIdSecret } from "../component/ClientIdSecret";
const clientAuthentications = [
"client_secret_post",
@ -45,23 +45,23 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
name="config.clientAuthMethod"
defaultValue={clientAuthentications[0]}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="clientAuthentication"
required
onToggle={() => setOpenClientAuth(!openClientAuth)}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setOpenClientAuth(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
aria-label={t("clientAuthentication")}
isOpen={openClientAuth}
>
{clientAuthentications.map((option) => (
<SelectOption
selected={option === value}
selected={option === field.value}
key={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 { useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom-v5-compat";
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 { TextField } from "../component/TextField";
import { DisplayOrder } from "../component/DisplayOrder";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import type { IdentityProviderParams } from "../routes/IdentityProvider";
export const OIDCGeneralSettings = ({ id }: { id: string }) => {
@ -41,14 +41,12 @@ export const OIDCGeneralSettings = ({ id }: { id: string }) => {
<KeycloakTextInput
isReadOnly={tab === "settings"}
isRequired
type="text"
id="alias"
data-testid="alias"
name="alias"
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
ref={register({ required: true })}
{...register("alias", { required: true })}
/>
</FormGroup>

View file

@ -1,15 +1,15 @@
import { useFormContext } from "react-hook-form";
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 { HelpItem } from "../../components/help-enabler/HelpItem";
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
import { useAdminClient } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext";
import { DiscoverySettings } from "./DiscoverySettings";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { addTrailingSlash } from "../../util";
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { DiscoverySettings } from "./DiscoverySettings";
export const OpenIdConnectSettings = () => {
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 {
FormGroup,
Select,
SelectOption,
SelectVariant,
} 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 { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
const comparisonValues = ["exact", "minimum", "maximum", "better"];
@ -33,24 +33,24 @@ export const ReqAuthnConstraints = () => {
name="config.authnContextComparisonType"
defaultValue={comparisonValues[0]}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="comparison"
required
direction="up"
onToggle={(isExpanded) => setComparisonOpen(isExpanded)}
onSelect={(_, value) => {
onChange(value.toString());
field.onChange(value.toString());
setComparisonOpen(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
aria-label={t("comparison")}
isOpen={comparisonOpen}
>
{comparisonValues.map((option) => (
<SelectOption
selected={option === value}
selected={option === field.value}
key={option}
value={option}
>

View file

@ -1,19 +1,23 @@
import { useFormContext } from "react-hook-form";
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 { 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 { useRealm } from "../../context/realm-context/RealmContext";
import { DescriptorSettings } from "./DescriptorSettings";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useRealm } from "../../context/realm-context/RealmContext";
import environment from "../../environment";
import { addTrailingSlash } from "../../util";
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
import { DescriptorSettings } from "./DescriptorSettings";
type FormFields = IdentityProviderRepresentation & {
discoveryError: string;
};
export const SamlConnectSettings = () => {
const { t } = useTranslation("identity-providers");
@ -27,7 +31,7 @@ export const SamlConnectSettings = () => {
setError,
clearErrors,
formState: { errors },
} = useFormContext();
} = useFormContext<FormFields>();
const setupForm = (result: IdentityProviderRepresentation) => {
Object.entries(result).map(([key, value]) =>
@ -92,13 +96,11 @@ export const SamlConnectSettings = () => {
validated={errors.config?.entityId ? "error" : "default"}
>
<KeycloakTextInput
type="text"
name="config.entityId"
data-testid="serviceProviderEntityId"
id="kc-service-provider-entity-id"
ref={register({ required: true })}
validated={errors.config?.entityId ? "error" : "default"}
defaultValue={`${environment.authServerUrl}/realms/${realm}`}
{...register("config.entityId", { required: true })}
/>
</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 { 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 { HelpItem } from "../../components/help-enabler/HelpItem";
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";
@ -54,15 +54,13 @@ export const SamlGeneralSettings = ({
>
<KeycloakTextInput
isRequired
type="text"
id="alias"
data-testid="alias"
name="alias"
isReadOnly={isAliasReadonly}
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
ref={register({ required: true })}
{...register("alias", { required: true })}
/>
</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 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 { PasswordInput } from "../../components/password-input/PasswordInput";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { PasswordInput } from "../../components/password-input/PasswordInput";
export const ClientIdSecret = ({
secretRequired = true,
@ -18,7 +19,7 @@ export const ClientIdSecret = ({
const {
register,
formState: { errors },
} = useFormContext();
} = useFormContext<IdentityProviderRepresentation>();
return (
<>
@ -41,11 +42,9 @@ export const ClientIdSecret = ({
>
<KeycloakTextInput
isRequired
type="text"
id="kc-client-id"
data-testid="clientId"
name="config.clientId"
ref={register({ required: true })}
{...register("config.clientId", { required: true })}
/>
</FormGroup>
<FormGroup
@ -65,23 +64,20 @@ export const ClientIdSecret = ({
}
helperTextInvalid={t("common:required")}
>
{create && (
{create ? (
<PasswordInput
isRequired={secretRequired}
id="kc-client-secret"
data-testid="clientSecret"
name="config.clientSecret"
ref={register({ required: secretRequired })}
{...register("config.clientSecret", { required: secretRequired })}
/>
)}
{!create && (
) : (
<KeycloakTextInput
isRequired={secretRequired}
type="password"
id="kc-client-secret"
data-testid="clientSecret"
name="config.clientSecret"
ref={register({ required: secretRequired })}
{...register("config.clientSecret", { required: secretRequired })}
/>
)}
</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 { 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 { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useAdminClient } from "../../context/auth/AdminClient";
import environment from "../../environment";
type DiscoveryEndpointFieldProps = {
id: string;
@ -130,7 +130,6 @@ export const DiscoveryEndpointField = ({
>
<KeycloakTextInput
type="url"
name="discoveryEndpoint"
data-testid="discoveryEndpoint"
id="kc-discovery-endpoint"
placeholder={
@ -138,7 +137,6 @@ export const DiscoveryEndpointField = ({
? "https://hostname/auth/realms/master/.well-known/openid-configuration"
: ""
}
onBlur={() => setDiscovering(true)}
validated={
errors.discoveryError || errors.discoveryEndpoint
? "error"
@ -151,7 +149,10 @@ export const DiscoveryEndpointField = ({
? environment.resourceUrl + "/discovery-load-indicator.svg"
: ""
}
ref={register({ required: true })}
{...register("discoveryEndpoint", {
required: true,
onBlur: () => setDiscovering(true),
})}
/>
</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 { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";
@ -24,16 +24,16 @@ export const DisplayOrder = () => {
name="config.guiOrder"
control={control}
defaultValue=""
render={({ onChange, value }) => (
render={({ field }) => (
<TextInput
id="kc-display-order"
type="number"
value={value}
value={field.value}
data-testid="displayOrder"
min={0}
onChange={(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 { 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 { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
@ -47,8 +49,7 @@ const FacebookFields = () => {
>
<KeycloakTextInput
id="facebookFetchedFields"
name="config.fetchedFields"
ref={register()}
{...register("config.fetchedFields")}
/>
</FormGroup>
);
@ -73,8 +74,7 @@ const GithubFields = () => {
<KeycloakTextInput
id="baseUrl"
type="url"
name="config.baseUrl"
ref={register()}
{...register("config.baseUrl")}
/>
</FormGroup>
<FormGroup
@ -90,8 +90,7 @@ const GithubFields = () => {
<KeycloakTextInput
id="apiUrl"
type="url"
name="config.apiUrl"
ref={register()}
{...register("config.apiUrl")}
/>
</FormGroup>
</>
@ -116,8 +115,7 @@ const GoogleFields = () => {
>
<KeycloakTextInput
id="googleHostedDomain"
name="config.hostedDomain"
ref={register()}
{...register("config.hostedDomain")}
/>
</FormGroup>
<FormGroup
@ -134,13 +132,13 @@ const GoogleFields = () => {
name="config.userIp"
defaultValue="false"
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Switch
id="googleUserIp"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value === "true"}
onChange={(value) => onChange(value.toString())}
isChecked={field.value === "true"}
onChange={(value) => field.onChange(value.toString())}
aria-label={t("google.userIp")}
/>
)}
@ -160,13 +158,13 @@ const GoogleFields = () => {
name="config.offlineAccess"
defaultValue="false"
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Switch
id="googleOfflineAccess"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value === "true"}
onChange={(value) => onChange(value.toString())}
isChecked={field.value === "true"}
onChange={(value) => field.onChange(value.toString())}
aria-label={t("google.offlineAccess")}
/>
)}
@ -181,7 +179,7 @@ const OpenshiftFields = () => {
const {
register,
formState: { errors },
} = useFormContext();
} = useFormContext<IdentityProviderRepresentation>();
return (
<FormGroup
@ -204,9 +202,8 @@ const OpenshiftFields = () => {
<KeycloakTextInput
id="baseUrl"
type="url"
name="config.baseUrl"
ref={register({ required: true })}
isRequired
{...register("config.baseUrl", { required: true })}
/>
</FormGroup>
);
@ -231,13 +228,13 @@ const PaypalFields = () => {
name="config.sandbox"
defaultValue="false"
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Switch
id="paypalSandbox"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value === "true"}
onChange={(value) => onChange(value.toString())}
isChecked={field.value === "true"}
onChange={(value) => field.onChange(value.toString())}
aria-label={t("paypal.sandbox")}
/>
)}
@ -251,7 +248,7 @@ const StackoverflowFields = () => {
const {
register,
formState: { errors },
} = useFormContext();
} = useFormContext<IdentityProviderRepresentation>();
return (
<FormGroup
@ -271,9 +268,8 @@ const StackoverflowFields = () => {
>
<KeycloakTextInput
id="stackoverflowKey"
name="config.key"
ref={register({ required: true })}
isRequired
{...register("config.key", { required: true })}
/>
</FormGroup>
);
@ -296,8 +292,7 @@ const LinkedInFields = () => {
>
<KeycloakTextInput
id="profileProjection"
name="config.profileProjection"
ref={register}
{...register("config.profileProjection")}
/>
</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 { Controller, useFormContext } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { FieldProps, FormGroupField } from "./FormGroupField";
@ -24,16 +24,18 @@ export const SwitchField = ({
name={field}
defaultValue={fieldType === "string" ? "false" : false}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Switch
id={label}
label={t("common:on")}
labelOff={t("common:off")}
isChecked={
fieldType === "string" ? value === "true" : (value as boolean)
fieldType === "string"
? field.value === "true"
: (field.value as boolean)
}
onChange={(value) =>
onChange(fieldType === "string" ? "" + value : value)
field.onChange(fieldType === "string" ? "" + value : value)
}
isDisabled={isReadOnly}
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 { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
@ -8,12 +8,10 @@ export const TextField = ({ label, field, isReadOnly = false }: FieldProps) => {
return (
<FormGroupField label={label}>
<KeycloakTextInput
type="text"
id={label}
data-testid={label}
name={field}
ref={register}
isReadOnly={isReadOnly}
{...register(field)}
/>
</FormGroupField>
);