Use react-form-hook v7 for flow form (#3785)

This commit is contained in:
Jon Koops 2022-11-17 13:39:29 +01:00 committed by GitHub
parent a9c7b11284
commit 3da00919b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 86 additions and 97 deletions

View file

@ -1,7 +1,4 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom-v5-compat";
import AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
import {
AlertVariant,
Button,
@ -10,12 +7,16 @@ import {
Modal,
ModalVariant,
} from "@patternfly/react-core";
import { useEffect } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom-v5-compat";
import { useAdminClient } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts";
import { useAdminClient } from "../context/auth/AdminClient";
import { useRealm } from "../context/realm-context/RealmContext";
import { NameDescription } from "./form/NameDescription";
import { toFlow } from "./routes/Flow";
import { useRealm } from "../context/realm-context/RealmContext";
type DuplicateFlowModalProps = {
name: string;
@ -31,27 +32,25 @@ export const DuplicateFlowModal = ({
onComplete,
}: DuplicateFlowModalProps) => {
const { t } = useTranslation("authentication");
const form = useForm({
shouldUnregister: false,
});
const { setValue, trigger, getValues } = form;
const form = useForm<AuthenticationFlowRepresentation>({ mode: "onChange" });
const { setValue, trigger, getValues, handleSubmit } = form;
const { adminClient } = useAdminClient();
const { addAlert, addError } = useAlerts();
const navigate = useNavigate();
const { realm } = useRealm();
useEffect(() => {
setValue("description", description);
setValue("alias", t("copyOf", { name }));
}, [name, description, setValue]);
setValue("description", description);
}, [name, description]);
const save = async () => {
const onSubmit = async () => {
if (!(await trigger())) return;
const form = getValues();
try {
await adminClient.authenticationManagement.copyFlow({
flow: name,
newName: form.alias,
newName: form.alias!,
});
const newFlow = (
await adminClient.authenticationManagement.getFlows()
@ -82,33 +81,34 @@ export const DuplicateFlowModal = ({
return (
<Modal
title={t("duplicateFlow")}
isOpen={true}
onClose={toggleDialog}
variant={ModalVariant.small}
actions={[
<Button
id="modal-confirm"
key="confirm"
onClick={save}
data-testid="confirm"
type="submit"
form="duplicate-flow-form"
>
{t("duplicate")}
</Button>,
<Button
data-testid="cancel"
id="modal-cancel"
key="cancel"
data-testid="cancel"
variant={ButtonVariant.link}
onClick={() => {
toggleDialog();
}}
onClick={toggleDialog}
>
{t("common:cancel")}
</Button>,
]}
isOpen
>
<FormProvider {...form}>
<Form isHorizontal>
<Form
id="duplicate-flow-form"
onSubmit={handleSubmit(onSubmit)}
isHorizontal
>
<NameDescription />
</Form>
</FormProvider>

View file

@ -1,6 +1,4 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form";
import type AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
import {
AlertVariant,
Button,
@ -9,10 +7,12 @@ import {
Modal,
ModalVariant,
} from "@patternfly/react-core";
import { useEffect } from "react";
import { FormProvider, useForm } from "react-hook-form-v7";
import { useTranslation } from "react-i18next";
import type AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
import { useAdminClient } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts";
import { useAdminClient } from "../context/auth/AdminClient";
import { NameDescription } from "./form/NameDescription";
type EditFlowModalProps = {
@ -20,29 +20,20 @@ type EditFlowModalProps = {
toggleDialog: () => void;
};
type EditForm = {
alias: string;
description: string;
};
export const EditFlowModal = ({ flow, toggleDialog }: EditFlowModalProps) => {
const { t } = useTranslation("authentication");
const form = useForm<EditForm>({
shouldUnregister: false,
});
const { reset, handleSubmit } = form;
const { adminClient } = useAdminClient();
const { addAlert, addError } = useAlerts();
const form = useForm<AuthenticationFlowRepresentation>({ mode: "onChange" });
const { reset, handleSubmit } = form;
useEffect(() => {
reset(flow);
}, [flow, reset]);
useEffect(() => reset(flow), [flow]);
const save = async (values: EditForm) => {
const onSubmit = async (formValues: AuthenticationFlowRepresentation) => {
try {
await adminClient.authenticationManagement.updateFlow(
{ flowId: flow.id! },
{ ...flow, ...values }
{ ...flow, ...formValues }
);
addAlert(t("updateFlowSuccess"), AlertVariant.success);
} catch (error) {
@ -54,33 +45,34 @@ export const EditFlowModal = ({ flow, toggleDialog }: EditFlowModalProps) => {
return (
<Modal
title={t("editFlow")}
isOpen={true}
onClose={toggleDialog}
variant={ModalVariant.small}
actions={[
<Button
id="modal-confirm"
key="confirm"
onClick={handleSubmit(save)}
data-testid="confirm"
type="submit"
form="edit-flow-form"
>
{t("edit")}
</Button>,
<Button
data-testid="cancel"
id="modal-cancel"
key="cancel"
data-testid="cancel"
variant={ButtonVariant.link}
onClick={() => {
toggleDialog();
}}
onClick={() => toggleDialog()}
>
{t("common:cancel")}
</Button>,
]}
isOpen
>
<FormProvider {...form}>
<Form isHorizontal>
<Form
id="edit-flow-form"
onSubmit={handleSubmit(onSubmit)}
isHorizontal
>
<NameDescription />
</Form>
</FormProvider>

View file

@ -1,38 +1,36 @@
import { Link } from "react-router-dom-v5-compat";
import { useNavigate } from "react-router-dom-v5-compat";
import { useTranslation } from "react-i18next";
import { FormProvider, useForm } from "react-hook-form";
import type AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
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 AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { FormAccess } from "../../components/form-access/FormAccess";
import { useRealm } from "../../context/realm-context/RealmContext";
import { useAdminClient } from "../../context/auth/AdminClient";
import { useAlerts } from "../../components/alert/Alerts";
import { NameDescription } from "./NameDescription";
import { FlowType } from "./FlowType";
import { toFlow } from "../routes/Flow";
import { FormAccess } from "../../components/form-access/FormAccess";
import { ViewHeader } from "../../components/view-header/ViewHeader";
import { useAdminClient } from "../../context/auth/AdminClient";
import { useRealm } from "../../context/realm-context/RealmContext";
import { toAuthentication } from "../routes/Authentication";
import { toFlow } from "../routes/Flow";
import { FlowType } from "./FlowType";
import { NameDescription } from "./NameDescription";
export default function CreateFlow() {
const { t } = useTranslation("authentication");
const navigate = useNavigate();
const { realm } = useRealm();
const form = useForm<AuthenticationFlowRepresentation>({
defaultValues: { builtIn: false, topLevel: true },
});
const { handleSubmit, register } = form;
const { adminClient } = useAdminClient();
const { addAlert } = useAlerts();
const form = useForm<AuthenticationFlowRepresentation>();
const { handleSubmit } = form;
const onSubmit = async (formValues: AuthenticationFlowRepresentation) => {
const flow = { ...formValues, builtIn: false, topLevel: true };
const save = async (flow: AuthenticationFlowRepresentation) => {
try {
const { id } = await adminClient.authenticationManagement.createFlow(
flow
@ -66,10 +64,8 @@ export default function CreateFlow() {
<FormAccess
isHorizontal
role="manage-authorization"
onSubmit={handleSubmit(save)}
onSubmit={handleSubmit(onSubmit)}
>
<input name="builtIn" type="hidden" ref={register} />
<input name="topLevel" type="hidden" ref={register} />
<NameDescription />
<FlowType />
<ActionGroup>

View file

@ -1,12 +1,13 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, useFormContext } from "react-hook-form";
import AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
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 { HelpItem } from "../../components/help-enabler/HelpItem";
@ -14,8 +15,7 @@ const TYPES = ["basic-flow", "client-flow"] as const;
export const FlowType = () => {
const { t } = useTranslation("authentication");
const { control } = useFormContext();
const { control } = useFormContext<AuthenticationFlowRepresentation>();
const [open, setOpen] = useState(false);
return (
@ -33,21 +33,25 @@ export const FlowType = () => {
name="providerId"
defaultValue={TYPES[0]}
control={control}
render={({ onChange, value }) => (
render={({ field }) => (
<Select
toggleId="flowType"
onToggle={setOpen}
onSelect={(_, value) => {
onChange(value.toString());
field.onChange(value.toString());
setOpen(false);
}}
selections={t(`top-level-flow-type.${value}`)}
selections={t(`top-level-flow-type.${field.value}`)}
variant={SelectVariant.single}
aria-label={t("flowType")}
isOpen={open}
>
{TYPES.map((type) => (
<SelectOption selected={type === value} key={type} value={type}>
<SelectOption
key={type}
selected={type === field.value}
value={type}
>
{t(`top-level-flow-type.${type}`)}
</SelectOption>
))}

View file

@ -1,17 +1,18 @@
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";
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 { useTranslation } from "react-i18next";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
export const NameDescription = () => {
const { t } = useTranslation("authentication");
const {
register,
formState: { errors },
} = useFormContext();
} = useFormContext<AuthenticationFlowRepresentation>();
return (
<>
@ -22,20 +23,18 @@ export const NameDescription = () => {
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
isRequired
labelIcon={
<HelpItem helpText="authentication-help:name" fieldLabelId="name" />
}
isRequired
>
<KeycloakTextInput
type="text"
id="kc-name"
name="alias"
data-testid="name"
ref={register({ required: true })}
validated={
errors.alias ? ValidatedOptions.error : ValidatedOptions.default
}
{...register("alias", { required: true })}
/>
</FormGroup>
<FormGroup
@ -53,21 +52,19 @@ export const NameDescription = () => {
helperTextInvalid={errors.description?.message}
>
<KeycloakTextArea
ref={register({
maxLength: {
value: 255,
message: t("common:maxLength", { length: 255 }),
},
})}
type="text"
id="kc-description"
name="description"
data-testid="description"
validated={
errors.description
? ValidatedOptions.error
: ValidatedOptions.default
}
{...register("description", {
maxLength: {
value: 255,
message: t("common:maxLength", { length: 255 }),
},
})}
/>
</FormGroup>
</>