mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-18 13:44:12 +00:00
feat: added export options (#529)
* feat: added export options * chore: eslint console proposal --------- Co-authored-by: arc-alex <ac@omnivox.dk>
This commit is contained in:
@@ -21,6 +21,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-console": "warn"
|
"no-console": ["warn", { "allow": ["warn", "error"]}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import { Alias, OSCSettings, OscSubscription, ProjectData, Settings, UserFields,
|
|||||||
|
|
||||||
import { apiRepoLatest } from '../../externals';
|
import { apiRepoLatest } from '../../externals';
|
||||||
import { InfoType } from '../models/Info';
|
import { InfoType } from '../models/Info';
|
||||||
|
import fileDownload from '../utils/fileDownload';
|
||||||
|
|
||||||
import { ontimeURL } from './apiConstants';
|
import { ontimeURL } from './apiConstants';
|
||||||
|
|
||||||
@@ -109,32 +110,17 @@ export async function postOscSubscriptions(data: OscSubscription) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description HTTP request to download db
|
* @description HTTP request to download db in CSV format
|
||||||
* @return {Promise}
|
|
||||||
*/
|
*/
|
||||||
export const downloadRundown = async () => {
|
export const downloadCSV = () => {
|
||||||
await axios({
|
return fileDownload(ontimeURL, { name: 'rundown', type: 'csv' }, { type: 'text/csv;charset=utf-8;' });
|
||||||
url: `${ontimeURL}/db`,
|
};
|
||||||
method: 'GET',
|
|
||||||
responseType: 'blob', // important
|
|
||||||
}).then((response) => {
|
|
||||||
const headerLine = response.headers['Content-Disposition'];
|
|
||||||
let filename = 'rundown.json';
|
|
||||||
|
|
||||||
// try and get the filename from the response
|
/**
|
||||||
if (headerLine != null) {
|
* @description HTTP request to download db in JSON format
|
||||||
const startFileNameIndex = headerLine.indexOf('"') + 1;
|
*/
|
||||||
const endFileNameIndex = headerLine.lastIndexOf('"');
|
export const downloadRundown = () => {
|
||||||
filename = headerLine.substring(startFileNameIndex, endFileNameIndex);
|
return fileDownload(ontimeURL, { name: 'rundown', type: 'json' }, { type: 'application/json;charset=utf-8;' });
|
||||||
}
|
|
||||||
|
|
||||||
const url = window.URL.createObjectURL(new Blob([response.data], { type: 'application/json' }));
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.setAttribute('download', filename);
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { makeCSV, makeTable } from '../../features/cuesheet/cuesheetUtils';
|
||||||
|
|
||||||
|
type FileOptions = {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type BlobOptions = {
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function fileDownload(url: string, fileOptions: FileOptions, blobOptions: BlobOptions) {
|
||||||
|
const response = await axios({
|
||||||
|
url: `${url}/db`,
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
|
||||||
|
const headerLine = response.headers['Content-Disposition'];
|
||||||
|
let { name: fileName } = fileOptions;
|
||||||
|
const { type: fileType } = fileOptions;
|
||||||
|
const { project, rundown, userFields } = response.data;
|
||||||
|
|
||||||
|
// try and get the filename from the response
|
||||||
|
if (headerLine != null) {
|
||||||
|
const startFileNameIndex = headerLine.indexOf('"') + 1;
|
||||||
|
const endFileNameIndex = headerLine.lastIndexOf('"');
|
||||||
|
fileName = headerLine.substring(startFileNameIndex, endFileNameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileContent = '';
|
||||||
|
|
||||||
|
if (fileType === 'json') {
|
||||||
|
fileContent = JSON.stringify(response.data);
|
||||||
|
fileName += '.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileType === 'csv') {
|
||||||
|
const sheetData = makeTable(project, rundown, userFields);
|
||||||
|
fileContent = makeCSV(sheetData);
|
||||||
|
fileName += '.csv';
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([fileContent], { type: blobOptions.type });
|
||||||
|
const downloadUrl = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.setAttribute('href', downloadUrl);
|
||||||
|
link.setAttribute('download', fileName);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
// Clean up the URL.createObjectURL to release resources
|
||||||
|
URL.revokeObjectURL(downloadUrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -21,4 +21,4 @@
|
|||||||
border: 1px solid $white-10;
|
border: 1px solid $white-10;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { OntimeRundownEntry, ProjectData } from 'ontime-types';
|
import { OntimeRundownEntry, ProjectData } from 'ontime-types';
|
||||||
|
|
||||||
import Empty from '../../common/components/state/Empty';
|
import Empty from '../../common/components/state/Empty';
|
||||||
@@ -6,6 +6,7 @@ import { useEventAction } from '../../common/hooks/useEventAction';
|
|||||||
import { useCuesheet } from '../../common/hooks/useSocket';
|
import { useCuesheet } from '../../common/hooks/useSocket';
|
||||||
import useRundown from '../../common/hooks-query/useRundown';
|
import useRundown from '../../common/hooks-query/useRundown';
|
||||||
import useUserFields from '../../common/hooks-query/useUserFields';
|
import useUserFields from '../../common/hooks-query/useUserFields';
|
||||||
|
import ExportModal, { ExportType } from '../modals/export-modal/ExportModal';
|
||||||
|
|
||||||
import CuesheetTableHeader from './cuesheet-table-header/CuesheetTableHeader';
|
import CuesheetTableHeader from './cuesheet-table-header/CuesheetTableHeader';
|
||||||
import Cuesheet from './Cuesheet';
|
import Cuesheet from './Cuesheet';
|
||||||
@@ -20,6 +21,8 @@ export default function CuesheetWrapper() {
|
|||||||
const { updateEvent } = useEventAction();
|
const { updateEvent } = useEventAction();
|
||||||
const featureData = useCuesheet();
|
const featureData = useCuesheet();
|
||||||
const columns = useMemo(() => makeCuesheetColumns(userFields), [userFields]);
|
const columns = useMemo(() => makeCuesheetColumns(userFields), [userFields]);
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [headerData, setheaderData] = useState<ProjectData | null>(null);
|
||||||
|
|
||||||
// Set window title
|
// Set window title
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -69,37 +72,80 @@ export default function CuesheetWrapper() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const exportHandler = useCallback(
|
const exportHandler = useCallback(
|
||||||
(headerData: ProjectData) => {
|
(headerData: ProjectData, exportType: ExportType) => {
|
||||||
if (!headerData || !rundown || !userFields) {
|
if (!headerData || !rundown || !userFields) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sheetData = makeTable(headerData, rundown, userFields);
|
let fileName = '';
|
||||||
const csvContent = makeCSV(sheetData);
|
let url = '';
|
||||||
|
|
||||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
if (exportType === 'json') {
|
||||||
const url = URL.createObjectURL(blob);
|
const jsonContent = JSON.stringify({
|
||||||
|
headerData,
|
||||||
|
rundown,
|
||||||
|
userFields,
|
||||||
|
});
|
||||||
|
|
||||||
|
fileName = 'ontime export.json';
|
||||||
|
|
||||||
|
const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' });
|
||||||
|
url = URL.createObjectURL(blob);
|
||||||
|
} else if (exportType === 'csv') {
|
||||||
|
const sheetData = makeTable(headerData, rundown, userFields);
|
||||||
|
const csvContent = makeCSV(sheetData);
|
||||||
|
|
||||||
|
fileName = 'ontime export.csv';
|
||||||
|
|
||||||
|
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||||
|
url = URL.createObjectURL(blob);
|
||||||
|
} else {
|
||||||
|
console.error('Invalid export type: ', exportType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.setAttribute('href', url);
|
link.setAttribute('href', url);
|
||||||
link.setAttribute('download', 'ontime export.csv');
|
link.setAttribute('download', fileName);
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
|
|
||||||
// Clean up the URL.createObjectURL to release resources
|
// Clean up the URL.createObjectURL to release resources
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
|
return;
|
||||||
},
|
},
|
||||||
[rundown, userFields],
|
[rundown, userFields],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onModalClose = (exportType?: ExportType) => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
|
||||||
|
if (!exportType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerData) {
|
||||||
|
exportHandler(headerData, exportType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOpenModal = (projectData: ProjectData) => {
|
||||||
|
setheaderData(projectData);
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
if (!rundown || !userFields) {
|
if (!rundown || !userFields) {
|
||||||
return <Empty text='Loading...' />;
|
return <Empty text='Loading...' />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.tableWrapper} data-testid='cuesheet'>
|
<div className={styles.tableWrapper} data-testid='cuesheet'>
|
||||||
<CuesheetTableHeader handleCSVExport={exportHandler} featureData={featureData} />
|
<CuesheetTableHeader handleExport={handleOpenModal} featureData={featureData} />
|
||||||
<Cuesheet data={rundown} columns={columns} handleUpdate={handleUpdate} selectedId={featureData.selectedEventId} />
|
<Cuesheet data={rundown} columns={columns} handleUpdate={handleUpdate} selectedId={featureData.selectedEventId} />
|
||||||
|
<ExportModal
|
||||||
|
isOpen={isModalOpen}
|
||||||
|
onClose={onModalClose}
|
||||||
|
buttonVariants={{ csv: 'ontime-filled', json: 'ontime-ghosted' }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import CuesheetTableHeaderTimers from './CuesheetTableHeaderTimers';
|
|||||||
import style from './CuesheetTableHeader.module.scss';
|
import style from './CuesheetTableHeader.module.scss';
|
||||||
|
|
||||||
interface CuesheetTableHeaderProps {
|
interface CuesheetTableHeaderProps {
|
||||||
handleCSVExport: (headerData: ProjectData) => void;
|
handleExport: (headerData: ProjectData) => void;
|
||||||
featureData: {
|
featureData: {
|
||||||
playback: Playback;
|
playback: Playback;
|
||||||
selectedEventIndex: number | null;
|
selectedEventIndex: number | null;
|
||||||
@@ -25,7 +25,7 @@ interface CuesheetTableHeaderProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CuesheetTableHeader({ handleCSVExport, featureData }: CuesheetTableHeaderProps) {
|
export default function CuesheetTableHeader({ handleExport, featureData }: CuesheetTableHeaderProps) {
|
||||||
const followSelected = useCuesheetSettings((state) => state.followSelected);
|
const followSelected = useCuesheetSettings((state) => state.followSelected);
|
||||||
const showSettings = useCuesheetSettings((state) => state.showSettings);
|
const showSettings = useCuesheetSettings((state) => state.showSettings);
|
||||||
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
|
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
|
||||||
@@ -33,9 +33,9 @@ export default function CuesheetTableHeader({ handleCSVExport, featureData }: Cu
|
|||||||
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
||||||
const { data: project } = useProjectData();
|
const { data: project } = useProjectData();
|
||||||
|
|
||||||
const exportCsv = () => {
|
const exportProject = () => {
|
||||||
if (project) {
|
if (project) {
|
||||||
handleCSVExport(project);
|
handleExport(project);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,9 +72,9 @@ export default function CuesheetTableHeader({ handleCSVExport, featureData }: Cu
|
|||||||
{isFullScreen ? <IoContract /> : <IoExpand />}
|
{isFullScreen ? <IoContract /> : <IoExpand />}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip openDelay={tooltipDelayFast} label='Export rundown to CSV'>
|
<Tooltip openDelay={tooltipDelayFast} label='Export rundown'>
|
||||||
<span className={style.actionIcon} onClick={exportCsv}>
|
<span className={style.actionIcon} onClick={exportProject}>
|
||||||
CSV
|
Export
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { memo, useCallback, useEffect } from 'react';
|
import { memo, useCallback, useEffect, useState } from 'react';
|
||||||
import { VStack } from '@chakra-ui/react';
|
import { VStack } from '@chakra-ui/react';
|
||||||
import { IoColorWand } from '@react-icons/all-files/io5/IoColorWand';
|
import { IoColorWand } from '@react-icons/all-files/io5/IoColorWand';
|
||||||
import { IoExtensionPuzzle } from '@react-icons/all-files/io5/IoExtensionPuzzle';
|
import { IoExtensionPuzzle } from '@react-icons/all-files/io5/IoExtensionPuzzle';
|
||||||
@@ -10,11 +10,12 @@ import { IoPushOutline } from '@react-icons/all-files/io5/IoPushOutline';
|
|||||||
import { IoSaveOutline } from '@react-icons/all-files/io5/IoSaveOutline';
|
import { IoSaveOutline } from '@react-icons/all-files/io5/IoSaveOutline';
|
||||||
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
||||||
|
|
||||||
import { downloadRundown } from '../../common/api/ontimeApi';
|
import { downloadCSV, downloadRundown } from '../../common/api/ontimeApi';
|
||||||
import QuitIconBtn from '../../common/components/buttons/QuitIconBtn';
|
import QuitIconBtn from '../../common/components/buttons/QuitIconBtn';
|
||||||
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
||||||
import useElectronEvent from '../../common/hooks/useElectronEvent';
|
import useElectronEvent from '../../common/hooks/useElectronEvent';
|
||||||
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
|
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
|
||||||
|
import ExportModal, { ExportType } from '../modals/export-modal/ExportModal';
|
||||||
|
|
||||||
import style from './MenuBar.module.scss';
|
import style from './MenuBar.module.scss';
|
||||||
|
|
||||||
@@ -100,6 +101,22 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
};
|
};
|
||||||
}, [handleKeyPress, isElectron]);
|
}, [handleKeyPress, isElectron]);
|
||||||
|
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const onModalClose = (exportType?: ExportType) => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
|
||||||
|
if (!exportType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exportType === 'json') {
|
||||||
|
downloadRundown();
|
||||||
|
} else if (exportType === 'csv') {
|
||||||
|
downloadCSV();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack>
|
<VStack>
|
||||||
<QuitIconBtn disabled={!isElectron} clickHandler={sendShutdown} size='md' />
|
<QuitIconBtn disabled={!isElectron} clickHandler={sendShutdown} size='md' />
|
||||||
@@ -128,12 +145,18 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
icon={<IoSaveOutline />}
|
icon={<IoSaveOutline />}
|
||||||
isDisabled={appMode === AppMode.Run}
|
isDisabled={appMode === AppMode.Run}
|
||||||
clickHandler={downloadRundown}
|
clickHandler={() => setIsModalOpen(true)}
|
||||||
tooltip='Export project file'
|
tooltip='Export project file'
|
||||||
aria-label='Export project file'
|
aria-label='Export project file'
|
||||||
size='sm'
|
size='sm'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ExportModal
|
||||||
|
onClose={onModalClose}
|
||||||
|
isOpen={isModalOpen}
|
||||||
|
buttonVariants={{ csv: 'ontime-subtle-on-light', json: 'ontime-filled' }}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className={style.gap} />
|
<div className={style.gap} />
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
.modalHeader {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalBody {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Button, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import styles from './ExportModal.module.scss';
|
||||||
|
|
||||||
|
export type ExportType = 'csv' | 'json';
|
||||||
|
interface ExportModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: (type?: ExportType) => void;
|
||||||
|
buttonVariants: {
|
||||||
|
csv: string;
|
||||||
|
json: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ExportModal(props: ExportModalProps) {
|
||||||
|
const { isOpen, onClose, buttonVariants } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal isOpen={isOpen} onClose={onClose} motionPreset='scale' size='xl' colorScheme='blackAlpha'>
|
||||||
|
<ModalOverlay />
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader className={styles.modalHeader}>Download options</ModalHeader>
|
||||||
|
<ModalCloseButton />
|
||||||
|
<ModalBody className={styles.modalBody}>
|
||||||
|
<Button onClick={() => onClose('csv')} variant={buttonVariants.csv} width='48%'>
|
||||||
|
rundown as CSV
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => onClose('json')} variant={buttonVariants.json} width='48%'>
|
||||||
|
Project file
|
||||||
|
</Button>
|
||||||
|
</ModalBody>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
+15
-22
@@ -1,16 +1,20 @@
|
|||||||
{
|
{
|
||||||
"rundown": [
|
"rundown": [
|
||||||
{
|
{
|
||||||
"title": "First test event",
|
"type": "block",
|
||||||
|
"id": "18797"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "title 1",
|
||||||
"subtitle": "",
|
"subtitle": "",
|
||||||
"presenter": "",
|
"presenter": "",
|
||||||
"note": "",
|
"note": "",
|
||||||
"endAction": "none",
|
"endAction": "none",
|
||||||
"timerType": "count-down",
|
"timerType": "count-down",
|
||||||
"timeStart": 32400000,
|
"timeStart": 60000,
|
||||||
"timeEnd": 36000000,
|
"timeEnd": 120000,
|
||||||
"duration": 3600000,
|
"duration": 60000,
|
||||||
"isPublic": true,
|
"isPublic": false,
|
||||||
"skip": false,
|
"skip": false,
|
||||||
"colour": "",
|
"colour": "",
|
||||||
"user0": "",
|
"user0": "",
|
||||||
@@ -29,22 +33,16 @@
|
|||||||
"cue": "1"
|
"cue": "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"duration": 600000,
|
"title": "title 2",
|
||||||
"type": "delay",
|
|
||||||
"revision": 0,
|
|
||||||
"id": "b1d5a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Second test event",
|
|
||||||
"subtitle": "",
|
"subtitle": "",
|
||||||
"presenter": "",
|
"presenter": "",
|
||||||
"note": "",
|
"note": "",
|
||||||
"endAction": "none",
|
"endAction": "none",
|
||||||
"timerType": "count-down",
|
"timerType": "count-down",
|
||||||
"timeStart": 36000000,
|
"timeStart": 120000,
|
||||||
"timeEnd": 39600000,
|
"timeEnd": 180000,
|
||||||
"duration": 3600000,
|
"duration": 60000,
|
||||||
"isPublic": true,
|
"isPublic": false,
|
||||||
"skip": false,
|
"skip": false,
|
||||||
"colour": "",
|
"colour": "",
|
||||||
"user0": "",
|
"user0": "",
|
||||||
@@ -63,12 +61,7 @@
|
|||||||
"cue": "2"
|
"cue": "2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Lunch",
|
"title": "title 3",
|
||||||
"type": "block",
|
|
||||||
"id": "91682"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Third test event",
|
|
||||||
"subtitle": "",
|
"subtitle": "",
|
||||||
"presenter": "",
|
"presenter": "",
|
||||||
"note": "",
|
"note": "",
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ test('cuesheet displays events and exports csv', async ({ page }) => {
|
|||||||
await page.getByRole('cell', { name: '+10 min' }).click();
|
await page.getByRole('cell', { name: '+10 min' }).click();
|
||||||
await page.getByRole('cell', { name: 'Lunch' }).click();
|
await page.getByRole('cell', { name: 'Lunch' }).click();
|
||||||
const downloadPromise = page.waitForEvent('download');
|
const downloadPromise = page.waitForEvent('download');
|
||||||
await page.getByTestId('cuesheet').getByText('CSV').click();
|
await page.getByTestId('cuesheet').getByText('Export').click();
|
||||||
|
await page.getByText('CSV').click();
|
||||||
|
|
||||||
// From here we test the CSV download feature
|
// From here we test the CSV download feature
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user