diff --git a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/ImportReview.tsx b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/ImportReview.tsx
index 73e0d49f7..9ebccff4f 100644
--- a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/ImportReview.tsx
+++ b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/ImportReview.tsx
@@ -1,5 +1,6 @@
import { useState } from 'react';
import { CustomFields, Rundown } from 'ontime-types';
+import { getFirstEventNormal, getLastEventNormal, millisToString } from 'ontime-utils';
import Button from '../../../../../common/components/buttons/Button';
import useRundown from '../../../../../common/hooks-query/useRundown';
@@ -43,6 +44,9 @@ export default function ImportReview(props: ImportReviewProps) {
onFinished();
};
+ const { firstEvent } = getFirstEventNormal(rundown.entries, rundown.flatOrder);
+ const { lastEvent } = getLastEventNormal(rundown.entries, rundown.flatOrder);
+
return (
@@ -56,6 +60,24 @@ export default function ImportReview(props: ImportReviewProps) {
+
+
+ Title {rundown.title}
+
+
+ Number of entries {rundown.flatOrder.length}
+
+ {firstEvent && (
+
+ Start Time {millisToString(firstEvent.timeStart)}
+
+ )}
+ {lastEvent && (
+
+ End Time {millisToString(lastEvent.timeEnd)}
+
+ )}
+
);
diff --git a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/import-map/ImportMapForm.tsx b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/import-map/ImportMapForm.tsx
index d1d354006..30968d7d0 100644
--- a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/import-map/ImportMapForm.tsx
+++ b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/import-map/ImportMapForm.tsx
@@ -5,6 +5,7 @@ import { checkRegex, ImportMap } from 'ontime-utils';
import Button from '../../../../../../common/components/buttons/Button';
import IconButton from '../../../../../../common/components/buttons/IconButton';
+import Info from '../../../../../../common/components/info/Info';
import Input from '../../../../../../common/components/input/input/Input';
import Select from '../../../../../../common/components/select/Select';
import Tooltip from '../../../../../../common/components/tooltip/Tooltip';
@@ -136,6 +137,10 @@ export default function ImportMapForm({
+
+ Match your spreadsheet columns to Ontime fields.
+ You can also add Custom Fields by providing a name for Ontime and the spreadsheet column name.
+
diff --git a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/preview/PreviewRundown.tsx b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/preview/PreviewRundown.tsx
index dd9251c8f..b6a96c4fb 100644
--- a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/preview/PreviewRundown.tsx
+++ b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/preview/PreviewRundown.tsx
@@ -18,9 +18,7 @@ function booleanToText(value?: boolean) {
return value ? 'Yes' : undefined;
}
-export default function PreviewRundown(props: PreviewRundownProps) {
- const { rundown, customFields } = props;
-
+export default function PreviewRundown({ rundown, customFields }: PreviewRundownProps) {
// we only count Ontime Events which are 1 based in client
let eventIndex = 0;
@@ -59,9 +57,7 @@ export default function PreviewRundown(props: PreviewRundownProps) {
const colour = entry.colour ? getAccessibleColour(entry.colour) : {};
return (
- |
- -
- |
+ | {/** Index */}
{entry.type}
|
diff --git a/apps/server/src/api-data/excel/__mocks__/simpleTemplate.ts b/apps/server/src/api-data/excel/__mocks__/simpleTemplate.ts
new file mode 100644
index 000000000..fcd7e6239
--- /dev/null
+++ b/apps/server/src/api-data/excel/__mocks__/simpleTemplate.ts
@@ -0,0 +1,124 @@
+export const simpleTemplate = [
+ ['ⓘ Notes on import', '', '', '', '', '', 'ⓘ How to use'],
+ [
+ 'Ontime will import this spreasheet as a rundown in your project',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '1. Make your own copy of the spreadsheet by either File -> Make a copy or File -> Download -> Microsoft Excel',
+ ],
+ [
+ '- Each spreadsheet can only contain one rundown',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '2. Delete the table header with the Notes on import and How to use instructions',
+ ],
+ [
+ '- You can have as many columns as necessary, Ontime only imports the columns you request',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '3. Remove any columns that are not necessary to your workflow',
+ ],
+ [
+ '- The names of the worksheet and columns are given in Ontime on import',
+ '',
+ '',
+ '',
+ '',
+ '',
+ 'See documentation for spreadsheet import',
+ '',
+ 'https://docs.getontime.no/features/import-spreadsheet/',
+ ],
+ [
+ '- Ontime creates an entry for every row on the table with a known Timer Type (see note on column header)',
+ '',
+ '',
+ '',
+ '',
+ '',
+ 'See documentation for Google Sheet import',
+ '',
+ 'https://docs.getontime.no/features/import-spreadsheet-gsheet/',
+ ],
+ ['- All fields in a row are optional, Ontime will fill in with default data as needed'],
+ ['ⓘ Hover over note tags to see additional help on column data'],
+ [
+ '',
+ '',
+ '',
+ 'Note ---------------------------------------------',
+ '',
+ '',
+ '',
+ 'Note',
+ 'Note --------------------------------------------------------',
+ ],
+ ['Cue', 'Title', 'Colour', 'Time Start', 'Time End', 'Duration', 'Note', 'Timer Type', 'Video Notes'],
+ [
+ 'Demo',
+ 'Clear all, or Create New Project to start fresh',
+ '#9d9d9d',
+ '',
+ '',
+ '',
+ 'Moderator - Emma Thompson\n' +
+ '\n' +
+ 'Speakers\n' +
+ '- Liam Carter + Sophia Patel\n' +
+ '- Ethan Brooks\n' +
+ '- Lucas Bennett',
+ 'milestone',
+ ],
+ ['', 'Morning Sessions', '#339E4E', '', '', '', '', 'group-start'],
+ [
+ '1',
+ 'Pre-show Countdown',
+ '#77C785',
+ '10:00:00',
+ '11:00:00',
+ '',
+ 'Music plays, holding slide on screens',
+ 'count-down',
+ 'Camera + PowerPoint on stream\nPowerPoint on screens',
+ ],
+ ['Standby', '10:45 - Presenters ready side stage', '#A790F5', '', '', '', '', 'milestone'],
+ ['1.1', 'Welcome', '#FFCC78', '', '', '00:10:00', '', 'count-down', 'Cameras on stream\nPowerPoint on screens'],
+ [
+ '1.2',
+ 'Session 1',
+ '#77C785',
+ '',
+ '',
+ '00:50:00',
+ '',
+ 'count-down',
+ 'Camera + PowerPoint on stream\nPowerPoint on screens',
+ ],
+ ['House', '11:30 - House staff setup lunch in lobby', '#A790F5', '', '', '', '', 'milestone'],
+ ['', 'Lunch', '#3E75E8', '', '', '', '', 'group-start'],
+ ['2.1', 'Lunch / Countdown to next session', '#779BE7', '12:00:00', '13:00:00', '', '', 'count-down'],
+ ['', 'Afternoon Sessions', '#339E4E', '', '', '', '', 'group-start'],
+ ['Standby', '12:45 - Presenters ready side stage', '#A790F5', '', '', '', '', 'milestone'],
+ [
+ '3.2',
+ 'Session 2',
+ '#77C785',
+ '13:00:00',
+ '',
+ '00:50:00',
+ '',
+ 'count-down',
+ 'Camera + PPT + Video on stream\n' + 'PowerPoint + Video on screens\n' + '\n' + 'Video file: Session2.mp4',
+ ],
+ ['3.2', 'Wrap up', '#FFCC78', '', '', '00:10:00', '', 'count-down', 'Holding slide on screens'],
+ ['Strike', '14:00 - AV & Room strike', '#A790F5', '', '', '', '', 'milestone'],
+];
diff --git a/apps/server/src/api-data/excel/__tests__/excel.parser.test.ts b/apps/server/src/api-data/excel/__tests__/excel.parser.test.ts
index ffcb90692..35251abcd 100644
--- a/apps/server/src/api-data/excel/__tests__/excel.parser.test.ts
+++ b/apps/server/src/api-data/excel/__tests__/excel.parser.test.ts
@@ -1,12 +1,34 @@
import { CustomFields, OntimeEvent, OntimeGroup, SupportedEntry, TimerType } from 'ontime-types';
-import { ImportMap, MILLIS_PER_MINUTE } from 'ontime-utils';
+import { ImportMap, MILLIS_PER_MINUTE, millisToString } from 'ontime-utils';
import { parseExcel } from '../excel.parser.js';
import { dataFromExcelTemplate } from './mockData.js';
+import { simpleTemplate } from '../__mocks__/simpleTemplate.js';
describe('parseExcel()', () => {
- it('parses the example file', () => {
+ it('parses the simple template file', () => {
+ const result = parseExcel(simpleTemplate, {});
+
+ expect(result.rundown.flatOrder.length).toBe(14);
+ expect(result.rundown.order.length).toBe(4);
+
+ const firstEvent = result.rundown.entries[result.rundown.flatOrder[2]];
+ expect(firstEvent).toMatchObject({
+ type: SupportedEntry.Event,
+ title: 'Pre-show Countdown',
+ });
+ expect(millisToString((firstEvent as OntimeEvent).timeStart)).toBe('10:00:00');
+
+ const lastEvent = result.rundown.entries[result.rundown.flatOrder[12]];
+ expect(lastEvent).toMatchObject({
+ type: SupportedEntry.Event,
+ title: 'Wrap up',
+ });
+ // the excel step does not relate elements yet
+ expect(millisToString((lastEvent as OntimeEvent).timeEnd)).toBe('00:00:00');
+ });
+ it('parses an import map with only custom fields', () => {
// partial import map with only custom fields
const importMap = {
custom: {
diff --git a/apps/server/src/api-data/excel/excel.parser.ts b/apps/server/src/api-data/excel/excel.parser.ts
index 5d367a081..e85d770e1 100644
--- a/apps/server/src/api-data/excel/excel.parser.ts
+++ b/apps/server/src/api-data/excel/excel.parser.ts
@@ -212,7 +212,7 @@ export const parseExcel = (
return;
}
- //and fall through to treat it as an event
+ // after group and milestones we only have events remaining
const event = {
...entry,
custom: { ...entryCustomFields },
@@ -223,6 +223,7 @@ export const parseExcel = (
event.timerType = TimerType.CountDown;
}
+ // we link all events unless user specifies otherwise
if (entry.linkStart === undefined) {
event.linkStart = true;
}