From c5870452e39939d71b7dd178c22805d5afd542ae Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Fri, 18 Oct 2024 11:53:23 -0500 Subject: [PATCH] make custom fields case sensitive (#1242) * remove custom field lowercasing * don't allow custom field form to submit duplicate field * remove unused * update custom field tests * also keep upper case when editing * show key in UI * also kep upper case when creating a new field * fix test * allow old forced case keys to stay as is * allow space * add extension to import * supply initial key to CustomFieldForm * refactor: improve element contrast * refactor: style and composition * consistent use of `customFieldLabelToKey` * fix CopyTag * remove log --------- Co-authored-by: arc-alex Co-authored-by: Carlos Valente --- apps/client/src/externals.ts | 1 + .../FeatureSettings.module.scss | 10 ++++ .../custom-fields/CustomFieldEntry.tsx | 9 +++- .../custom-fields/CustomFieldForm.tsx | 52 ++++++++++++------- .../custom-fields/CustomFields.tsx | 13 +++-- apps/client/src/theme/OntimeAlert.ts | 2 +- .../custom-fields/customFields.validation.ts | 4 +- .../integration-service/OscIntegration.ts | 5 +- .../__tests__/rundownCache.test.ts | 34 ++++++------ .../services/rundown-service/rundownCache.ts | 14 +++-- .../utils/__tests__/parserFunctions.test.ts | 32 ++++++++++-- apps/server/src/utils/parserFunctions.ts | 19 +++++-- packages/utils/index.ts | 4 +- .../customFieldLabelToKey.ts | 12 +++++ .../utils/src/regex-utils/isAlphanumeric.ts | 9 ++++ 15 files changed, 161 insertions(+), 59 deletions(-) create mode 100644 packages/utils/src/customField-utils/customFieldLabelToKey.ts diff --git a/apps/client/src/externals.ts b/apps/client/src/externals.ts index ea971bfc9..a456611f9 100644 --- a/apps/client/src/externals.ts +++ b/apps/client/src/externals.ts @@ -3,3 +3,4 @@ export const apiRepoLatest = 'https://api.github.com/repos/cpvalente/ontime/rele export const websiteUrl = 'https://www.getontime.no'; export const documentationUrl = 'https://docs.getontime.no'; +export const customFieldsDocsUrl = 'https://docs.getontime.no/features/custom-fields/'; diff --git a/apps/client/src/features/app-settings/panel/feature-settings-panel/FeatureSettings.module.scss b/apps/client/src/features/app-settings/panel/feature-settings-panel/FeatureSettings.module.scss index c9c8a13f2..704cf483a 100644 --- a/apps/client/src/features/app-settings/panel/feature-settings-panel/FeatureSettings.module.scss +++ b/apps/client/src/features/app-settings/panel/feature-settings-panel/FeatureSettings.module.scss @@ -1,3 +1,7 @@ +.halfWidth { + width: 50%; +} + .fullWidth { width: 100%; } @@ -37,3 +41,9 @@ .flex { display: flex; } + +.twoCols { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} diff --git a/apps/client/src/features/app-settings/panel/feature-settings-panel/custom-fields/CustomFieldEntry.tsx b/apps/client/src/features/app-settings/panel/feature-settings-panel/custom-fields/CustomFieldEntry.tsx index 18a787392..a22694ee8 100644 --- a/apps/client/src/features/app-settings/panel/feature-settings-panel/custom-fields/CustomFieldEntry.tsx +++ b/apps/client/src/features/app-settings/panel/feature-settings-panel/custom-fields/CustomFieldEntry.tsx @@ -4,6 +4,7 @@ import { IoPencil } from '@react-icons/all-files/io5/IoPencil'; import { IoTrash } from '@react-icons/all-files/io5/IoTrash'; import { CustomField, CustomFieldLabel } from 'ontime-types'; +import CopyTag from '../../../../../common/components/copy-tag/CopyTag'; import Swatch from '../../../../../common/components/input/colour-input/Swatch'; import CustomFieldForm from './CustomFieldForm'; @@ -36,6 +37,7 @@ export default function CustomFieldEntry(props: CustomFieldEntryProps) { onSubmit={handleEdit} initialColour={colour} initialLabel={label} + initialKey={field} /> @@ -47,7 +49,12 @@ export default function CustomFieldEntry(props: CustomFieldEntryProps) { - {label} + {label} + + + {field} + + void; initialColour?: string; initialLabel?: string; + initialKey?: string; } export default function CustomFieldForm(props: CustomFieldsFormProps) { - const { onSubmit, onCancel, initialColour, initialLabel } = props; + const { onSubmit, onCancel, initialColour, initialLabel, initialKey } = props; + const { data } = useCustomFields(); + // we use this to force an update const [_, setColour] = useState(initialColour || ''); @@ -31,7 +35,7 @@ export default function CustomFieldForm(props: CustomFieldsFormProps) { getValues, formState: { errors, isSubmitting, isValid, isDirty }, } = useForm({ - defaultValues: { label: initialLabel || '', colour: initialColour || '' }, + defaultValues: { label: initialLabel || '', colour: initialColour || '', key: initialKey || '' }, resetOptions: { keepDirtyValues: true, }, @@ -66,28 +70,38 @@ export default function CustomFieldForm(props: CustomFieldsFormProps) { return (
-
- Label (only alphanumeric characters are allowed) - {errors.label && {errors.label.message}} - { - if (value.trim().length === 0) return 'Required field'; - if (!isAlphanumeric(value)) return 'Only alphanumeric characters are allowed'; - return true; - }, - })} - size='sm' - variant='ontime-filled' - autoComplete='off' - /> +
+
+ Label (only alphanumeric characters are allowed) + {errors.label && {errors.label.message}} + setValue('key', customFieldLabelToKey(getValues('label')) ?? 'N/A'), + validate: (value) => { + if (value.trim().length === 0) return 'Required field'; + if (!isAlphanumericWithSpace(value)) return 'Only alphanumeric characters and space are allowed'; + if (Object.keys(data).includes(value)) return 'Custom fields must be unique'; + return true; + }, + })} + size='sm' + variant='ontime-filled' + autoComplete='off' + /> +
+ +
+ Key (auto-generated value for use in Integrations and API) + +
Colour handleSelectColour(value)} />
+ {errors.root && {errors.root.message}}