diff --git a/apps/client/src/common/models/ProjectData.ts b/apps/client/src/common/models/ProjectData.ts index 4d7a0e57c..a57066cac 100644 --- a/apps/client/src/common/models/ProjectData.ts +++ b/apps/client/src/common/models/ProjectData.ts @@ -8,4 +8,5 @@ export const projectDataPlaceholder: ProjectData = { backstageUrl: '', backstageInfo: '', projectLogo: null, + custom: [], }; diff --git a/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx b/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx index 56181c462..e7c1deee2 100644 --- a/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx +++ b/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; -import { useForm } from 'react-hook-form'; +import { useFieldArray, useForm } from 'react-hook-form'; +import { IoTrash } from 'react-icons/io5'; import { Button, Input, Textarea } from '@chakra-ui/react'; import { useQueryClient } from '@tanstack/react-query'; @@ -23,6 +24,7 @@ type ProjectCreateFormValues = { publicUrl?: string; backstageInfo?: string; backstageUrl?: string; + custom?: { title: string; value: string }[]; }; export default function ProjectCreateForm(props: ProjectCreateFromProps) { @@ -34,6 +36,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) { const { handleSubmit, register, + control, formState: { isSubmitting, isValid }, setFocus, } = useForm({ @@ -44,6 +47,11 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) { }, }); + const { fields, append, remove } = useFieldArray({ + control, + name: 'custom', + }); + // set focus to first field useEffect(() => { setFocus('title'); @@ -59,6 +67,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) { ...values, filename, }); + await queryClient.invalidateQueries({ queryKey: PROJECT_LIST }); onClose(); } catch (error) { @@ -66,6 +75,10 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) { } }; + const handleAddCustom = () => { + append({ title: '', value: '' }); + }; + return ( + + + + + + {fields.map((field, idx) => ( +
+ {idx + 1}. + + + +
+ ))} +
); diff --git a/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx b/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx index c21bb1fb9..b0e947121 100644 --- a/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx +++ b/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx @@ -1,6 +1,6 @@ import { ChangeEvent, useEffect, useRef } from 'react'; -import { useForm } from 'react-hook-form'; -import { IoDownloadOutline, IoTrash } from 'react-icons/io5'; +import { useFieldArray, useForm } from 'react-hook-form'; +import { IoAdd, IoDownloadOutline, IoTrash } from 'react-icons/io5'; import { Button, Input, Textarea } from '@chakra-ui/react'; import { type ProjectData } from 'ontime-types'; @@ -25,6 +25,7 @@ export default function ProjectData() { formState: { isSubmitting, isValid, isDirty, errors }, setError, watch, + control, setValue, } = useForm({ defaultValues: data, @@ -32,6 +33,12 @@ export default function ProjectData() { resetOptions: { keepDirtyValues: true, }, + mode: 'onChange', + }); + + const { fields, append, remove } = useFieldArray({ + control, + name: 'custom', }); // reset form values if data changes @@ -77,6 +84,10 @@ export default function ProjectData() { }); }; + const handleAddCustom = () => { + append({ title: '', value: '' }); + }; + const onSubmit = async (formData: ProjectData) => { try { await postProjectData(formData); @@ -231,6 +242,69 @@ export default function ProjectData() { {...register('backstageUrl')} /> + + + + + + {fields.length > 0 && + fields.map((field, idx) => { + const rowErrors = errors.custom?.[idx] as + | { + title?: { message?: string }; + value?: { message?: string }; + } + | undefined; + return ( +
+
+
+ + +
+ {rowErrors?.title?.message && {rowErrors.title.message}} +
+