refactor: fixes to custom field

This commit is contained in:
Carlos Valente
2025-07-11 16:49:41 +02:00
parent 4d419c0877
commit d8c1c38123
20 changed files with 103 additions and 108 deletions
@@ -7,8 +7,8 @@ import { getURLSearchParamsFromObj, makeOptionsFromCustomFields } from '../viewP
describe('makeOptionsFromCustomFields()', () => { describe('makeOptionsFromCustomFields()', () => {
const testCustomFields: CustomFields = { const testCustomFields: CustomFields = {
field1: { label: 'Field 1', colour: 'red', type: 'string' }, field1: { label: 'Field 1', colour: 'red', type: 'text' },
field2: { label: 'Field 2', colour: 'blue', type: 'string' }, field2: { label: 'Field 2', colour: 'blue', type: 'text' },
}; };
it('creates an array of options to use in a select', () => { it('creates an array of options to use in a select', () => {
@@ -16,7 +16,7 @@ interface CustomFieldEntryProps {
colour: string; colour: string;
label: string; label: string;
fieldKey: string; fieldKey: string;
type: 'string' | 'image'; type: CustomField['type'];
onEdit: (key: CustomFieldKey, patch: CustomField) => Promise<void>; onEdit: (key: CustomFieldKey, patch: CustomField) => Promise<void>;
onDelete: (key: CustomFieldKey) => Promise<void>; onDelete: (key: CustomFieldKey) => Promise<void>;
} }
@@ -42,7 +42,7 @@ export default function CustomFieldForm(props: CustomFieldsFormProps) {
watch, watch,
formState: { errors, isSubmitting, isValid, isDirty }, formState: { errors, isSubmitting, isValid, isDirty },
} = useForm<CustomFieldFormData>({ } = useForm<CustomFieldFormData>({
defaultValues: { type: 'string', label: initialLabel || '', colour: initialColour || '' }, defaultValues: { type: 'text', label: initialLabel || '', colour: initialColour || '' },
resetOptions: { resetOptions: {
keepDirtyValues: true, keepDirtyValues: true,
}, },
@@ -96,7 +96,7 @@ export default function CustomFieldForm(props: CustomFieldsFormProps) {
onValueChange={(value) => setValue('type', value, { shouldDirty: true })} onValueChange={(value) => setValue('type', value, { shouldDirty: true })}
value={watch('type')} value={watch('type')}
items={[ items={[
{ value: 'string', label: 'Text' }, { value: 'text', label: 'Text' },
{ value: 'image', label: 'Image' }, { value: 'image', label: 'Image' },
]} ]}
/> />
@@ -30,7 +30,7 @@ export default function EntryEditorCustomFields({
const { backgroundColor, color } = getAccessibleColour(customFields[fieldKey].colour); const { backgroundColor, color } = getAccessibleColour(customFields[fieldKey].colour);
const labelText = customFields[fieldKey].label; const labelText = customFields[fieldKey].label;
if (customFields[fieldKey].type === 'string') { if (customFields[fieldKey].type === 'text') {
return ( return (
<EventTextArea <EventTextArea
key={key} key={key}
@@ -183,7 +183,7 @@ export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<Ontim
id: key, id: key,
header: customFields[key].label, header: customFields[key].label,
meta: { colour: customFields[key].colour, type: customFields[key].type }, meta: { colour: customFields[key].colour, type: customFields[key].type },
cell: customFields[key].type === 'string' ? MakeCustomField : LazyImage, cell: customFields[key].type === 'text' ? MakeCustomField : LazyImage,
size: 250, size: 250,
minSize: 75, minSize: 75,
})); }));
@@ -14,17 +14,17 @@ describe('parseCustomFields()', () => {
const errorEmitter = vi.fn(); const errorEmitter = vi.fn();
// @ts-expect-error -- data is external, we check bad types // @ts-expect-error -- data is external, we check bad types
const customFields = { const customFields = {
1: { label: 'test', type: 'string', colour: 'red' }, // ok 1: { label: 'test', type: 'text', colour: 'red' }, // ok
2: { label: 'test', type: 'string' }, // duplicate label 2: { label: 'test', type: 'text' }, // duplicate label
3: { label: '', type: 'string' }, // missing colour 3: { label: '', type: 'text' }, // missing colour
4: { type: 'string', colour: '' }, // missing label 4: { type: 'text', colour: '' }, // missing label
} as CustomFields; } as CustomFields;
const result = parseCustomFields({ customFields }, errorEmitter); const result = parseCustomFields({ customFields }, errorEmitter);
expect(result).toMatchObject({ expect(result).toMatchObject({
test: { test: {
label: 'test', label: 'test',
type: 'string', type: 'text',
colour: 'red', colour: 'red',
}, },
}); });
@@ -39,9 +39,9 @@ describe('sanitiseCustomFields()', () => {
it('returns an object of valid entries', () => { it('returns an object of valid entries', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
test: { label: 'test', type: 'string', colour: 'red' }, test: { label: 'test', type: 'text', colour: 'red' },
test2: { label: 'test2', type: 'string', colour: 'green' }, test2: { label: 'test2', type: 'text', colour: 'green' },
Test3: { label: 'Test3', type: 'string', colour: '' }, Test3: { label: 'Test3', type: 'text', colour: '' },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual(customFields); expect(sanitationResult).toStrictEqual(customFields);
@@ -51,18 +51,18 @@ describe('sanitiseCustomFields()', () => {
const testTypes = sanitiseCustomFields({ const testTypes = sanitiseCustomFields({
test1: { label: 'test1', type: 'another', colour: 'red' }, test1: { label: 'test1', type: 'another', colour: 'red' },
test2: { label: 'test2', type: 'image', colour: 'red' }, test2: { label: 'test2', type: 'image', colour: 'red' },
test3: { label: 'test3', type: 'string', colour: 'red' }, test3: { label: 'test3', type: 'text', colour: 'red' },
}); });
expect(testTypes).toMatchObject({ expect(testTypes).toMatchObject({
test2: { label: 'test2', type: 'image', colour: 'red' }, test2: { label: 'test2', type: 'image', colour: 'red' },
test3: { label: 'test3', type: 'string', colour: 'red' }, test3: { label: 'test3', type: 'text', colour: 'red' },
}); });
}); });
it('colour must be a string', () => { it('colour must be a string', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
// @ts-expect-error intentional bad data // @ts-expect-error intentional bad data
test: { label: 'test', type: 'string', colour: 5 }, test: { label: 'test', type: 'text', colour: 5 },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual({}); expect(sanitationResult).toStrictEqual({});
@@ -70,7 +70,7 @@ describe('sanitiseCustomFields()', () => {
it('label can not be empty', () => { it('label can not be empty', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
'': { label: '', type: 'string', colour: 'red' }, '': { label: '', type: 'text', colour: 'red' },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual({}); expect(sanitationResult).toStrictEqual({});
@@ -79,10 +79,10 @@ describe('sanitiseCustomFields()', () => {
it('remove extra stuff', () => { it('remove extra stuff', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
// @ts-expect-error intentional bad data // @ts-expect-error intentional bad data
test: { label: 'test', type: 'string', colour: 'red', extra: 'should be removed' }, test: { label: 'test', type: 'text', colour: 'red', extra: 'should be removed' },
}; };
const expectedCustomFields: CustomFields = { const expectedCustomFields: CustomFields = {
test: { label: 'test', type: 'string', colour: 'red' }, test: { label: 'test', type: 'text', colour: 'red' },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual(expectedCustomFields); expect(sanitationResult).toStrictEqual(expectedCustomFields);
@@ -90,10 +90,10 @@ describe('sanitiseCustomFields()', () => {
it('enforce name cohesion', () => { it('enforce name cohesion', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
test: { label: 'NewName', type: 'string', colour: 'red' }, test: { label: 'NewName', type: 'text', colour: 'red' },
}; };
const expectedCustomFields: CustomFields = { const expectedCustomFields: CustomFields = {
NewName: { label: 'NewName', type: 'string', colour: 'red' }, NewName: { label: 'NewName', type: 'text', colour: 'red' },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual(expectedCustomFields); expect(sanitationResult).toStrictEqual(expectedCustomFields);
@@ -101,10 +101,10 @@ describe('sanitiseCustomFields()', () => {
it('labels with space', () => { it('labels with space', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
Test_with_Space: { label: 'Test with Space', type: 'string', colour: 'red' }, Test_with_Space: { label: 'Test with Space', type: 'text', colour: 'red' },
}; };
const expectedCustomFields: CustomFields = { const expectedCustomFields: CustomFields = {
Test_with_Space: { label: 'Test with Space', type: 'string', colour: 'red' }, Test_with_Space: { label: 'Test with Space', type: 'text', colour: 'red' },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual(expectedCustomFields); expect(sanitationResult).toStrictEqual(expectedCustomFields);
@@ -112,15 +112,15 @@ describe('sanitiseCustomFields()', () => {
it('filters invalid entries', () => { it('filters invalid entries', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
test: { label: 'test', type: 'string', colour: 'red' }, test: { label: 'test', type: 'text', colour: 'red' },
test2: { label: 'test2', type: 'string', colour: 'green' }, test2: { label: 'test2', type: 'text', colour: 'green' },
bad: { label: '', type: 'string', colour: '' }, bad: { label: '', type: 'text', colour: '' },
Test3: { label: 'Test3', type: 'string', colour: '' }, Test3: { label: 'Test3', type: 'text', colour: '' },
}; };
const expectedCustomFields: CustomFields = { const expectedCustomFields: CustomFields = {
test: { label: 'test', type: 'string', colour: 'red' }, test: { label: 'test', type: 'text', colour: 'red' },
test2: { label: 'test2', type: 'string', colour: 'green' }, test2: { label: 'test2', type: 'text', colour: 'green' },
Test3: { label: 'Test3', type: 'string', colour: '' }, Test3: { label: 'Test3', type: 'text', colour: '' },
}; };
const sanitationResult = sanitiseCustomFields(customFields); const sanitationResult = sanitiseCustomFields(customFields);
expect(sanitationResult).toStrictEqual(expectedCustomFields); expect(sanitationResult).toStrictEqual(expectedCustomFields);
@@ -56,7 +56,7 @@ export function sanitiseCustomFields(data: object): CustomFields {
'colour' in data && 'colour' in data &&
typeof data.colour === 'string' && typeof data.colour === 'string' &&
'type' in data && 'type' in data &&
(data.type === 'string' || data.type === 'image') (data.type === 'text' || data.type === 'image')
); );
} }
@@ -11,7 +11,7 @@ export const validateCustomField = [
.custom((value) => { .custom((value) => {
return isAlphanumericWithSpace(value); return isAlphanumericWithSpace(value);
}), }),
body('type').isIn(['string', 'image']), body('type').isIn(['text', 'image']),
body('colour').isString().trim(), body('colour').isString().trim(),
requestValidationFunction, requestValidationFunction,
@@ -26,7 +26,7 @@ export const validateEditCustomField = [
.custom((value) => { .custom((value) => {
return isAlphanumericWithSpace(value); return isAlphanumericWithSpace(value);
}), }),
body('type').isIn(['string', 'image']), body('type').isIn(['text', 'image']),
body('colour').isString().trim(), body('colour').isString().trim(),
requestValidationFunction, requestValidationFunction,
@@ -18,30 +18,30 @@ describe('parseExcel()', () => {
}; };
const existingCustomFields: CustomFields = { const existingCustomFields: CustomFields = {
user0: { type: 'string', colour: 'red', label: 'user0' }, user0: { type: 'text', colour: 'red', label: 'user0' },
user1: { type: 'string', colour: 'green', label: 'user1' }, user1: { type: 'text', colour: 'green', label: 'user1' },
user2: { type: 'string', colour: 'blue', label: 'user2' }, user2: { type: 'text', colour: 'blue', label: 'user2' },
}; };
const parsedData = parseExcel(dataFromExcelTemplate, existingCustomFields, 'testSheet', importMap); const parsedData = parseExcel(dataFromExcelTemplate, existingCustomFields, 'testSheet', importMap);
expect(parsedData.customFields).toStrictEqual({ expect(parsedData.customFields).toStrictEqual({
user0: { user0: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'user0', label: 'user0',
}, },
user1: { user1: {
type: 'string', type: 'text',
colour: 'green', colour: 'green',
label: 'user1', label: 'user1',
}, },
user2: { user2: {
type: 'string', type: 'text',
colour: 'blue', colour: 'blue',
label: 'user2', label: 'user2',
}, },
user3: { user3: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'user3', label: 'user3',
}, },
@@ -97,12 +97,12 @@ describe('parseExcel()', () => {
const parsedData = parseExcel(dataFromExcelTemplate, {}, 'testSheet', importMap); const parsedData = parseExcel(dataFromExcelTemplate, {}, 'testSheet', importMap);
expect(parsedData.customFields).toStrictEqual({ expect(parsedData.customFields).toStrictEqual({
niu1: { niu1: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'niu1', label: 'niu1',
}, },
niu2: { niu2: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'niu2', label: 'niu2',
}, },
@@ -448,17 +448,17 @@ describe('getCustomFieldData()', () => {
const result = getCustomFieldData(importMap, {}); const result = getCustomFieldData(importMap, {});
expect(result.mergedCustomFields).toStrictEqual({ expect(result.mergedCustomFields).toStrictEqual({
lighting: { lighting: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'lighting', label: 'lighting',
}, },
sound: { sound: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'sound', label: 'sound',
}, },
video: { video: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'video', label: 'video',
}, },
@@ -499,30 +499,30 @@ describe('getCustomFieldData()', () => {
} as ImportMap; } as ImportMap;
const existingCustomFields: CustomFields = { const existingCustomFields: CustomFields = {
lighting: { label: 'lighting', type: 'string', colour: 'red' }, lighting: { label: 'lighting', type: 'text', colour: 'red' },
sound: { label: 'sound', type: 'string', colour: 'green' }, sound: { label: 'sound', type: 'text', colour: 'green' },
ontime_key: { label: 'ontime key', type: 'string', colour: 'blue' }, ontime_key: { label: 'ontime key', type: 'text', colour: 'blue' },
}; };
const result = getCustomFieldData(importMap, existingCustomFields); const result = getCustomFieldData(importMap, existingCustomFields);
expect(result.mergedCustomFields).toStrictEqual({ expect(result.mergedCustomFields).toStrictEqual({
lighting: { lighting: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'lighting', label: 'lighting',
}, },
sound: { sound: {
type: 'string', type: 'text',
colour: 'green', colour: 'green',
label: 'sound', label: 'sound',
}, },
video: { video: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'video', label: 'video',
}, },
ontime_key: { ontime_key: {
type: 'string', type: 'text',
colour: 'blue', colour: 'blue',
label: 'ontime key', label: 'ontime key',
}, },
@@ -550,17 +550,17 @@ describe('getCustomFieldData()', () => {
const result = getCustomFieldData(importMap, {}); const result = getCustomFieldData(importMap, {});
expect(result.mergedCustomFields).toStrictEqual({ expect(result.mergedCustomFields).toStrictEqual({
Lighting: { Lighting: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'Lighting', label: 'Lighting',
}, },
Sound: { Sound: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'Sound', label: 'Sound',
}, },
video: { video: {
type: 'string', type: 'text',
colour: '', colour: '',
label: 'video', label: 'video',
}, },
@@ -330,7 +330,7 @@ export function getCustomFieldData(
// 1. add the custom field to the merged custom fields // 1. add the custom field to the merged custom fields
mergedCustomFields[keyInCustomFields] = { mergedCustomFields[keyInCustomFields] = {
type: 'string', // we currently only support string custom fields type: 'text', // we currently only support text custom fields
colour: maybeExistingColour, colour: maybeExistingColour,
label: ontimeLabel, label: ontimeLabel,
}; };
@@ -49,7 +49,7 @@ export function makeRundown(patch: Partial<Rundown>): Rundown {
export function makeCustomField(patch: Partial<CustomField>): CustomField { export function makeCustomField(patch: Partial<CustomField>): CustomField {
return { return {
type: 'string', type: 'text',
colour: '#000000', colour: '#000000',
label: 'Custom Field', label: 'Custom Field',
...patch, ...patch,
@@ -62,7 +62,7 @@ describe('createTransaction', () => {
rundown.title = 'Another Title'; rundown.title = 'Another Title';
customFields['newField'] = { customFields['newField'] = {
label: 'New Field', label: 'New Field',
type: 'string', type: 'text',
colour: 'blue', colour: 'blue',
}; };
@@ -524,12 +524,12 @@ describe('processRundown()', () => {
const customProperties: CustomFields = { const customProperties: CustomFields = {
lighting: { lighting: {
label: 'lighting', label: 'lighting',
type: 'string', type: 'text',
colour: 'red', colour: 'red',
}, },
sound: { sound: {
label: 'sound', label: 'sound',
type: 'string', type: 'text',
colour: 'red', colour: 'red',
}, },
}; };
@@ -197,12 +197,12 @@ describe('parseRundown()', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
lighting: { lighting: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'lighting', label: 'lighting',
}, },
sound: { sound: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'sound', label: 'sound',
}, },
@@ -229,7 +229,7 @@ describe('parseRundown()', () => {
const customFields: CustomFields = { const customFields: CustomFields = {
lighting: { lighting: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'lighting', label: 'lighting',
}, },
@@ -308,12 +308,12 @@ describe('handleCustomField()', () => {
it('creates a map of where custom fields are used', () => { it('creates a map of where custom fields are used', () => {
const customFields = { const customFields = {
lighting: { lighting: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'lighting', label: 'lighting',
}, },
sound: { sound: {
type: 'string', type: 'text',
colour: 'red', colour: 'red',
label: 'sound', label: 'sound',
}, },
+15 -25
View File
@@ -121,38 +121,28 @@ export function createTransaction(options: TransactionOptions): Transaction {
await getDataProvider().setRundown(cachedRundown.id, cachedRundown); await getDataProvider().setRundown(cachedRundown.id, cachedRundown);
}); });
// increment the revision number // update fields which are agnostic of whether the rundown is processed
cachedRundown.revision = cachedRundown.revision + 1; cachedRundown.revision = cachedRundown.revision + 1;
cachedRundown.title = rundown.title;
/**
* Some mutations do not require processing the rundown
* We simply increment the revision and return the rundown
*/
if (!shouldProcess) { if (!shouldProcess) {
cachedRundown.title = rundown.title; // if we dont need to process, we just reassign the commit data to the cache
cachedRundown.entries = rundown.entries; cachedRundown.entries = rundown.entries;
cachedRundown.order = rundown.order; cachedRundown.order = rundown.order;
cachedRundown.flatOrder = rundown.flatOrder; cachedRundown.flatOrder = rundown.flatOrder;
return { } else {
rundown: cachedRundown, const processedData = processRundown(rundown, projectCustomFields);
rundownMetadata, // metadata doesnt change as long as we dont process the rundown // update the cache values
customFields: projectCustomFields, // eslint-disable-next-line @typescript-eslint/no-unused-vars -- we are not interested in the iteration data
revision: cachedRundown.revision, const { previousEvent, latestEvent, previousEntry, entries, order, assignedCustomFields, ...metadata } =
}; processedData;
cachedRundown.entries = entries;
cachedRundown.order = order;
cachedRundown.flatOrder = metadata.flatEntryOrder;
customFieldsMetadata.assigned = assignedCustomFields;
rundownMetadata = metadata;
} }
const processedData = processRundown(rundown, projectCustomFields);
// update the cache values
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- we are not interested in the iteration data
const { previousEvent, latestEvent, previousEntry, entries, order, assignedCustomFields, ...metadata } =
processedData;
cachedRundown.title = rundown.title;
cachedRundown.entries = entries;
cachedRundown.order = order;
cachedRundown.flatOrder = metadata.flatEntryOrder;
customFieldsMetadata.assigned = assignedCustomFields;
rundownMetadata = metadata;
} }
// if the customFields are mutable we persist the changes // if the customFields are mutable we persist the changes
@@ -464,9 +464,14 @@ export async function editCustomField(key: CustomFieldKey, newField: Partial<Cus
const { oldKey, newKey } = customFieldMutation.edit(customFields, key, existingField, newField); const { oldKey, newKey } = customFieldMutation.edit(customFields, key, existingField, newField);
// if key has changed we remove the old reference // if key has changed
if (oldKey !== newKey && oldKey in customFieldsMetadata.assigned) { if (oldKey !== newKey) {
customFieldMutation.renameUsages(rundown, customFieldsMetadata.assigned, oldKey, newKey); // 1. delete the old key
customFieldMutation.remove(customFields, oldKey);
if (oldKey in customFieldsMetadata.assigned) {
// 2. reassign references
customFieldMutation.renameUsages(rundown, customFieldsMetadata.assigned, oldKey, newKey);
}
} }
// the custom fields have been removed and there is no processing to be done // the custom fields have been removed and there is no processing to be done
@@ -101,21 +101,21 @@ describe('safeMerge', () => {
it('merges customFields into existing object', () => { it('merges customFields into existing object', () => {
const existing = { const existing = {
customFields: { customFields: {
lighting: { type: 'string', label: 'lighting' }, lighting: { type: 'text', label: 'lighting' },
sound: { type: 'string', label: 'sound' }, sound: { type: 'text', label: 'sound' },
}, },
}; };
const newData = { const newData = {
customFields: { customFields: {
switcher: { type: 'string', label: 'switcher' }, switcher: { type: 'text', label: 'switcher' },
vfx: { type: 'string', label: 'vfx' }, vfx: { type: 'text', label: 'vfx' },
}, },
}; };
const expected = { const expected = {
switcher: { type: 'string', label: 'switcher' }, switcher: { type: 'text', label: 'switcher' },
vfx: { type: 'string', label: 'vfx' }, vfx: { type: 'text', label: 'vfx' },
}; };
//@ts-expect-error -- testing partial merge //@ts-expect-error -- testing partial merge
+2 -2
View File
@@ -528,12 +528,12 @@ export const demoDb: DatabaseModel = {
customFields: { customFields: {
Song: { Song: {
label: 'Song', label: 'Song',
type: 'string', type: 'text',
colour: '#339E4E', colour: '#339E4E',
}, },
Artist: { Artist: {
label: 'Artist', label: 'Artist',
type: 'string', type: 'text',
colour: '#3E75E8', colour: '#3E75E8',
}, },
}, },
+2 -2
View File
@@ -477,12 +477,12 @@
"customFields": { "customFields": {
"song": { "song": {
"label": "Song", "label": "Song",
"type": "string", "type": "text",
"colour": "#339E4E" "colour": "#339E4E"
}, },
"artist": { "artist": {
"label": "Artist", "label": "Artist",
"type": "string", "type": "text",
"colour": "#3E75E8" "colour": "#3E75E8"
} }
}, },
+2 -2
View File
@@ -494,12 +494,12 @@
"customFields": { "customFields": {
"Song": { "Song": {
"label": "Song", "label": "Song",
"type": "string", "type": "text",
"colour": "#339E4E" "colour": "#339E4E"
}, },
"Artist": { "Artist": {
"label": "Artist", "label": "Artist",
"type": "string", "type": "text",
"colour": "#3E75E8" "colour": "#3E75E8"
} }
}, },
@@ -1,7 +1,7 @@
export type CustomFieldKey = string; export type CustomFieldKey = string;
export type CustomField = { export type CustomField = {
type: 'string' | 'image'; type: 'text' | 'image';
colour: string; colour: string;
label: string; label: string;
}; };