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 <ac@omnivox.dk>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
This commit is contained in:
2024-10-18 11:53:23 -05:00
committed by GitHub
parent b73b529c00
commit c5870452e3
15 changed files with 161 additions and 59 deletions
@@ -85,7 +85,7 @@ export class OscIntegration implements IIntegration<OscSubscription, OSCSettings
private initTX(enabledOut: boolean, targetIP: string, portOut: number, subscriptions: OscSubscription[]) {
this.initSubscriptions(subscriptions);
if (!enabledOut && this.enabledOut) {
if (!enabledOut) {
this.targetIP = targetIP;
this.portOut = portOut;
this.enabledOut = enabledOut;
@@ -104,6 +104,7 @@ export class OscIntegration implements IIntegration<OscSubscription, OSCSettings
try {
this.oscClient = new Client(targetIP, portOut);
logger.info(LogOrigin.Tx, `Starting OSC Clint on port: ${portOut}`);
} catch (error) {
this.oscClient = null;
throw new Error(`Failed initialising OSC client: ${error}`);
@@ -111,7 +112,7 @@ export class OscIntegration implements IIntegration<OscSubscription, OSCSettings
}
private initRX(enabledIn: boolean, portIn: number) {
if (!enabledIn && this.enabledIn) {
if (!enabledIn) {
this.shutdownRX();
return;
}
@@ -925,7 +925,7 @@ describe('custom fields', () => {
describe('createCustomField()', () => {
it('creates a field from given parameters', async () => {
const expected = {
lighting: {
Lighting: {
label: 'Lighting',
type: 'string',
colour: 'blue',
@@ -942,19 +942,19 @@ describe('custom fields', () => {
await createCustomField({ label: 'Sound', type: 'string', colour: 'blue' });
const expected = {
lighting: {
Lighting: {
label: 'Lighting',
type: 'string',
colour: 'blue',
},
sound: {
Sound: {
label: 'Sound',
type: 'string',
colour: 'green',
},
};
const customField = await editCustomField('sound', { label: 'Sound', type: 'string', colour: 'green' });
const customField = await editCustomField('Sound', { label: 'Sound', type: 'string', colour: 'green' });
expect(customFieldChangelog).toStrictEqual(new Map());
expect(customField).toStrictEqual(expected);
@@ -964,17 +964,17 @@ describe('custom fields', () => {
const created = await createCustomField({ label: 'Video', type: 'string', colour: 'red' });
const expected = {
lighting: {
Lighting: {
label: 'Lighting',
type: 'string',
colour: 'blue',
},
sound: {
Sound: {
label: 'Sound',
type: 'string',
colour: 'green',
},
video: {
Video: {
label: 'Video',
type: 'string',
colour: 'red',
@@ -984,17 +984,17 @@ describe('custom fields', () => {
expect(created).toStrictEqual(expected);
const expectedAfter = {
lighting: {
Lighting: {
label: 'Lighting',
type: 'string',
colour: 'blue',
},
sound: {
Sound: {
label: 'Sound',
type: 'string',
colour: 'green',
},
av: {
AV: {
label: 'AV',
type: 'string',
colour: 'red',
@@ -1003,10 +1003,10 @@ describe('custom fields', () => {
// We need to flush all scheduled tasks for the generate function to settle
vi.useFakeTimers();
const customField = await editCustomField('video', { label: 'AV', type: 'string', colour: 'red' });
const customField = await editCustomField('Video', { label: 'AV', type: 'string', colour: 'red' });
expect(customField).toStrictEqual(expectedAfter);
expect(customFieldChangelog).toStrictEqual(new Map([['video', 'av']]));
await editCustomField('av', { label: 'video' });
expect(customFieldChangelog).toStrictEqual(new Map([['Video', 'AV']]));
await editCustomField('AV', { label: 'Video' });
vi.runAllTimers();
expect(customFieldChangelog).toStrictEqual(new Map());
vi.useRealTimers();
@@ -1016,19 +1016,19 @@ describe('custom fields', () => {
describe('removeCustomField()', () => {
it('deletes a field with a given label', async () => {
const expected = {
lighting: {
Lighting: {
label: 'Lighting',
type: 'string',
colour: 'blue',
},
video: {
label: 'video',
Video: {
label: 'Video',
type: 'string',
colour: 'red',
},
};
const customField = await removeCustomField('sound');
const customField = await removeCustomField('Sound');
expect(customField).toStrictEqual(expected);
});
@@ -11,7 +11,15 @@ import {
OntimeRundownEntry,
PlayableEvent,
} from 'ontime-types';
import { generateId, insertAtIndex, reorderArray, swapEventData, getTimeFromPrevious, isNewLatest } from 'ontime-utils';
import {
generateId,
insertAtIndex,
reorderArray,
swapEventData,
getTimeFromPrevious,
isNewLatest,
customFieldLabelToKey,
} from 'ontime-utils';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
import { createPatch } from '../../utils/parser.js';
import { apply } from './delayUtils.js';
@@ -447,7 +455,7 @@ function scheduleCustomFieldPersist(persistedCustomFields: CustomFields) {
*/
export const createCustomField = async (field: CustomField) => {
const { label, type, colour } = field;
const key = label.toLowerCase();
const key = customFieldLabelToKey(label);
// check if label already exists
const alreadyExists = Object.hasOwn(persistedCustomFields, key);
@@ -479,7 +487,7 @@ export const editCustomField = async (key: string, newField: Partial<CustomField
throw new Error('Change of field type is not allowed');
}
const newKey = newField.label.toLowerCase();
const newKey = customFieldLabelToKey(newField.label);
persistedCustomFields[newKey] = { ...existingField, ...newField };
if (key !== newKey) {