mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-13 19:33:46 +00:00
Alpha 5 (#1741)
* refactor: align header columns * refactor: improve scrollbar visibility * refactor: center align table elements * refactor: make param elements stateful * fix: issue with collapsed elements not loosing value * fix: prevent search params containing multiple alias references * fix: the issue where a file disappears if it is both migrated and recovered in the same load operation (#1744) * refactor: disable group action for elements in groups * refactor: move context menu items into the event element (#1747) * feat: sheet import new features for v4 (#1730) * import milestone * fixup! import milestone * test: milestone import * add entries to group stop on new group or on group-end type * fixup! add entries to group * cleanup * add event target duration * link start if undefined * add skip import type * extract some to the excel paresing functions * tweaks to presentation * move file --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * fix: notify runtimeStore of events bieng groupd * fix: improve authentication and stage detection in demo * chore: ship logo with project * fix: client is referenced by name * fix: prevent reflow in event editor * fix: stale render on selected event due to ref mismatch * Create/Load/Delete multiple rundowns (#1696) * refactor: restore last loaded rundown * refactor: initialise rundown in ProjectService * feat: allow switching rundowns ensure on coordination between the db object and the working object server provide list of rundowns implement switch in the UI implement delete implement new rundown button * fix: render order for floating button * refactor: appropriate names to service * refactor: rundown endpoints * refactor: save last loaded rundown ID * refactor: rundown management UI * refactor: emit refetch all on project load --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * feat: recover single event subscription * fixup! feat: sheet import new features for v4 (#1730) * fix: prevent dropping a group inside another * fixup! refactor: move context menu items into the event element (#1747) * fix: prevent stale references to custom fields * fix: propagate updates to all rundowns * refactor: client rundown metadata (#1728) * generate metadata in the hook * move test * ensure there is always a last element * use for-loop * update metadata in useEfect * fully extract metadata generation * use direct assignment * cleanup --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * refactor: small imporvement and tests for coerce functions (#1752) * refactor: small imporvement and tests for coerce functions add test `coerceString` add test `coerceBoolean` add test `coerceColour` * remove old todo * fix: consistent quick add behaviour * refactor: create flat rundown with metadata * fix: show add buttons on top * feat: allow editing milestones * refactor: style tweaks to rundown elements refactor: milestones are full width refactor: cuesheet header alignment fix: editor styling in cuesheet * refactor: virtualise table * refactor: improve overscan (#1758) * bump version to 4.0.0-alpha.5 --------- Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import { CustomFieldKey, CustomFields, MaybeNumber } from 'ontime-types';
|
||||
import { checkRegex, customFieldLabelToKey, ImportMap } from 'ontime-utils';
|
||||
|
||||
/**
|
||||
* Receives an import map which contains custom field labels and a custom fields object
|
||||
* the result importkeys is an inverted record of <importKey, ontimeKey>
|
||||
* We need this function since, when importing from sheets, the user gives us custom field labels, not keys
|
||||
* @returns the new custom fields, and a map of excel column names to ontime keys
|
||||
* @private exported for testing
|
||||
*/
|
||||
export function getCustomFieldData(
|
||||
importMap: ImportMap,
|
||||
existingCustomFields: CustomFields,
|
||||
): {
|
||||
mergedCustomFields: CustomFields;
|
||||
customFieldImportKeys: Record<keyof CustomFields, string>;
|
||||
} {
|
||||
const mergedCustomFields: CustomFields = {};
|
||||
/**
|
||||
* A map of import keys to ontime keys
|
||||
* Map<excel column name, ontime key>
|
||||
*/
|
||||
const customFieldImportKeys: Record<string, CustomFieldKey> = {};
|
||||
|
||||
for (const ontimeLabel in importMap.custom) {
|
||||
// if the label is not valid, we skip the import
|
||||
if (!checkRegex.isAlphanumericWithSpace(ontimeLabel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// generate a key for the custom field
|
||||
const keyInCustomFields = customFieldLabelToKey(ontimeLabel);
|
||||
// we lower case the excel key to make it easier to match
|
||||
const columnNameInExcel = importMap.custom[ontimeLabel].toLowerCase();
|
||||
const maybeExistingColour = existingCustomFields[keyInCustomFields]?.colour ?? '';
|
||||
|
||||
// 1. add the custom field to the merged custom fields
|
||||
mergedCustomFields[keyInCustomFields] = {
|
||||
type: 'text', // we currently only support text custom fields
|
||||
colour: maybeExistingColour,
|
||||
label: ontimeLabel,
|
||||
};
|
||||
|
||||
// 2. add the column to the import keys
|
||||
customFieldImportKeys[columnNameInExcel] = keyInCustomFields;
|
||||
}
|
||||
return { mergedCustomFields, customFieldImportKeys };
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function infers a boolean from a string value
|
||||
*/
|
||||
export function parseBooleanString(value: unknown): boolean {
|
||||
if (typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
|
||||
// falsy values would be nullish or empty string
|
||||
if (!value || typeof value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
return value.toLowerCase() !== 'false';
|
||||
}
|
||||
|
||||
type IndexMap = Record<keyof Omit<ImportMap, 'worksheet' | 'custom'>, MaybeNumber> &
|
||||
Record<keyof Pick<ImportMap, 'custom'>, Record<number, string>>;
|
||||
|
||||
export type SheetMetadata = Partial<
|
||||
Record<keyof Omit<ImportMap, 'worksheet' | 'custom'>, { row: number; col: number }> &
|
||||
Record<string, { row: number; col: number }>
|
||||
>;
|
||||
|
||||
export function generateImportHandlers(importMap: ImportMap) {
|
||||
const indexMap: IndexMap = {
|
||||
title: null,
|
||||
cue: null,
|
||||
note: null,
|
||||
colour: null,
|
||||
flag: null,
|
||||
skip: null,
|
||||
countToEnd: null,
|
||||
linkStart: null,
|
||||
timeStart: null,
|
||||
timeEnd: null,
|
||||
duration: null,
|
||||
timeWarning: null,
|
||||
timeDanger: null,
|
||||
endAction: null,
|
||||
timerType: null,
|
||||
entryId: null,
|
||||
custom: {},
|
||||
};
|
||||
|
||||
const sheetMetadata: SheetMetadata = {};
|
||||
|
||||
const handlers = {
|
||||
[importMap.timeStart]: (row: number, col: number) => {
|
||||
indexMap.timeStart = col;
|
||||
sheetMetadata.timeStart = { row, col };
|
||||
},
|
||||
[importMap.linkStart]: (row: number, col: number) => {
|
||||
indexMap.linkStart = col;
|
||||
sheetMetadata.linkStart = { row, col };
|
||||
},
|
||||
[importMap.timeEnd]: (row: number, col: number) => {
|
||||
indexMap.timeEnd = col;
|
||||
sheetMetadata.timeEnd = { row, col };
|
||||
},
|
||||
[importMap.duration]: (row: number, col: number) => {
|
||||
indexMap.duration = col;
|
||||
sheetMetadata.duration = { row, col };
|
||||
},
|
||||
|
||||
[importMap.cue]: (row: number, col: number) => {
|
||||
indexMap.cue = col;
|
||||
sheetMetadata.cue = { row, col };
|
||||
},
|
||||
[importMap.title]: (row: number, col: number) => {
|
||||
indexMap.title = col;
|
||||
sheetMetadata.title = { row, col };
|
||||
},
|
||||
[importMap.flag]: (row: number, col: number) => {
|
||||
indexMap.flag = col;
|
||||
sheetMetadata.flag = { row, col };
|
||||
},
|
||||
[importMap.countToEnd]: (row: number, col: number) => {
|
||||
indexMap.countToEnd = col;
|
||||
sheetMetadata.countToEnd = { row, col };
|
||||
},
|
||||
[importMap.skip]: (row: number, col: number) => {
|
||||
indexMap.skip = col;
|
||||
sheetMetadata.skip = { row, col };
|
||||
},
|
||||
[importMap.note]: (row: number, col: number) => {
|
||||
indexMap.note = col;
|
||||
sheetMetadata.note = { row, col };
|
||||
},
|
||||
[importMap.colour]: (row: number, col: number) => {
|
||||
indexMap.colour = col;
|
||||
sheetMetadata.colour = { row, col };
|
||||
},
|
||||
[importMap.endAction]: (row: number, col: number) => {
|
||||
indexMap.endAction = col;
|
||||
sheetMetadata.endAction = { row, col };
|
||||
},
|
||||
[importMap.timerType]: (row: number, col: number) => {
|
||||
indexMap.timerType = col;
|
||||
sheetMetadata.timerType = { row, col };
|
||||
},
|
||||
[importMap.timeWarning]: (row: number, col: number) => {
|
||||
indexMap.timeWarning = col;
|
||||
sheetMetadata.timeWarning = { row, col };
|
||||
},
|
||||
[importMap.timeDanger]: (row: number, col: number) => {
|
||||
indexMap.timeDanger = col;
|
||||
sheetMetadata.timeDanger = { row, col };
|
||||
},
|
||||
[importMap.entryId]: (row: number, col: number) => {
|
||||
indexMap.entryId = col;
|
||||
sheetMetadata['id'] = { row, col }; // important this will be used in a normal context where the id is not called entryId
|
||||
},
|
||||
custom: (row: number, col: number, columnText: string, ontimeKey: string) => {
|
||||
indexMap.custom[col] = columnText;
|
||||
sheetMetadata[`custom:${ontimeKey}`] = { row, col };
|
||||
},
|
||||
};
|
||||
|
||||
return { handlers, indexMap, sheetMetadata };
|
||||
}
|
||||
Reference in New Issue
Block a user