fix(catalog-import): migrate to the new react-hook-form version

Signed-off-by: Dominik Henneke <dominik.henneke@sda-se.com>
This commit is contained in:
Dominik Henneke
2021-08-03 21:34:21 +02:00
committed by Fredrik Adelöw
parent 508520ffbc
commit 3c684fdb9c
9 changed files with 95 additions and 61 deletions
+3 -5
View File
@@ -9,7 +9,7 @@ import { ApiRef } from '@backstage/core-plugin-api';
import { BackstagePlugin } from '@backstage/core-plugin-api';
import { CatalogApi } from '@backstage/catalog-client';
import { ConfigApi } from '@backstage/core-plugin-api';
import { Control } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import { DiscoveryApi } from '@backstage/core-plugin-api';
import { Entity } from '@backstage/catalog-model';
import { EntityName } from '@backstage/catalog-model';
@@ -23,9 +23,8 @@ import { ScmIntegrationRegistry } from '@backstage/integration';
import { SubmitHandler } from 'react-hook-form';
import { TextFieldProps } from '@material-ui/core/TextField/TextField';
import { UnpackNestedValue } from 'react-hook-form';
import { UseControllerOptions } from 'react-hook-form';
import { UseFormMethods } from 'react-hook-form';
import { UseFormOptions } from 'react-hook-form';
import { UseFormProps } from 'react-hook-form';
import { UseFormReturn } from 'react-hook-form';
// Warning: (ae-missing-release-tag) "AnalyzeResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -53,7 +52,6 @@ export const AutocompleteTextField: <TFieldValue extends string>({
name,
options,
required,
control,
errors,
rules,
loading,
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { ConfigApi } from '@backstage/core-plugin-api';
import {
Box,
Checkbox,
@@ -25,6 +26,7 @@ import {
} from '@material-ui/core';
import React from 'react';
import { BackButton } from '../Buttons';
import { asInputRef } from '../helpers';
import { StepFinishImportLocation } from '../StepFinishImportLocation';
import { StepInitAnalyzeUrl } from '../StepInitAnalyzeUrl';
import {
@@ -34,7 +36,6 @@ import {
import { StepPrepareSelectLocations } from '../StepPrepareSelectLocations';
import { StepReviewLocation } from '../StepReviewLocation';
import { ImportFlows, ImportState } from '../useImportState';
import { ConfigApi } from '@backstage/core-plugin-api';
export type StepperProviderOpts = {
pullRequest?: {
@@ -186,7 +187,7 @@ export function defaultGenerateStepper(
defaultBody={body}
renderFormFields={({
values,
control,
setValue,
errors,
groupsLoading,
groups,
@@ -198,25 +199,31 @@ export function defaultGenerateStepper(
</Box>
<TextField
name="title"
{...asInputRef(
register('title', {
required: true,
}),
)}
label="Pull Request Title"
placeholder="Add Backstage catalog entity descriptor files"
margin="normal"
variant="outlined"
fullWidth
inputRef={register({ required: true })}
error={Boolean(errors.title)}
required
/>
<TextField
name="body"
{...asInputRef(
register('body', {
required: true,
}),
)}
label="Pull Request Body"
placeholder="A describing text with Markdown support"
margin="normal"
variant="outlined"
fullWidth
inputRef={register({ required: true })}
error={Boolean(errors.body)}
multiline
required
@@ -227,13 +234,14 @@ export function defaultGenerateStepper(
</Box>
<TextField
name="componentName"
{...asInputRef(
register('componentName', { required: true }),
)}
label="Name of the created component"
placeholder="my-component"
margin="normal"
variant="outlined"
fullWidth
inputRef={register({ required: true })}
error={Boolean(errors.componentName)}
required
/>
@@ -241,7 +249,6 @@ export function defaultGenerateStepper(
{!values.useCodeowners && (
<AutocompleteTextField
name="owner"
control={control}
errors={errors}
options={groups || []}
loading={groupsLoading}
@@ -260,11 +267,10 @@ export function defaultGenerateStepper(
<FormControlLabel
control={
<Checkbox
name="useCodeowners"
inputRef={register}
{...asInputRef(register('useCodeowners'))}
onChange={(_, value) => {
if (value) {
control.setValue('owner', '');
setValue('owner', '');
}
}}
/>
@@ -14,13 +14,14 @@
* limitations under the License.
*/
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
import { FormHelperText, Grid, TextField } from '@material-ui/core';
import React, { useCallback, useState } from 'react';
import { useForm } from 'react-hook-form';
import { AnalyzeResult, catalogImportApiRef } from '../../api';
import { NextButton } from '../Buttons';
import { asInputRef } from '../helpers';
import { ImportFlows, PrepareResult } from '../useImportState';
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
type FormData = {
url: string;
@@ -123,15 +124,17 @@ export const StepInitAnalyzeUrl = ({
return (
<form onSubmit={handleSubmit(handleResult)}>
<TextField
{...register('url', {
required: true,
validate: {
httpsValidator: (value: any) =>
(typeof value === 'string' &&
value.match(/^http[s]?:\/\//) !== null) ||
'Must start with http:// or https://.',
},
})}
{...asInputRef(
register('url', {
required: true,
validate: {
httpsValidator: (value: any) =>
(typeof value === 'string' &&
value.match(/^http[s]?:\/\//) !== null) ||
'Must start with http:// or https://.',
},
}),
)}
fullWidth
id="url"
label="Repository URL"
@@ -18,14 +18,13 @@ import { CircularProgress, TextField } from '@material-ui/core';
import { TextFieldProps } from '@material-ui/core/TextField/TextField';
import { Autocomplete } from '@material-ui/lab';
import React from 'react';
import { Control, Controller, FieldErrors } from 'react-hook-form';
import { Controller, FieldErrors } from 'react-hook-form';
type Props<TFieldValue extends string> = {
name: TFieldValue;
options: string[];
required?: boolean;
control?: Control<Record<string, any>>;
errors?: FieldErrors<Record<TFieldValue, string>>;
rules?: React.ComponentProps<typeof Controller>['rules'];
@@ -42,7 +41,6 @@ export const AutocompleteTextField = <TFieldValue extends string>({
name,
options,
required,
control,
errors,
rules,
loading = false,
@@ -54,16 +52,17 @@ export const AutocompleteTextField = <TFieldValue extends string>({
return (
<Controller
name={name}
control={control}
rules={rules}
render={({ field }) => (
render={({ field: { onChange } }) => (
<Autocomplete
loading={loading}
loadingText={loadingText}
options={options || []}
autoSelect
freeSolo
{...field}
onChange={(_event: React.ChangeEvent<{}>, value: string | null) =>
onChange(value)
}
renderInput={params => (
<TextField
{...params}
@@ -18,6 +18,7 @@ import { FormHelperText, TextField } from '@material-ui/core';
import { act, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { asInputRef } from '../helpers';
import { PreparePullRequestForm } from './PreparePullRequestForm';
describe('<PreparePullRequestForm />', () => {
@@ -29,7 +30,7 @@ describe('<PreparePullRequestForm />', () => {
defaultValues={{ main: 'default' }}
render={({ register }) => (
<>
<TextField name="main" inputRef={register()} />
<TextField {...asInputRef(register('main'))} />
<button type="submit">Submit</button>{' '}
</>
)}
@@ -54,10 +55,9 @@ describe('<PreparePullRequestForm />', () => {
render={({ register }) => (
<>
<TextField
{...asInputRef(register('main'))}
id="main"
name="main"
label="Main Field"
inputRef={register()}
/>
<button type="submit">Submit</button>
</>
@@ -85,9 +85,9 @@ describe('<PreparePullRequestForm />', () => {
render={({ errors, register }) => (
<>
<TextField
{...asInputRef(register('main', { required: true }))}
name="main"
required
inputRef={register({ required: true })}
/>
{errors.main && (
<FormHelperText error>
@@ -55,10 +55,6 @@ export const PreparePullRequestForm = <
onSubmit,
render,
}: Props<TFieldValues>) => {
<<<<<<< HEAD
const { handleSubmit, watch, control, register, errors } =
useForm<TFieldValues>({ mode: 'onTouched', defaultValues });
=======
const {
handleSubmit,
watch,
@@ -66,7 +62,6 @@ export const PreparePullRequestForm = <
register,
formState: { errors },
} = useForm<TFieldValues>({ mode: 'onTouched', defaultValues });
>>>>>>> chore: fixing up some migrations
return (
<form onSubmit={handleSubmit(onSubmit)}>
@@ -20,6 +20,7 @@ import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { AnalyzeResult, catalogImportApiRef } from '../../api';
import { asInputRef } from '../helpers';
import {
generateEntities,
StepPrepareCreatePullRequest,
@@ -91,10 +92,10 @@ describe('<StepPrepareCreatePullRequest />', () => {
renderFormFields={({ register }) => {
return (
<>
<TextField name="title" inputRef={register()} />
<TextField name="body" inputRef={register()} />
<TextField name="componentName" inputRef={register()} />
<TextField name="owner" inputRef={register()} />
<TextField {...asInputRef(register('title'))} />
<TextField {...asInputRef(register('body'))} />
<TextField {...asInputRef(register('componentName'))} />
<TextField {...asInputRef(register('owner'))} />
</>
);
}}
@@ -132,19 +133,17 @@ describe('<StepPrepareCreatePullRequest />', () => {
renderFormFields={({ register }) => {
return (
<>
<TextField name="title" inputRef={register()} />
<TextField name="body" inputRef={register()} />
<TextField {...asInputRef(register('title'))} />
<TextField {...asInputRef(register('body'))} />
<TextField
{...asInputRef(register('componentName'))}
id="name"
label="name"
name="componentName"
inputRef={register()}
/>
<TextField
{...asInputRef(register('owner'))}
id="owner"
label="owner"
name="owner"
inputRef={register()}
/>
</>
);
@@ -222,10 +221,10 @@ spec:
renderFormFields={({ register }) => {
return (
<>
<TextField name="title" inputRef={register()} />
<TextField name="body" inputRef={register()} />
<TextField name="componentName" inputRef={register()} />
<TextField name="owner" inputRef={register()} />
<TextField {...asInputRef(register('title'))} />
<TextField {...asInputRef(register('body'))} />
<TextField {...asInputRef(register('componentName'))} />
<TextField {...asInputRef(register('owner'))} />
</>
);
}}
@@ -15,6 +15,7 @@
*/
import { Entity } from '@backstage/catalog-model';
import { useApi } from '@backstage/core-plugin-api';
import {
catalogApiRef,
formatEntityRefTitle,
@@ -22,7 +23,7 @@ import {
import { Box, FormHelperText, Grid, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import React, { useCallback, useState } from 'react';
import { UnpackNestedValue, UseFormMethods } from 'react-hook-form';
import { FieldErrors, UnpackNestedValue, UseFormReturn } from 'react-hook-form';
import { useAsync } from 'react-use';
import YAML from 'yaml';
import { AnalyzeResult, catalogImportApiRef } from '../../api';
@@ -32,7 +33,6 @@ import { PrepareResult } from '../useImportState';
import { PreparePullRequestForm } from './PreparePullRequestForm';
import { PreviewCatalogInfoComponent } from './PreviewCatalogInfoComponent';
import { PreviewPullRequestComponent } from './PreviewPullRequestComponent';
import { useApi } from '@backstage/core-plugin-api';
const useStyles = makeStyles(theme => ({
previewCard: {
@@ -63,7 +63,8 @@ type Props = {
defaultBody: string;
renderFormFields: (
props: Pick<UseFormMethods<FormData>, 'errors' | 'register' | 'control'> & {
props: Pick<UseFormReturn<FormData>, 'register' | 'setValue'> & {
errors: FieldErrors<FormData>;
values: UnpackNestedValue<FormData>;
groups: string[];
groupsLoading: boolean;
@@ -192,13 +193,13 @@ export const StepPrepareCreatePullRequest = ({
analyzeResult.generatedEntities[0]?.metadata?.name || '',
useCodeowners: false,
}}
render={({ values, errors, control, register }) => (
render={({ values, errors, register, setValue }) => (
<>
{renderFormFields({
values,
errors,
register,
control,
setValue,
groups: groups ?? [],
groupsLoading,
})}
@@ -0,0 +1,33 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { UseFormRegisterReturn } from 'react-hook-form';
/**
* A helper that converts the result of a render('name', opts) to make it compatible with material-ui.
*
* See also https://github.com/react-hook-form/react-hook-form/issues/4629#issuecomment-815840872
* TODO: remove when updating to material-ui v5 (https://github.com/mui-org/material-ui/pull/23174)
*
* @param renderResult - the result of a render('name', opts)
*/
export function asInputRef(renderResult: UseFormRegisterReturn) {
const { ref, ...rest } = renderResult;
return {
inputRef: ref,
...rest,
};
}