From 1e1aa4bca5762de00d1ed92fe840fe39bbb27941 Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Mon, 12 May 2025 13:56:25 +0200 Subject: [PATCH] Fix: sheet export (#1606) * add util to get keys from labels * look for existing keys first then create new * save ontime key to rundown metadata * update test --- apps/server/src/utils/__tests__/parser.test.ts | 18 +++++++++++++----- apps/server/src/utils/parser.ts | 12 +++++++----- packages/utils/index.ts | 2 +- .../customField-utils/customFieldLabelToKey.ts | 10 ++++++++++ 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/server/src/utils/__tests__/parser.test.ts b/apps/server/src/utils/__tests__/parser.test.ts index 6a4c4e724..3f34bb90d 100644 --- a/apps/server/src/utils/__tests__/parser.test.ts +++ b/apps/server/src/utils/__tests__/parser.test.ts @@ -838,6 +838,7 @@ describe('getCustomFieldData()', () => { lighting: 'lx', sound: 'sound', video: 'av', + ontime_label: 'excel label', }, entryId: 'id', } as ImportMap; @@ -845,6 +846,7 @@ describe('getCustomFieldData()', () => { const customFields: CustomFields = { lighting: { label: 'lx', type: 'string', colour: 'red' }, sound: { label: 'sound', type: 'string', colour: 'green' }, + ontime_key: { label: 'ontime_label', type: 'string', colour: 'blue' }, }; const result = getCustomFieldData(importMap, customFields); @@ -864,6 +866,11 @@ describe('getCustomFieldData()', () => { colour: '', label: 'video', }, + ontime_key: { + type: 'string', + colour: 'blue', + label: 'ontime_label', + }, }); // it is an inverted record of @@ -871,6 +878,7 @@ describe('getCustomFieldData()', () => { lx: 'lighting', sound: 'sound', av: 'video', + 'excel label': 'ontime_key', }); }); }); @@ -1022,8 +1030,8 @@ describe('parseExcel()', () => { user2: { type: 'string', colour: 'blue', label: 'user2' }, }; - const parsedData = parseExcel(testdata, existingCustomFields, importMap); - expect(parsedData.customFields).toStrictEqual({ + const { customFields, rundown } = parseExcel(testdata, existingCustomFields, importMap); + expect(customFields).toStrictEqual({ user0: { type: 'string', colour: 'red', @@ -1075,9 +1083,9 @@ describe('parseExcel()', () => { label: 'user9', }, }); - expect(parsedData.rundown.length).toBe(2); - expect(parsedData.rundown[0]).toMatchObject(expectedParsedRundown[0]); - expect(parsedData.rundown[1]).toMatchObject(expectedParsedRundown[1]); + expect(rundown.length).toBe(2); + expect(rundown[0]).toMatchObject(expectedParsedRundown[0]); + expect(rundown[1]).toMatchObject(expectedParsedRundown[1]); }); it('parses a file without custom fields', () => { diff --git a/apps/server/src/utils/parser.ts b/apps/server/src/utils/parser.ts index 4b293f1c4..b4eec3048 100644 --- a/apps/server/src/utils/parser.ts +++ b/apps/server/src/utils/parser.ts @@ -1,5 +1,6 @@ import { customFieldLabelToKey, + customKeyFromLabel, defaultImportMap, generateId, type ImportMap, @@ -60,7 +61,7 @@ export function getCustomFieldData( const customFields = {}; const customFieldImportKeys = {}; for (const ontimeLabel in importMap.custom) { - const ontimeKey = customFieldLabelToKey(ontimeLabel); + const ontimeKey = customKeyFromLabel(ontimeLabel, existingCustomFields) ?? customFieldLabelToKey(ontimeLabel); const importLabel = importMap.custom[ontimeLabel].toLowerCase(); const colour = ontimeKey in existingCustomFields ? existingCustomFields[ontimeKey].colour : ''; customFields[ontimeKey] = { @@ -198,9 +199,9 @@ export const parseExcel = ( entryIdIndex = col; rundownMetadata['id'] = { row, col }; }, - custom: (row: number, col: number, columnText: string) => { + custom: (row: number, col: number, columnText: string, ontimeKey: string) => { customFieldIndexes[col] = columnText; - rundownMetadata[`custom:${columnText}`] = { row, col }; + rundownMetadata[`custom:${ontimeKey}`] = { row, col }; }, } as const; @@ -266,12 +267,13 @@ export const parseExcel = ( // check if it is an ontime column if (handlers[columnText]) { - handlers[columnText](rowIndex, j, undefined); + handlers[columnText](rowIndex, j, undefined, undefined); } // check if it is a custom field if (columnText in customFieldImportKeys) { - handlers.custom(rowIndex, j, columnText); + const ontimeKey = customFieldImportKeys[columnText]; + handlers.custom(rowIndex, j, columnText, ontimeKey); } // else. we don't know how to handle this column diff --git a/packages/utils/index.ts b/packages/utils/index.ts index 23681c87f..06ec95a5d 100644 --- a/packages/utils/index.ts +++ b/packages/utils/index.ts @@ -58,7 +58,7 @@ export { isAlphanumeric, isAlphanumericWithSpace } from './src/regex-utils/isAlp export { isColourHex } from './src/regex-utils/isColourHex.js'; export { splitWhitespace } from './src/regex-utils/splitWhitespace.js'; -export { customFieldLabelToKey } from './src/customField-utils/customFieldLabelToKey.js'; +export { customFieldLabelToKey, customKeyFromLabel } from './src/customField-utils/customFieldLabelToKey.js'; // helpers from externals export { deepmerge } from './src/externals/deepmerge.js'; diff --git a/packages/utils/src/customField-utils/customFieldLabelToKey.ts b/packages/utils/src/customField-utils/customFieldLabelToKey.ts index 63aab28cd..91fc57d97 100644 --- a/packages/utils/src/customField-utils/customFieldLabelToKey.ts +++ b/packages/utils/src/customField-utils/customFieldLabelToKey.ts @@ -1,3 +1,5 @@ +import type { CustomFields } from 'ontime-types'; + import { isAlphanumericWithSpace } from '../regex-utils/isAlphanumeric.js'; /** @@ -9,3 +11,11 @@ export const customFieldLabelToKey = (label: string): string | null => { } return null; }; + +export const customKeyFromLabel = (label: string, fields: CustomFields): string | null => { + const maybeMatchingKey = Object.keys(fields).find((key) => fields[key].label === label); + if (maybeMatchingKey) { + return maybeMatchingKey; + } + return null; +};