Upgrade to React Hook Form version 7 (#4239)

This commit is contained in:
Jon Koops 2023-01-26 10:31:07 +01:00 committed by GitHub
parent 014d3ce0e4
commit 8f05a102af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
179 changed files with 1322 additions and 1871 deletions

View file

@ -27,7 +27,7 @@ export const EditTheResource = ({
const { t } = useTranslation();
const { addAlert, addError } = useAlerts();
const form = useForm<FormValues>({ shouldUnregister: false });
const form = useForm<FormValues>();
const { control, register, reset, handleSubmit } = form;
const { fields } = useFieldArray<FormValues>({

View file

@ -998,12 +998,6 @@ describe("Clients test", () => {
adminClient.deleteClient(keysName);
});
it("Change use JWKS Url", () => {
const keysTab = clientDetailsPage.goToKeysTab();
keysTab.formUtils().checkSaveButtonIsDisabled(true);
keysTab.toggleUseJwksUrl().formUtils().checkSaveButtonIsDisabled(false);
});
it("Generate new keys", () => {
const keysTab = clientDetailsPage.goToKeysTab();
keysTab.clickGenerate();

View file

@ -274,7 +274,7 @@ describe("Events tests", () => {
.goToEventsTab()
.goToAdminEventsSettingsSubTab()
.disableSaveEvents()
.save()
.save({ waitForRealm: false, waitForConfig: true })
.clearAdminEvents();
sidebarPage.goToEvents();
@ -300,7 +300,7 @@ describe("Events tests", () => {
.goToEventsTab()
.goToAdminEventsSettingsSubTab()
.enableSaveEvents()
.save();
.save({ waitForRealm: false, waitForConfig: true });
sidebarPage.goToEvents();
eventsPage.goToAdminEventsTab();
adminEventsTab
@ -373,7 +373,7 @@ describe("Events tests", () => {
.goToEventsTab()
.goToAdminEventsSettingsSubTab()
.disableSaveEvents()
.save();
.save({ waitForRealm: false, waitForConfig: true });
sidebarPage.goToEvents();
eventsPage.goToAdminEventsTab();
adminEventsTab

View file

@ -197,7 +197,9 @@ export default class PageObject {
itemName: string,
element?: Cypress.Chainable<JQuery>
) {
element = element ?? cy.get(this.selectMenuItem).contains(itemName);
element =
element ??
cy.get(this.selectMenuItem).contains(new RegExp(`^${itemName}$`));
return this.clickDropdownMenuItem(itemName, element);
}

View file

@ -36,10 +36,21 @@ export default class AdminEventsSettingsTab extends PageObject {
return this;
}
save() {
cy.intercept("/admin/realms/master").as("saveRealm");
save(
{ waitForRealm, waitForConfig } = {
waitForRealm: true,
waitForConfig: false,
}
) {
waitForRealm && cy.intercept("/admin/realms/master").as("saveRealm");
waitForConfig &&
cy.intercept("/admin/realms/master/events/config").as("saveConfig");
cy.get(this.saveBtn).click();
cy.wait("@saveRealm");
waitForRealm && cy.wait("@saveRealm");
waitForConfig && cy.wait("@saveConfig");
return this;
}
}

View file

@ -72,8 +72,7 @@
"react-dom": "^17.0.2",
"react-dropzone": "^14.2.3",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^6.15.8",
"react-hook-form-v7": "npm:react-hook-form@^7.35.1",
"react-hook-form": "^7.42.1",
"react-i18next": "^12.0.0",
"react-router-dom": "^6.6.2",
"react-use-localstorage": "^3.5.3",

View file

@ -10,7 +10,7 @@ import {
SelectOption,
SelectVariant,
} from "@patternfly/react-core";
import { Controller, useForm } from "react-hook-form-v7";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAlerts } from "../components/alert/Alerts";

View file

@ -8,7 +8,7 @@ import {
ModalVariant,
} from "@patternfly/react-core";
import { useEffect } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -33,7 +33,7 @@ export const DuplicateFlowModal = ({
}: DuplicateFlowModalProps) => {
const { t } = useTranslation("authentication");
const form = useForm<AuthenticationFlowRepresentation>({ mode: "onChange" });
const { setValue, trigger, getValues, handleSubmit } = form;
const { setValue, getValues, handleSubmit } = form;
const { adminClient } = useAdminClient();
const { addAlert, addError } = useAlerts();
const navigate = useNavigate();
@ -45,7 +45,6 @@ export const DuplicateFlowModal = ({
}, [name, description]);
const onSubmit = async () => {
if (!(await trigger())) return;
const form = getValues();
try {
await adminClient.authenticationManagement.copyFlow({

View file

@ -8,7 +8,7 @@ import {
ModalVariant,
} from "@patternfly/react-core";
import { useEffect } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAlerts } from "../components/alert/Alerts";

View file

@ -10,7 +10,7 @@ import {
} from "@patternfly/react-core";
import { PencilAltIcon } from "@patternfly/react-icons";
import { useEffect } from "react";
import { useForm } from "react-hook-form-v7";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -1,6 +1,5 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form";
import type AuthenticatorConfigInfoRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation";
import type AuthenticatorConfigRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation";
import {
ActionGroup,
AlertVariant,
@ -14,16 +13,17 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { CogIcon, TrashIcon } from "@patternfly/react-icons";
import { useEffect, useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type AuthenticatorConfigRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation";
import type AuthenticatorConfigInfoRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation";
import type { ExpandableExecution } from "../execution-model";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useAlerts } from "../../components/alert/Alerts";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { DynamicComponents } from "../../components/dynamic/DynamicComponents";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { convertFormValuesToObject, convertToFormValues } from "../../util";
import type { ExpandableExecution } from "../execution-model";
type ExecutionConfigModalForm = {
alias: string;
@ -46,7 +46,7 @@ export const ExecutionConfigModal = ({
const [configDescription, setConfigDescription] =
useState<AuthenticatorConfigInfoRepresentation>();
const form = useForm<ExecutionConfigModalForm>({ shouldUnregister: false });
const form = useForm<ExecutionConfigModalForm>();
const {
register,
setValue,
@ -148,16 +148,14 @@ export const ExecutionConfigModal = ({
>
<KeycloakTextInput
isReadOnly={!!config}
type="text"
id="alias"
name="alias"
data-testid="alias"
ref={register({ required: true })}
validated={
errors.alias
? ValidatedOptions.error
: ValidatedOptions.default
}
{...register("alias", { required: true })}
/>
</FormGroup>
<FormProvider {...form}>

View file

@ -12,7 +12,7 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form-v7";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../../components/help-enabler/HelpItem";

View file

@ -5,7 +5,7 @@ import {
Button,
PageSection,
} from "@patternfly/react-core";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";

View file

@ -6,7 +6,7 @@ import {
SelectVariant,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -1,6 +1,6 @@
import AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -17,7 +17,7 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { useEffect, useMemo } from "react";
import { Controller, useForm, useWatch } from "react-hook-form-v7";
import { Controller, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAlerts } from "../../components/alert/Alerts";

View file

@ -18,7 +18,7 @@ import {
} from "@patternfly/react-core";
import { PlusCircleIcon } from "@patternfly/react-icons";
import { useEffect, useMemo, useState } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type PasswordPolicyTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/passwordPolicyTypeRepresentation";
@ -94,7 +94,6 @@ export const PasswordPolicy = ({
const form = useForm<SubmittedValues>({
defaultValues: {},
shouldUnregister: false,
});
const {
handleSubmit,

View file

@ -9,7 +9,7 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { MinusCircleIcon } from "@patternfly/react-icons";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -20,7 +20,7 @@ import {
FormProvider,
useForm,
useFormContext,
} from "react-hook-form-v7";
} from "react-hook-form";
import { useTranslation } from "react-i18next";
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
@ -29,7 +29,7 @@ import { FormAccess } from "../../components/form-access/FormAccess";
import { useHelp } from "../../components/help-enabler/HelpHeader";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { TimeSelector } from "../../components/time-selector/TimeSelector";
import { useAdminClient } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext";
@ -163,7 +163,7 @@ export const WebauthnPolicy = ({
const { addAlert, addError } = useAlerts();
const { realm: realmName } = useRealm();
const { enabled } = useHelp();
const form = useForm({ mode: "onChange", shouldUnregister: false });
const form = useForm({ mode: "onChange" });
const {
control,
register,

View file

@ -40,7 +40,12 @@ export default function MappingDetails() {
const { id, mapperId } = useParams<MapperParams>();
const form = useForm();
const { register, setValue, errors, handleSubmit } = form;
const {
register,
setValue,
formState: { errors },
handleSubmit,
} = form;
const [mapping, setMapping] = useState<ProtocolMapperTypeRepresentation>();
const [config, setConfig] = useState<{
protocol?: string;
@ -228,14 +233,12 @@ export default function MappingDetails() {
helperTextInvalid={t("common:required")}
>
<KeycloakTextInput
ref={register({ required: true })}
type="text"
id="name"
name="name"
isReadOnly={isUpdating}
validated={
errors.name ? ValidatedOptions.error : ValidatedOptions.default
}
{...register("name", { required: true })}
/>
</FormGroup>
<FormProvider {...form}>

View file

@ -10,7 +10,7 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { useEffect, useState } from "react";
import { Controller, useForm, useWatch } from "react-hook-form-v7";
import { Controller, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";

View file

@ -1,6 +1,6 @@
import { AlertVariant, PageSection, Text } from "@patternfly/react-core";
import type { TFunction } from "i18next";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";

View file

@ -1,5 +1,5 @@
import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../components/form-access/FormAccess";

View file

@ -13,12 +13,7 @@ import {
import { InfoCircleIcon } from "@patternfly/react-icons";
import { cloneDeep, sortBy } from "lodash-es";
import { useMemo, useState } from "react";
import {
Controller,
FormProvider,
useForm,
useWatch,
} from "react-hook-form-v7";
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -210,7 +205,7 @@ export default function ClientDetails() {
const [downloadDialogOpen, toggleDownloadDialogOpen] = useToggle();
const [changeAuthenticatorOpen, toggleChangeAuthenticatorOpen] = useToggle();
const form = useForm<FormFields>({ shouldUnregister: false });
const form = useForm<FormFields>();
const { clientId } = useParams<ClientParams>();
const [key, setKey] = useState(0);

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { Form } from "@patternfly/react-core";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";

View file

@ -1,5 +1,5 @@
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -6,7 +6,7 @@ import {
InputGroup,
Switch,
} from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";

View file

@ -5,7 +5,7 @@ import {
SelectVariant,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -1,10 +1,10 @@
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { useRealm } from "../../context/realm-context/RealmContext";
import environment from "../../environment";
import { convertAttributeNameToForm } from "../../util";

View file

@ -6,7 +6,7 @@ import {
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -1,5 +1,5 @@
import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -7,7 +7,7 @@ import {
WizardFooter,
} from "@patternfly/react-core";
import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";

View file

@ -6,12 +6,7 @@ import {
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
import {
Controller,
Path,
PathValue,
useFormContext,
} from "react-hook-form-v7";
import { Controller, Path, PathValue, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -5,7 +5,7 @@ import {
SelectVariant,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -6,7 +6,7 @@ import {
FormGroup,
Modal,
} from "@patternfly/react-core";
import { useForm } from "react-hook-form-v7";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAlerts } from "../../components/alert/Alerts";

View file

@ -9,13 +9,13 @@ import {
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeyValueInput } from "../../components/key-value-form/hook-form-v7/KeyValueInput";
import { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
import { KeyValueInput } from "../../components/key-value-form/KeyValueInput";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { TimeSelector } from "../../components/time-selector/TimeSelector";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext";

View file

@ -1,5 +1,5 @@
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -8,7 +8,7 @@ import {
} from "@patternfly/react-core";
import { sortBy } from "lodash-es";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -9,7 +9,7 @@ import {
ToolbarItem,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAlerts } from "../../components/alert/Alerts";

View file

@ -7,12 +7,12 @@ import {
SelectVariant,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { convertAttributeNameToForm, sortProviders } from "../../util";
import { FormFields } from "../ClientDetails";

View file

@ -1,5 +1,5 @@
import { ActionGroup, Button, FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -1,5 +1,5 @@
import { ActionGroup, Button, FormGroup, Switch } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../../components/form-access/FormAccess";

View file

@ -7,7 +7,7 @@ import {
Tooltip,
} from "@patternfly/react-core";
import { useEffect, useRef } from "react";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { Trans, useTranslation } from "react-i18next";
import { Link } from "react-router-dom";

View file

@ -7,7 +7,7 @@ import {
SplitItem,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -10,7 +10,7 @@ import {
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form-v7";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
@ -21,7 +21,7 @@ import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/def
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
import { ClientSelect } from "../../components/client/react-hook-v7/ClientSelect";
import { ClientSelect } from "../../components/client/ClientSelect";
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import type { KeyValueType } from "../../components/key-value-form/key-value-convert";

View file

@ -1,5 +1,5 @@
import { FormGroup, Radio } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFieldArray, useFormContext } from "react-hook-form-v7";
import { Controller, useFieldArray, useFormContext } from "react-hook-form";
import {
Button,
Select,

View file

@ -13,12 +13,7 @@ import {
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
import {
Controller,
FormProvider,
useForm,
useWatch,
} from "react-hook-form-v7";
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
@ -50,7 +45,6 @@ export default function PermissionDetails() {
const { t } = useTranslation("clients");
const form = useForm<FormFields>({
shouldUnregister: false,
mode: "onChange",
});
const {

View file

@ -14,7 +14,7 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form-v7";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
@ -23,10 +23,10 @@ import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import type { KeyValueType } from "../../components/key-value-form/key-value-convert";
import { KeyValueInput } from "../../components/key-value-form/hook-form-v7/KeyValueInput";
import { KeyValueInput } from "../../components/key-value-form/KeyValueInput";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { MultiLineInput } from "../../components/multi-line-input/hook-form-v7/MultiLineInput";
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { convertFormValuesToObject, convertToFormValues } from "../../util";
@ -55,7 +55,6 @@ export default function ResourceDetails() {
const { adminClient } = useAdminClient();
const { addAlert, addError } = useAlerts();
const form = useForm<SubmittedResource>({
shouldUnregister: false,
mode: "onChange",
});
const {

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { Select, SelectOption, SelectVariant } from "@patternfly/react-core";
import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceRepresentation";

View file

@ -10,7 +10,7 @@ import {
ValidatedOptions,
} from "@patternfly/react-core";
import { useState } from "react";
import { useForm } from "react-hook-form-v7";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import {
FormGroup,
Select,

View file

@ -1,6 +1,6 @@
import { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { Select, SelectOption, SelectVariant } from "@patternfly/react-core";
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";

View file

@ -11,7 +11,7 @@ import {
SelectVariant,
} from "@patternfly/react-core";
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form-v7";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, FormProvider, useForm } from "react-hook-form-v7";
import { Controller, FormProvider, useForm } from "react-hook-form";
import {
AlertVariant,
Button,

View file

@ -1,5 +1,5 @@
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import {
SelectOption,
FormGroup,

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useFormContext, Controller } from "react-hook-form-v7";
import { useFormContext, Controller } from "react-hook-form";
import { FormGroup, Button, Checkbox } from "@patternfly/react-core";
import { MinusCircleIcon } from "@patternfly/react-icons";
import {

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useFormContext, Controller } from "react-hook-form-v7";
import { useFormContext, Controller } from "react-hook-form";
import { MinusCircleIcon } from "@patternfly/react-icons";
import { FormGroup, Button, Checkbox } from "@patternfly/react-core";
import {

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { CodeEditor, Language } from "@patternfly/react-code-editor";

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { FormGroup, Radio } from "@patternfly/react-core";
import { HelpItem } from "../../../components/help-enabler/HelpItem";

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { HelpItem } from "../../../components/help-enabler/HelpItem";

View file

@ -8,7 +8,7 @@ import {
PageSection,
} from "@patternfly/react-core";
import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
@ -64,7 +64,7 @@ export default function PolicyDetails() {
const { t } = useTranslation("clients");
const { id, realm, policyId, policyType } = useParams<PolicyDetailsParams>();
const navigate = useNavigate();
const form = useForm({ shouldUnregister: false });
const form = useForm();
const { reset, handleSubmit } = form;
const { adminClient } = useAdminClient();

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { HelpItem } from "../../../components/help-enabler/HelpItem";

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useFormContext, Controller } from "react-hook-form-v7";
import { useFormContext, Controller } from "react-hook-form";
import { FormGroup, Button, Checkbox } from "@patternfly/react-core";
import { MinusCircleIcon } from "@patternfly/react-icons";
import {

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import {
DatePicker,
Flex,

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import {
Alert,
Button,

View file

@ -19,7 +19,7 @@ import {
SplitItem,
} from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form-v7";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useAlerts } from "../../components/alert/Alerts";

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import {
FormGroup,
Select,

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";

View file

@ -7,7 +7,7 @@ import {
PageSection,
} from "@patternfly/react-core";
import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
@ -39,7 +39,7 @@ export default function ImportForm() {
const navigate = useNavigate();
const { adminClient } = useAdminClient();
const { realm } = useRealm();
const form = useForm<FormFields>({ shouldUnregister: false });
const form = useForm<FormFields>();
const { register, handleSubmit, setValue } = form;
const [imported, setImported] = useState<ClientRepresentation>({});

View file

@ -1,6 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useForm } from "react-hook-form-v7";
import { Controller, useForm } from "react-hook-form";
import {
ActionGroup,
AlertVariant,

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { Button, Modal, Form } from "@patternfly/react-core";
import { saveAs } from "file-saver";

View file

@ -5,7 +5,7 @@ import {
FormProvider,
useForm,
useFormContext,
} from "react-hook-form-v7";
} from "react-hook-form";
import {
Button,
ButtonVariant,

View file

@ -1,11 +1,6 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import {
Controller,
FormProvider,
useForm,
useWatch,
} from "react-hook-form-v7";
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
import {
Button,
ButtonVariant,

View file

@ -18,7 +18,7 @@ import { useTranslation } from "react-i18next";
import type CertificateRepresentation from "@keycloak/keycloak-admin-client/lib/defs/certificateRepresentation";
import type KeyStoreConfig from "@keycloak/keycloak-admin-client/lib/defs/keystoreConfig";
import { Controller, useFormContext, useWatch } from "react-hook-form-v7";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { useAlerts } from "../../components/alert/Alerts";
import { FormAccess } from "../../components/form-access/FormAccess";
import { HelpItem } from "../../components/help-enabler/HelpItem";

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { FormProvider, useFormContext } from "react-hook-form-v7";
import { FormProvider, useFormContext } from "react-hook-form";
import { AlertVariant } from "@patternfly/react-core";
import type { KeyTypes } from "./SamlKeys";

View file

@ -13,7 +13,7 @@ import {
} from "@patternfly/react-core";
import { saveAs } from "file-saver";
import { Fragment, useState } from "react";
import { Controller, useFormContext } from "react-hook-form-v7";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type CertificateRepresentation from "@keycloak/keycloak-admin-client/lib/defs/certificateRepresentation";

View file

@ -1,7 +1,7 @@
import { useState } from "react";
import { saveAs } from "file-saver";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import {
AlertVariant,
Button,

View file

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form-v7";
import { useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import type KeyStoreConfig from "@keycloak/keycloak-admin-client/lib/defs/keystoreConfig";

View file

@ -23,7 +23,7 @@ import {
} from "@patternfly/react-core";
import { QuestionCircleIcon } from "@patternfly/react-icons";
import { useEffect, useRef, useState } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useHelp } from "../../components/help-enabler/HelpHeader";

View file

@ -1,18 +1,18 @@
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";
import { useTranslation } from "react-i18next";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
import type { ClientQuery } from "@keycloak/keycloak-admin-client/lib/resources/clients";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { HelpItem } from "../help-enabler/HelpItem";
import type { ComponentProps } from "../dynamic/components";
import { HelpItem } from "../help-enabler/HelpItem";
type ClientSelectProps = ComponentProps & {
namespace: string;
@ -29,7 +29,10 @@ export const ClientSelect = ({
required = false,
}: ClientSelectProps) => {
const { t } = useTranslation(namespace);
const { control, errors } = useFormContext();
const {
control,
formState: { errors },
} = useFormContext();
const [open, setOpen] = useState(false);
const [clients, setClients] = useState<ClientRepresentation[]>([]);
@ -80,20 +83,20 @@ export const ClientSelect = ({
defaultValue={defaultValue || ""}
control={control}
rules={required ? { required: true } : {}}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId={name}
variant={SelectVariant.typeahead}
onToggle={(open) => setOpen(open)}
isOpen={open}
isDisabled={isDisabled}
selections={value}
selections={field.value}
onFilter={(_, value) => {
setSearch(value);
return convert(clients);
}}
onSelect={(_, value) => {
onChange(value.toString());
field.onChange(value.toString());
setOpen(false);
}}
aria-label={t(label!)}

View file

@ -1,110 +0,0 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form-v7";
import {
FormGroup,
Select,
SelectOption,
SelectVariant,
} from "@patternfly/react-core";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
import type { ClientQuery } from "@keycloak/keycloak-admin-client/lib/resources/clients";
import { useAdminClient, useFetch } from "../../../context/auth/AdminClient";
import { HelpItem } from "../../help-enabler/HelpItem";
import type { ComponentProps } from "../../dynamic/components";
type ClientSelectProps = ComponentProps & {
namespace: string;
required?: boolean;
};
export const ClientSelect = ({
name,
label,
helpText,
defaultValue,
namespace,
isDisabled = false,
required = false,
}: ClientSelectProps) => {
const { t } = useTranslation(namespace);
const {
control,
formState: { errors },
} = useFormContext();
const [open, setOpen] = useState(false);
const [clients, setClients] = useState<ClientRepresentation[]>([]);
const [search, setSearch] = useState("");
const { adminClient } = useAdminClient();
useFetch(
() => {
const params: ClientQuery = {
max: 20,
};
if (search) {
params.clientId = search;
params.search = true;
}
return adminClient.clients.find(params);
},
(clients) => setClients(clients),
[search]
);
const convert = (clients: ClientRepresentation[]) => [
<SelectOption key="empty" value="">
{t("common:none")}
</SelectOption>,
...clients.map((option) => (
<SelectOption key={option.id} value={option.clientId} />
)),
];
return (
<FormGroup
label={t(label!)}
isRequired={required}
labelIcon={
<HelpItem
helpText={t(helpText!)}
fieldLabelId={`${namespace}:${label}`}
/>
}
fieldId={name!}
validated={errors[name!] ? "error" : "default"}
helperTextInvalid={t("common:required")}
>
<Controller
name={name!}
defaultValue={defaultValue || ""}
control={control}
rules={required ? { required: true } : {}}
render={({ field }) => (
<Select
toggleId={name}
variant={SelectVariant.typeahead}
onToggle={(open) => setOpen(open)}
isOpen={open}
isDisabled={isDisabled}
selections={field.value}
onFilter={(_, value) => {
setSearch(value);
return convert(clients);
}}
onSelect={(_, value) => {
field.onChange(value.toString());
setOpen(false);
}}
aria-label={t(label!)}
>
{convert(clients)}
</Select>
)}
/>
</FormGroup>
);
};

View file

@ -1,9 +1,9 @@
import { FormGroup, Switch } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormGroup, Switch } from "@patternfly/react-core";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import type { ComponentProps } from "./components";
import { convertToName } from "./DynamicComponents";
export const BooleanComponent = ({
@ -29,16 +29,18 @@ export const BooleanComponent = ({
data-testid={name}
defaultValue={false}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Switch
id={name!}
isDisabled={isDisabled}
label={t("common:on")}
labelOff={t("common:off")}
isChecked={
value === "true" || value === true || value[0] === "true"
field.value === "true" ||
field.value === true ||
field.value[0] === "true"
}
onChange={(value) => onChange("" + value)}
onChange={(value) => field.onChange("" + value)}
data-testid={name}
aria-label={t(label!)}
/>

View file

@ -26,5 +26,5 @@ export const DynamicComponents = ({
</>
);
export const convertToName = (name: string) =>
export const convertToName = (name: string): string =>
convertAttributeNameToForm(`config.${name}`);

View file

@ -1,12 +1,12 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../help-enabler/HelpItem";
import { FileUpload } from "../json-file-upload/patternfly/FileUpload";
import type { ComponentProps } from "./components";
import { convertToName } from "./DynamicComponents";
import { FileUpload } from "../json-file-upload/patternfly/FileUpload";
export const FileComponent = ({
name,
@ -32,10 +32,10 @@ export const FileComponent = ({
name={convertToName(name!)}
control={control}
defaultValue={defaultValue || ""}
render={({ onChange, value }) => (
render={({ field }) => (
<FileUpload
id={name!}
value={value}
value={field.value}
type="text"
filename={filename}
isDisabled={isDisabled}
@ -43,13 +43,13 @@ export const FileComponent = ({
onReadStarted={() => setIsLoading(true)}
onReadFinished={() => setIsLoading(false)}
onClearClick={() => {
onChange("");
field.onChange("");
setFilename("");
}}
isLoading={isLoading}
allowEditingUploadedText={false}
onChange={(value, filename) => {
onChange(value);
field.onChange(value);
setFilename(filename);
}}
/>

View file

@ -25,9 +25,8 @@ export const GroupComponent = ({ name, label, helpText }: ComponentProps) => {
<Controller
name={convertToName(name!)}
defaultValue=""
typeAheadAriaLabel={t("selectGroup")}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<>
{open && (
<GroupPickerDialog
@ -37,7 +36,7 @@ export const GroupComponent = ({ name, label, helpText }: ComponentProps) => {
ok: "common:select",
}}
onConfirm={(groups) => {
onChange(groups?.[0].path);
field.onChange(groups?.[0].path);
setGroups(groups);
setOpen(false);
}}
@ -58,8 +57,10 @@ export const GroupComponent = ({ name, label, helpText }: ComponentProps) => {
>
<InputGroup>
<ChipGroup>
{value && (
<Chip onClick={() => onChange(undefined)}>{value}</Chip>
{field.value && (
<Chip onClick={() => field.onChange(undefined)}>
{field.value}
</Chip>
)}
</ChipGroup>
<Button

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";
import { useTranslation } from "react-i18next";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import type { ComponentProps } from "./components";
import { convertToName } from "./DynamicComponents";
export const ListComponent = ({
@ -37,23 +37,23 @@ export const ListComponent = ({
data-testid={name}
defaultValue={defaultValue || ""}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId={name}
isDisabled={isDisabled}
onToggle={(toggle) => setOpen(toggle)}
onSelect={(_, value) => {
onChange(value as string);
field.onChange(value as string);
setOpen(false);
}}
selections={value}
selections={field.value}
variant={SelectVariant.single}
aria-label={t(label!)}
isOpen={open}
>
{options?.map((option) => (
<SelectOption
selected={option === value}
selected={option === field.value}
key={option}
value={option}
/>

View file

@ -1,6 +1,3 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import {
ActionList,
ActionListItem,
@ -11,11 +8,14 @@ import {
TextInput,
} from "@patternfly/react-core";
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
import { useEffect, useState } from "react";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import { convertToName } from "./DynamicComponents";
import { KeyValueType } from "../key-value-form/key-value-convert";
import type { ComponentProps } from "./components";
import { convertToName } from "./DynamicComponents";
type IdKeyValueType = KeyValueType & {
id: number;

View file

@ -1,12 +1,12 @@
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";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../help-enabler/HelpItem";
import type { ComponentProps } from "./components";
@ -36,7 +36,7 @@ export const MultiValuedListComponent = ({
name={convertToName(name!)}
control={control}
defaultValue={defaultValue ? [defaultValue] : []}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId={name}
data-testid={name}
@ -49,18 +49,20 @@ export const MultiValuedListComponent = ({
variant={SelectVariant.typeaheadMulti}
typeAheadAriaLabel="Select"
onToggle={(isOpen) => setOpen(isOpen)}
selections={value}
selections={field.value}
onSelect={(_, v) => {
const option = v.toString();
if (value.includes(option)) {
onChange(value.filter((item: string) => item !== option));
if (field.value.includes(option)) {
field.onChange(
field.value.filter((item: string) => item !== option)
);
} else {
onChange([...value, option]);
field.onChange([...field.value, option]);
}
}}
onClear={(event) => {
event.stopPropagation();
onChange([]);
field.onChange([]);
}}
isOpen={open}
aria-label={t(label!)}

View file

@ -1,10 +1,10 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import { PasswordInput } from "../password-input/PasswordInput";
import type { ComponentProps } from "./components";
import { convertToName } from "./DynamicComponents";
export const PasswordComponent = ({
@ -29,9 +29,8 @@ export const PasswordComponent = ({
id={name!}
data-testid={name}
isDisabled={isDisabled}
ref={register()}
name={convertToName(name!)}
defaultValue={defaultValue?.toString()}
{...register(convertToName(name!))}
/>
</FormGroup>
);

View file

@ -1,5 +1,3 @@
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import {
Button,
Chip,
@ -7,12 +5,14 @@ import {
Split,
SplitItem,
} from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem";
import useToggle from "../../utils/useToggle";
import { HelpItem } from "../help-enabler/HelpItem";
import { AddRoleMappingModal } from "../role-mapping/AddRoleMappingModal";
import { ServiceRole, Row } from "../role-mapping/RoleMapping";
import { Row, ServiceRole } from "../role-mapping/RoleMapping";
import type { ComponentProps } from "./components";
import { convertToName } from "./DynamicComponents";
const parseValue = (value: any) =>
@ -33,7 +33,10 @@ export const RoleComponent = ({
const { t } = useTranslation("dynamic");
const [openModal, toggleModal] = useToggle();
const { control, errors } = useFormContext();
const {
control,
formState: { errors },
} = useFormContext();
const fieldName = convertToName(name!);
@ -50,27 +53,26 @@ export const RoleComponent = ({
<Controller
name={fieldName}
defaultValue={defaultValue || ""}
typeAheadAriaLabel="Select an action"
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Split>
{openModal && (
<AddRoleMappingModal
id="id"
type="roles"
name={name}
onAssign={(rows) => onChange(parseRow(rows[0]))}
onAssign={(rows) => field.onChange(parseRow(rows[0]))}
onClose={toggleModal}
isRadio
/>
)}
{value !== "" && (
{field.value !== "" && (
<SplitItem>
<Chip textMaxWidth="500px" onClick={() => onChange("")}>
<Chip textMaxWidth="500px" onClick={() => field.onChange("")}>
<ServiceRole
role={{ name: parseValue(value)[1] }}
client={{ clientId: parseValue(value)[0] }}
role={{ name: parseValue(field.value)[1] }}
client={{ clientId: parseValue(field.value)[0] }}
/>
</Chip>
</SplitItem>

View file

@ -1,7 +1,7 @@
import { CodeEditor, Language } from "@patternfly/react-code-editor";
import { FormGroup } from "@patternfly/react-core";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormGroup } from "@patternfly/react-core";
import { CodeEditor, Language } from "@patternfly/react-code-editor";
import { HelpItem } from "../help-enabler/HelpItem";
import type { ComponentProps } from "./components";
@ -32,14 +32,14 @@ export const ScriptComponent = ({
name={convertToName(name!)}
defaultValue={defaultValue}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<CodeEditor
id={name!}
data-testid={name}
isReadOnly={isDisabled}
type="text"
onChange={onChange}
code={value}
onChange={field.onChange}
code={field.value}
height="600px"
language={Language.javascript}
/>

View file

@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../help-enabler/HelpItem";
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
@ -29,10 +29,8 @@ export const StringComponent = ({
id={name!}
data-testid={name}
isDisabled={isDisabled}
ref={register()}
type="text"
name={convertToName(name!)}
defaultValue={defaultValue?.toString()}
{...register(convertToName(name!))}
/>
</FormGroup>
);

View file

@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "../help-enabler/HelpItem";
import { KeycloakTextArea } from "../keycloak-text-area/KeycloakTextArea";
@ -29,9 +29,8 @@ export const TextComponent = ({
id={name!}
data-testid={name}
isDisabled={isDisabled}
ref={register()}
name={convertToName(name!)}
defaultValue={defaultValue?.toString()}
{...register(convertToName(name!))}
/>
</FormGroup>
);

View file

@ -1,64 +0,0 @@
/**
* @vitest-environment jsdom
*/
import type WhoAmIRepresentation from "@keycloak/keycloak-admin-client/lib/defs/whoAmIRepresentation";
import { FormGroup, Switch } from "@patternfly/react-core";
import { render, screen } from "@testing-library/react";
import { Controller, useForm } from "react-hook-form";
import { describe, expect, it } from "vitest";
import { AccessContextProvider } from "../../context/access/Access";
import { RealmContext } from "../../context/realm-context/RealmContext";
import { WhoAmI, WhoAmIContext } from "../../context/whoami/WhoAmI";
import whoami from "../../context/whoami/__tests__/mock-whoami.json";
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
import { FormAccess } from "./FormAccess";
describe("FormAccess", () => {
const Form = ({ realm }: { realm: string }) => {
const { register, control } = useForm();
return (
<WhoAmIContext.Provider
value={{
refresh: () => {},
whoAmI: new WhoAmI(whoami as WhoAmIRepresentation),
}}
>
<RealmContext.Provider value={{ realm }}>
<AccessContextProvider>
<FormAccess role="manage-clients">
<FormGroup label="test" fieldId="field">
<KeycloakTextInput
type="text"
id="field"
data-testid="field"
name="fieldName"
ref={register()}
/>
</FormGroup>
<Controller
name="consentRequired"
defaultValue={false}
control={control}
render={({ onChange, value }) => (
<Switch
data-testid="kc-consent"
label={"on"}
labelOff="off"
isChecked={value}
onChange={onChange}
/>
)}
/>
</FormAccess>
</AccessContextProvider>
</RealmContext.Provider>
</WhoAmIContext.Provider>
);
};
it("renders disabled form for test realm", () => {
render(<Form realm="test" />);
expect(screen.getByTestId("field")).toBeDisabled();
expect(screen.getByTestId("kc-consent")).toBeDisabled();
});
});

View file

@ -1,18 +1,18 @@
import { useTranslation } from "react-i18next";
import { FormProvider, UseFormMethods } from "react-hook-form";
import { ActionGroup, Button } from "@patternfly/react-core";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import { ActionGroup, Button } from "@patternfly/react-core";
import { FormProvider, UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../form-access/FormAccess";
import type { KeyValueType } from "./key-value-convert";
import { KeyValueInput } from "./KeyValueInput";
import { FormAccess } from "../form-access/FormAccess";
export type AttributeForm = Omit<RoleRepresentation, "attributes"> & {
attributes?: KeyValueType[];
};
export type AttributesFormProps = {
form: UseFormMethods<AttributeForm>;
form: UseFormReturn<AttributeForm>;
save?: (model: AttributeForm) => void;
reset?: () => void;
fineGrainedAccess?: boolean;

View file

@ -1,6 +1,3 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useFieldArray, useFormContext, useWatch } from "react-hook-form";
import {
ActionList,
ActionListItem,
@ -9,9 +6,12 @@ import {
FlexItem,
} from "@patternfly/react-core";
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
import { useEffect } from "react";
import { useFieldArray, useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { KeyValueType } from "./key-value-convert";
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
import { KeyValueType } from "./key-value-convert";
type KeyValueInputProps = {
name: string;
@ -20,25 +20,28 @@ type KeyValueInputProps = {
export const KeyValueInput = ({ name }: KeyValueInputProps) => {
const { t } = useTranslation("common");
const { control, register } = useFormContext();
const { fields, append, remove } = useFieldArray<KeyValueType>({
control: control,
name,
});
const watchFields = useWatch<KeyValueType[]>({
const { fields, append, remove } = useFieldArray({
control,
name,
defaultValue: [],
});
const isValid = watchFields.every(
({ key, value }) =>
key && key.trim().length !== 0 && value && value.trim().length !== 0
const watchFields = useWatch({
control,
name,
defaultValue: [{ key: "", value: "" }],
});
const isValid =
Array.isArray(watchFields) &&
watchFields.every(
({ key, value }: KeyValueType) =>
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
key?.trim().length !== 0 && value?.trim().length !== 0
);
useEffect(() => {
if (!fields.length) {
append({ key: "", value: "" }, false);
append({ key: "", value: "" }, { shouldFocus: false });
}
}, [fields]);
@ -60,12 +63,11 @@ export const KeyValueInput = ({ name }: KeyValueInputProps) => {
<Flex key={attribute.id} data-testid="row">
<FlexItem grow={{ default: "grow" }}>
<KeycloakTextInput
name={`${name}[${index}].key`}
ref={register()}
placeholder={t("keyPlaceholder")}
aria-label={t("key")}
defaultValue={attribute.key}
defaultValue=""
data-testid={`${name}[${index}].key`}
{...register(`${name}[${index}].key`)}
/>
</FlexItem>
<FlexItem
@ -73,12 +75,11 @@ export const KeyValueInput = ({ name }: KeyValueInputProps) => {
spacer={{ default: "spacerNone" }}
>
<KeycloakTextInput
name={`${name}[${index}].value`}
ref={register()}
placeholder={t("valuePlaceholder")}
aria-label={t("value")}
defaultValue={attribute.value}
defaultValue=""
data-testid={`${name}[${index}].value`}
{...register(`${name}[${index}].value`)}
/>
</FlexItem>
<FlexItem>

View file

@ -1,115 +0,0 @@
import {
ActionList,
ActionListItem,
Button,
Flex,
FlexItem,
} from "@patternfly/react-core";
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
import { useEffect } from "react";
import { useFieldArray, useFormContext, useWatch } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { KeycloakTextInput } from "../../keycloak-text-input/KeycloakTextInput";
import { KeyValueType } from "../key-value-convert";
type KeyValueInputProps = {
name: string;
};
export const KeyValueInput = ({ name }: KeyValueInputProps) => {
const { t } = useTranslation("common");
const { control, register } = useFormContext();
const { fields, append, remove } = useFieldArray({
control,
name,
});
const watchFields = useWatch({
control,
name,
defaultValue: [{ key: "", value: "" }],
});
const isValid =
Array.isArray(watchFields) &&
watchFields.every(
({ key, value }: KeyValueType) =>
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
key?.trim().length !== 0 && value?.trim().length !== 0
);
useEffect(() => {
if (!fields.length) {
append({ key: "", value: "" }, { shouldFocus: false });
}
}, [fields]);
return (
<>
<Flex direction={{ default: "column" }}>
<Flex>
<FlexItem
grow={{ default: "grow" }}
spacer={{ default: "spacerNone" }}
>
<strong>{t("key")}</strong>
</FlexItem>
<FlexItem grow={{ default: "grow" }}>
<strong>{t("value")}</strong>
</FlexItem>
</Flex>
{fields.map((attribute, index) => (
<Flex key={attribute.id} data-testid="row">
<FlexItem grow={{ default: "grow" }}>
<KeycloakTextInput
placeholder={t("keyPlaceholder")}
aria-label={t("key")}
defaultValue=""
data-testid={`${name}[${index}].key`}
{...register(`${name}[${index}].key`)}
/>
</FlexItem>
<FlexItem
grow={{ default: "grow" }}
spacer={{ default: "spacerNone" }}
>
<KeycloakTextInput
placeholder={t("valuePlaceholder")}
aria-label={t("value")}
defaultValue=""
data-testid={`${name}[${index}].value`}
{...register(`${name}[${index}].value`)}
/>
</FlexItem>
<FlexItem>
<Button
variant="link"
title={t("removeAttribute")}
isDisabled={watchFields.length === 1}
onClick={() => remove(index)}
data-testid={`${name}[${index}].remove`}
>
<MinusCircleIcon />
</Button>
</FlexItem>
</Flex>
))}
</Flex>
<ActionList>
<ActionListItem>
<Button
data-testid={`${name}-add-row`}
className="pf-u-px-0 pf-u-mt-sm"
variant="link"
icon={<PlusCircleIcon />}
isDisabled={!isValid}
onClick={() => append({ key: "", value: "" })}
>
{t("addAttribute")}
</Button>
</ActionListItem>
</ActionList>
</>
);
};

View file

@ -1,4 +1,4 @@
import { Path, PathValue } from "react-hook-form-v7";
import { Path, PathValue } from "react-hook-form";
export type KeyValueType = { key: string; value: string };

View file

@ -1,118 +0,0 @@
import {
Button,
ButtonVariant,
InputGroup,
TextInput,
TextInputProps,
} from "@patternfly/react-core";
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
import { Fragment, useEffect, useMemo } from "react";
import { useFormContext, useWatch } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
function stringToMultiline(value?: string): string[] {
return typeof value === "string" ? value.split("##") : [];
}
function toStringValue(formValue: string[]): string {
return formValue.join("##");
}
export type MultiLineInputProps = Omit<TextInputProps, "form"> & {
name: string;
addButtonLabel?: string;
isDisabled?: boolean;
defaultValue?: string[];
stringify?: boolean;
};
export const MultiLineInput = ({
name,
addButtonLabel,
isDisabled = false,
defaultValue,
stringify = false,
...rest
}: MultiLineInputProps) => {
const { t } = useTranslation();
const { register, setValue, control } = useFormContext();
const value = useWatch({
name,
control,
defaultValue: defaultValue || "",
});
const fields = useMemo<string[]>(() => {
let values = stringify ? stringToMultiline(value as string) : value;
values =
Array.isArray(values) && values.length !== 0
? values
: defaultValue || [""];
return values;
}, [value]);
const remove = (index: number) => {
update([...fields.slice(0, index), ...fields.slice(index + 1)]);
};
const append = () => {
update([...fields, ""]);
};
const updateValue = (index: number, value: string) => {
update([...fields.slice(0, index), value, ...fields.slice(index + 1)]);
};
const update = (values: string[]) => {
const fieldValue = values.flatMap((field) => field);
setValue(name, stringify ? toStringValue(fieldValue) : fieldValue, {
shouldDirty: true,
});
};
useEffect(() => {
register(name);
}, [register]);
return (
<>
{fields.map((value, index) => (
<Fragment key={index}>
<InputGroup>
<TextInput
data-testid={name + index}
onChange={(value) => updateValue(index, value)}
name={`${name}[${index}].value`}
value={value}
isDisabled={isDisabled}
{...rest}
/>
<Button
variant={ButtonVariant.link}
onClick={() => remove(index)}
tabIndex={-1}
aria-label={t("common:remove")}
isDisabled={fields.length === 1}
>
<MinusCircleIcon />
</Button>
</InputGroup>
{index === fields.length - 1 && (
<Button
variant={ButtonVariant.link}
onClick={append}
tabIndex={-1}
aria-label={t("common:add")}
data-testid="addValue"
isDisabled={!value}
>
<PlusCircleIcon /> {t(addButtonLabel || "common:add")}
</Button>
)}
</Fragment>
))}
</>
);
};

Some files were not shown because too many files have changed in this diff Show more