diff --git a/apps/admin-ui/src/authentication/policies/PasswordPolicy.tsx b/apps/admin-ui/src/authentication/policies/PasswordPolicy.tsx index 2192379330..6388310382 100644 --- a/apps/admin-ui/src/authentication/policies/PasswordPolicy.tsx +++ b/apps/admin-ui/src/authentication/policies/PasswordPolicy.tsx @@ -1,6 +1,3 @@ -import { useEffect, useMemo, useState } from "react"; -import { FormProvider, useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; import { ActionGroup, AlertVariant, @@ -20,16 +17,19 @@ import { ToolbarItem, } 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 { useTranslation } from "react-i18next"; -import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type PasswordPolicyTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/passwordPolicyTypeRepresentation"; -import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; +import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; +import { useAlerts } from "../../components/alert/Alerts"; import { FormAccess } from "../../components/form-access/FormAccess"; import { useAdminClient } from "../../context/auth/AdminClient"; import { useRealm } from "../../context/realm-context/RealmContext"; -import { useAlerts } from "../../components/alert/Alerts"; -import { parsePolicy, SubmittedValues, serializePolicy } from "./util"; +import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; import { PolicyRow } from "./PolicyRow"; +import { parsePolicy, serializePolicy, SubmittedValues } from "./util"; type PolicySelectProps = { onSelect: (row: PasswordPolicyTypeRepresentation) => void; @@ -87,16 +87,27 @@ export const PasswordPolicy = ({ const { realm: realmName } = useRealm(); const [rows, setRows] = useState([]); - const onSelect = (row: PasswordPolicyTypeRepresentation) => + const onSelect = (row: PasswordPolicyTypeRepresentation) => { setRows([...rows, row]); + setValue(row.id!, row.defaultValue!, { shouldDirty: true }); + }; - const form = useForm({ shouldUnregister: false }); - const { handleSubmit, setValue, getValues } = form; + const form = useForm({ + defaultValues: {}, + shouldUnregister: false, + }); + const { + handleSubmit, + setValue, + reset, + formState: { isDirty }, + } = form; const setupForm = (realm: RealmRepresentation) => { + reset(); const values = parsePolicy(realm.passwordPolicy || "", passwordPolicies!); values.forEach((v) => { - setValue(v.id!, v.value); + setValue(v.id!, v.value!); }); setRows(values); }; @@ -142,7 +153,10 @@ export const PasswordPolicy = ({ setRows(rows.filter((r) => r.id !== id))} + onRemove={(id) => { + setRows(rows.filter((r) => r.id !== id)); + setValue(r.id!, "", { shouldDirty: true }); + }} /> ))} @@ -150,10 +164,7 @@ export const PasswordPolicy = ({ data-testid="save" variant="primary" type="submit" - isDisabled={ - serializePolicy(rows, getValues()) === - realm.passwordPolicy - } + isDisabled={!isDirty} > {t("common:save")} diff --git a/apps/admin-ui/src/authentication/policies/PolicyRow.tsx b/apps/admin-ui/src/authentication/policies/PolicyRow.tsx index 5dfdb68fe0..c22ea2e245 100644 --- a/apps/admin-ui/src/authentication/policies/PolicyRow.tsx +++ b/apps/admin-ui/src/authentication/policies/PolicyRow.tsx @@ -1,5 +1,4 @@ -import { useTranslation } from "react-i18next"; -import { Controller, useFormContext } from "react-hook-form"; +import type PasswordPolicyTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/passwordPolicyTypeRepresentation"; import { Button, FormGroup, @@ -10,10 +9,11 @@ import { ValidatedOptions, } from "@patternfly/react-core"; import { MinusCircleIcon } from "@patternfly/react-icons"; -import type PasswordPolicyTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/passwordPolicyTypeRepresentation"; +import { Controller, useFormContext } from "react-hook-form-v7"; +import { useTranslation } from "react-i18next"; -import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { HelpItem } from "../../components/help-enabler/HelpItem"; +import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import "./policy-row.css"; @@ -32,6 +32,7 @@ export const PolicyRow = ({ register, formState: { errors }, } = useFormContext(); + return ( { + render={({ field }) => { const MIN_VALUE = 0; const setValue = (newValue: number) => - onChange(Math.max(newValue, MIN_VALUE)); + field.onChange(Math.max(newValue, MIN_VALUE)); + const value = Number(field.value); return (