From 78e2f217a4a5afab4c198ada82bc5bfa21325965 Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Sat, 28 Sep 2024 20:34:04 +0200 Subject: [PATCH] handle timer type whitespace (#1225) --- .../server/src/utils/__tests__/parser.test.ts | 170 ++++++++++++++++-- apps/server/src/utils/parser.ts | 7 +- apps/server/src/utils/parserUtils.ts | 4 +- 3 files changed, 157 insertions(+), 24 deletions(-) diff --git a/apps/server/src/utils/__tests__/parser.test.ts b/apps/server/src/utils/__tests__/parser.test.ts index d09d1ed029..b7cbc9863a 100644 --- a/apps/server/src/utils/__tests__/parser.test.ts +++ b/apps/server/src/utils/__tests__/parser.test.ts @@ -729,26 +729,37 @@ describe('test import of v2 datamodel', () => { describe('makeString()', () => { it('converts variables to string', () => { - let val = 2; - let expected = '2'; - let converted = makeString(val); - expect(converted).toBe(expected); - - val = 2.22222222; - expected = '2.22222222'; - converted = makeString(val); - expect(converted).toBe(expected); - - // @ts-expect-error -- we know this is wrong, testing imports outside domain - val = ['testing']; - expected = 'testing'; - converted = makeString(val); - expect(converted).toBe(expected); + const cases = [ + { + val: 2, + expected: '2', + }, + { + val: 2.22222222, + expected: '2.22222222', + }, + { + val: ['testing'], + expected: 'testing', + }, + { + val: ' testing ', + expected: 'testing', + }, + { + val: { doing: 'testing' }, + expected: 'fallback', + }, + { + val: undefined, + expected: 'fallback', + }, + ]; - // @ts-expect-error -- we know this is wrong, testing imports outside domain - val = { doing: 'testing' }; - converted = makeString(val, 'fallback'); - expect(converted).toBe('fallback'); + cases.forEach(({ val, expected }) => { + const converted = makeString(val, 'fallback'); + expect(converted).toBe(expected); + }); }); }); @@ -1222,6 +1233,7 @@ describe('parseExcel()', () => { expect(result.rundown.length).toBe(1); expect((result.rundown.at(0) as OntimeEvent).title).toBe('A song from the hearth'); }); + it('imports blocks', () => { const testdata = [ [ @@ -1388,6 +1400,126 @@ describe('parseExcel()', () => { expect((result.rundown.at(1) as OntimeEvent).timerType).toBe(TimerType.CountDown); }); + it('imports as events if timer type is empty or has whitespace', () => { + const testdata = [ + [ + 'Time Start', + 'Time End', + 'Title', + 'End Action', + 'Public', + 'Skip', + 'Notes', + 'test0', + 'test1', + 'test2', + 'test3', + 'test4', + 'test5', + 'test6', + 'test7', + 'test8', + 'test9', + 'Colour', + 'cue', + 'Timer type', + ], + [ + '', + '', + '', + '', + 'x', + '', + 'Ballyhoo', + 'a0', + 'a1', + 'a2', + 'a3', + 'a4', + 'a5', + 'a6', + 'a7', + 'a8', + 'a9', + 'red', + 101, + ' ', + ], + [ + '1899-12-30T08:00:00.000Z', + '1899-12-30T08:30:00.000Z', + 'A song from the hearth', + 'load-next', + '', + 'x', + 'Rainbow chase', + 'b0', + '', + '', + '', + '', + 'b5', + '', + '', + '', + '', + '#F00', + 102, + undefined, + ], + [ + '1899-12-30T08:00:00.000Z', + '1899-12-30T08:30:00.000Z', + 'A song from the hearth', + 'load-next', + '', + 'x', + 'Rainbow chase', + 'b0', + '', + '', + '', + '', + 'b5', + '', + '', + '', + '', + '#F00', + 103, + ' count-up ', + ], + [], + ]; + + const importMap = { + worksheet: 'event schedule', + timeStart: 'time start', + timeEnd: 'time end', + duration: 'duration', + cue: 'cue', + title: 'title', + isPublic: 'public', + skip: 'skip', + note: 'notes', + colour: 'colour', + endAction: 'end action', + timerType: 'timer type', + timeWarning: 'warning time', + timeDanger: 'danger time', + custom: {}, + }; + const result = parseExcel(testdata, importMap); + expect(result.rundown.length).toBe(3); + expect((result.rundown.at(0) as OntimeEvent).type).toBe(SupportedEvent.Event); + expect((result.rundown.at(0) as OntimeEvent).timerType).toBe(TimerType.CountDown); + expect((result.rundown.at(1) as OntimeEvent).type).toBe(SupportedEvent.Event); + expect((result.rundown.at(1) as OntimeEvent).timerType).toBe(TimerType.CountDown); + expect((result.rundown.at(2) as OntimeEvent).type).toBe(SupportedEvent.Event); + expect((result.rundown.at(2) as OntimeEvent).timerType).toBe(TimerType.CountUp); + }); + it('am/pm conversion to 24h', () => { const testData = [ ['Time Start', 'Time End', 'Title', 'End Action', 'Public', 'Skip', 'Notes', 'Colour', 'cue'], diff --git a/apps/server/src/utils/parser.ts b/apps/server/src/utils/parser.ts index d920d8a409..bf4dd6f44c 100644 --- a/apps/server/src/utils/parser.ts +++ b/apps/server/src/utils/parser.ts @@ -195,11 +195,12 @@ export const parseExcel = (excelData: unknown[][], options?: Partial) const column = row[j]; // 1. we check if we have set a flag for a known field if (j === timerTypeIndex) { - if (column === 'block') { + const maybeTimeType = makeString(column, ''); + if (maybeTimeType === 'block') { event.type = SupportedEvent.Block; - } else if (column === '' || isKnownTimerType(column)) { + } else if (maybeTimeType === '' || isKnownTimerType(maybeTimeType)) { event.type = SupportedEvent.Event; - event.timerType = validateTimerType(column); + event.timerType = validateTimerType(maybeTimeType); } else { // if it is not a block or a known type, we dont import it return; diff --git a/apps/server/src/utils/parserUtils.ts b/apps/server/src/utils/parserUtils.ts index 02ff56d2b8..974d518368 100644 --- a/apps/server/src/utils/parserUtils.ts +++ b/apps/server/src/utils/parserUtils.ts @@ -8,9 +8,9 @@ import { deepmerge } from 'ontime-utils'; * @returns {string} - value as string or fallback if not possible */ export const makeString = (val: unknown, fallback = ''): string => { - if (typeof val === 'string') return val; + if (typeof val === 'string') return val.trim(); else if (val == null || val.constructor === Object) return fallback; - return val.toString(); + return val.toString().trim(); }; /**