mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-16 21:03:29 +00:00
refactor: simplify ux for sheet import
This commit is contained in:
committed by
Carlos Valente
parent
9dfc8083f0
commit
becd734ea8
+22
@@ -1,5 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { CustomFields, Rundown } from 'ontime-types';
|
import { CustomFields, Rundown } from 'ontime-types';
|
||||||
|
import { getFirstEventNormal, getLastEventNormal, millisToString } from 'ontime-utils';
|
||||||
|
|
||||||
import Button from '../../../../../common/components/buttons/Button';
|
import Button from '../../../../../common/components/buttons/Button';
|
||||||
import useRundown from '../../../../../common/hooks-query/useRundown';
|
import useRundown from '../../../../../common/hooks-query/useRundown';
|
||||||
@@ -43,6 +44,9 @@ export default function ImportReview(props: ImportReviewProps) {
|
|||||||
onFinished();
|
onFinished();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { firstEvent } = getFirstEventNormal(rundown.entries, rundown.flatOrder);
|
||||||
|
const { lastEvent } = getLastEventNormal(rundown.entries, rundown.flatOrder);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel.Section>
|
<Panel.Section>
|
||||||
<Panel.Title>
|
<Panel.Title>
|
||||||
@@ -56,6 +60,24 @@ export default function ImportReview(props: ImportReviewProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Panel.InlineElements>
|
</Panel.InlineElements>
|
||||||
</Panel.Title>
|
</Panel.Title>
|
||||||
|
<Panel.ListGroup>
|
||||||
|
<Panel.ListItem>
|
||||||
|
<b>Title</b> {rundown.title}
|
||||||
|
</Panel.ListItem>
|
||||||
|
<Panel.ListItem>
|
||||||
|
<b>Number of entries</b> {rundown.flatOrder.length}
|
||||||
|
</Panel.ListItem>
|
||||||
|
{firstEvent && (
|
||||||
|
<Panel.ListItem>
|
||||||
|
<b>Start Time</b> {millisToString(firstEvent.timeStart)}
|
||||||
|
</Panel.ListItem>
|
||||||
|
)}
|
||||||
|
{lastEvent && (
|
||||||
|
<Panel.ListItem>
|
||||||
|
<b>End Time</b> {millisToString(lastEvent.timeEnd)}
|
||||||
|
</Panel.ListItem>
|
||||||
|
)}
|
||||||
|
</Panel.ListGroup>
|
||||||
<PreviewSpreadsheet rundown={rundown} customFields={customFields} />
|
<PreviewSpreadsheet rundown={rundown} customFields={customFields} />
|
||||||
</Panel.Section>
|
</Panel.Section>
|
||||||
);
|
);
|
||||||
|
|||||||
+5
@@ -5,6 +5,7 @@ import { checkRegex, ImportMap } from 'ontime-utils';
|
|||||||
|
|
||||||
import Button from '../../../../../../common/components/buttons/Button';
|
import Button from '../../../../../../common/components/buttons/Button';
|
||||||
import IconButton from '../../../../../../common/components/buttons/IconButton';
|
import IconButton from '../../../../../../common/components/buttons/IconButton';
|
||||||
|
import Info from '../../../../../../common/components/info/Info';
|
||||||
import Input from '../../../../../../common/components/input/input/Input';
|
import Input from '../../../../../../common/components/input/input/Input';
|
||||||
import Select from '../../../../../../common/components/select/Select';
|
import Select from '../../../../../../common/components/select/Select';
|
||||||
import Tooltip from '../../../../../../common/components/tooltip/Tooltip';
|
import Tooltip from '../../../../../../common/components/tooltip/Tooltip';
|
||||||
@@ -136,6 +137,10 @@ export default function ImportMapForm({
|
|||||||
</Button>
|
</Button>
|
||||||
</Panel.InlineElements>
|
</Panel.InlineElements>
|
||||||
</Panel.Title>
|
</Panel.Title>
|
||||||
|
<Info>
|
||||||
|
Match your spreadsheet columns to Ontime fields. <br />
|
||||||
|
You can also add Custom Fields by providing a name for Ontime and the spreadsheet column name.
|
||||||
|
</Info>
|
||||||
<Panel.Table>
|
<Panel.Table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
+2
-6
@@ -18,9 +18,7 @@ function booleanToText(value?: boolean) {
|
|||||||
return value ? 'Yes' : undefined;
|
return value ? 'Yes' : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PreviewRundown(props: PreviewRundownProps) {
|
export default function PreviewRundown({ rundown, customFields }: PreviewRundownProps) {
|
||||||
const { rundown, customFields } = props;
|
|
||||||
|
|
||||||
// we only count Ontime Events which are 1 based in client
|
// we only count Ontime Events which are 1 based in client
|
||||||
let eventIndex = 0;
|
let eventIndex = 0;
|
||||||
|
|
||||||
@@ -59,9 +57,7 @@ export default function PreviewRundown(props: PreviewRundownProps) {
|
|||||||
const colour = entry.colour ? getAccessibleColour(entry.colour) : {};
|
const colour = entry.colour ? getAccessibleColour(entry.colour) : {};
|
||||||
return (
|
return (
|
||||||
<tr key={entry.id}>
|
<tr key={entry.id}>
|
||||||
<td className={style.center}>
|
<td /> {/** Index */}
|
||||||
<Tag>-</Tag>
|
|
||||||
</td>
|
|
||||||
<td className={style.center}>
|
<td className={style.center}>
|
||||||
<Tag>{entry.type}</Tag>
|
<Tag>{entry.type}</Tag>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -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'],
|
||||||
|
];
|
||||||
@@ -1,12 +1,34 @@
|
|||||||
import { CustomFields, OntimeEvent, OntimeGroup, SupportedEntry, TimerType } from 'ontime-types';
|
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 { parseExcel } from '../excel.parser.js';
|
||||||
|
|
||||||
import { dataFromExcelTemplate } from './mockData.js';
|
import { dataFromExcelTemplate } from './mockData.js';
|
||||||
|
import { simpleTemplate } from '../__mocks__/simpleTemplate.js';
|
||||||
|
|
||||||
describe('parseExcel()', () => {
|
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
|
// partial import map with only custom fields
|
||||||
const importMap = {
|
const importMap = {
|
||||||
custom: {
|
custom: {
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ export const parseExcel = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//and fall through to treat it as an event
|
// after group and milestones we only have events remaining
|
||||||
const event = {
|
const event = {
|
||||||
...entry,
|
...entry,
|
||||||
custom: { ...entryCustomFields },
|
custom: { ...entryCustomFields },
|
||||||
@@ -223,6 +223,7 @@ export const parseExcel = (
|
|||||||
event.timerType = TimerType.CountDown;
|
event.timerType = TimerType.CountDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we link all events unless user specifies otherwise
|
||||||
if (entry.linkStart === undefined) {
|
if (entry.linkStart === undefined) {
|
||||||
event.linkStart = true;
|
event.linkStart = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user