From 6160d7bcb9d3bf2a8b617b422e80fe7df8839967 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sun, 15 Sep 2024 23:36:34 +0800 Subject: [PATCH] refactor: refactor server status edit form with react-hook-form --- .../monitor/StatusPage/EditForm.tsx | 361 +++++++++++------- 1 file changed, 220 insertions(+), 141 deletions(-) diff --git a/src/client/components/monitor/StatusPage/EditForm.tsx b/src/client/components/monitor/StatusPage/EditForm.tsx index eb205f3..4db298f 100644 --- a/src/client/components/monitor/StatusPage/EditForm.tsx +++ b/src/client/components/monitor/StatusPage/EditForm.tsx @@ -1,26 +1,53 @@ -import { Switch, Divider, Form, Input, Typography } from 'antd'; import React from 'react'; import { MonitorPicker } from '../MonitorPicker'; -import { domainValidator, urlSlugValidator } from '../../../utils/validator'; import { useTranslation } from '@i18next-toolkit/react'; import { Button } from '@/components/ui/button'; -import { LuMinusCircle, LuPlus } from 'react-icons/lu'; +import { LuMinus, LuMinusCircle, LuPlus } from 'react-icons/lu'; import { MarkdownEditor } from '@/components/MarkdownEditor'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { useEventWithLoading } from '@/hooks/useEvent'; +import { Input as AntdInput, Divider, Typography } from 'antd'; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { Controller, useFieldArray, useForm } from 'react-hook-form'; +import { domainRegex, slugRegex } from '@tianji/shared'; +import { useElementSize } from '@/hooks/useResizeObserver'; +import { Switch } from '@/components/ui/switch'; -const { Text } = Typography; +const Text = Typography.Text; -export interface MonitorStatusPageEditFormValues { - title: string; - slug: string; - description: string; - monitorList: PrismaJson.MonitorStatusPageList; - domain: string; -} +const editFormSchema = z.object({ + title: z.string(), + slug: z.string().regex(slugRegex), + description: z.string(), + domain: z + .string() + .regex(domainRegex, 'Invalid domain') + .or(z.literal('')) + .optional(), + monitorList: z.array( + z.object({ + id: z.string(), + showCurrent: z.boolean().default(false).optional(), + }) + ), +}); + +export type MonitorStatusPageEditFormValues = z.infer; interface MonitorStatusPageEditFormProps { isLoading?: boolean; initialValues?: Partial; - onFinish: (values: MonitorStatusPageEditFormValues) => void; + onFinish: (values: MonitorStatusPageEditFormValues) => Promise; onCancel?: () => void; saveButtonLabel?: string; } @@ -28,143 +55,195 @@ interface MonitorStatusPageEditFormProps { export const MonitorStatusPageEditForm: React.FC = React.memo((props) => { const { t } = useTranslation(); + const { ref, width } = useElementSize(); + + const form = useForm({ + resolver: zodResolver(editFormSchema), + defaultValues: props.initialValues ?? { + title: '', + slug: '', + description: '', + domain: '', + monitorList: [], + }, + }); + + const { fields, append, remove } = useFieldArray({ + control: form.control, + name: 'monitorList', + keyName: 'key', + }); + + const [handleSubmit, isLoading] = useEventWithLoading( + async (values: MonitorStatusPageEditFormValues) => { + await props.onFinish(values); + form.reset(); + } + ); return ( -
- - layout="vertical" - initialValues={props.initialValues} - onFinish={props.onFinish} +
+ - - - + render={({ field }) => ( + + {t('Title')} + + + + + + )} + /> - -
- {t('Accept characters')}: a-z{' '} - 0-9 - -
-
- {t('No consecutive dashes')} -- -
-
- } - rules={[ - { - required: true, - }, - { - validator: urlSlugValidator, - }, - ]} - > - - - - - - - - - {t( - 'You can config your status page in your own domain, for example: status.example.com' - )} - - } - rules={[ - { - validator: domainValidator, - }, - ]} - > - - - - - {(fields, { add, remove }, { errors }) => { - return ( - <> - -
- {fields.map((field, index) => ( - // monitor item - <> - {index !== 0 && } - -
- - - - -
-
- - - - - - {t('Show Latest Value')} - -
- - remove(field.name)} - /> -
-
- - ))} + render={({ field }) => ( + + {t('Slug')} + + + + +
+
+ {t('Accept characters')}: a-z{' '} + 0-9 -
+
+ {t('No consecutive dashes')} -- +
+
+
+ +
+ )} + /> - + {/* Description */} + ( + + {t('Description')} + + + + + + )} + /> - - - - ); - }} - + {/* Custom Domain */} + ( + + {t('Custom Domain')} + + + + +
+ {t( + 'You can config your status page in your own domain, for example: status.example.com' + )} +
+
+ +
+ )} + /> -
- + + )} + /> + +
+ @@ -174,8 +253,8 @@ export const MonitorStatusPageEditForm: React.FC )}
- -
+ + ); }); MonitorStatusPageEditForm.displayName = 'MonitorStatusPageEditForm';