From 696c016c906c439042a5fd1f3951f57ed88824ea Mon Sep 17 00:00:00 2001 From: Shobhit Nagpal <74096450+Shobhit-Nagpal@users.noreply.github.com> Date: Sat, 17 May 2025 18:32:50 +0530 Subject: [PATCH] feat: custom data for projects (#1571) --- apps/client/src/common/models/ProjectData.ts | 1 + .../panel/project-panel/ProjectCreateForm.tsx | 51 +++++++++++- .../panel/project-panel/ProjectData.tsx | 78 ++++++++++++++++++- .../project-panel/ProjectPanel.module.scss | 15 ++++ .../src/views/project-info/ProjectInfo.scss | 10 ++- .../src/views/project-info/ProjectInfo.tsx | 2 + .../project-info/custom-info/CustomInfo.tsx | 36 +++++++++ .../views/project-info/projectInfo.options.ts | 11 ++- apps/server/src/api-data/db/db.controller.ts | 3 +- apps/server/src/api-data/db/db.validation.ts | 1 + .../api-data/project/project.controller.ts | 5 +- .../src/api-data/project/project.dao.ts | 9 +++ .../api-data/project/project.validation.ts | 3 + .../src/classes/data-provider/DataProvider.ts | 2 +- .../data-provider/DataProvider.utils.ts | 27 ++++--- .../__tests__/DataProvider.utils.test.ts | 19 +++++ apps/server/src/models/dataModel.ts | 1 + apps/server/src/models/demoProject.ts | 1 + .../project-service/ProjectService.ts | 8 +- .../utils/__tests__/parserFunctions.test.ts | 2 + apps/server/src/utils/parserFunctions.ts | 1 + apps/server/test-db/db.json | 5 +- e2e/tests/fixtures/test-db.json | 5 +- .../src/definitions/core/ProjectData.type.ts | 1 + 24 files changed, 264 insertions(+), 33 deletions(-) create mode 100644 apps/client/src/views/project-info/custom-info/CustomInfo.tsx create mode 100644 apps/server/src/api-data/project/project.dao.ts 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}} +
+