mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-09 17:33:55 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7c48f38a9 | |||
| dcb6bfa62d | |||
| 0abc4de3cd | |||
| f750ed3cdc | |||
| f026c1c1e3 | |||
| ce176b01a2 | |||
| 337dd7892a | |||
| b7daf2926a | |||
| 81a07099ae | |||
| 8f88ca5053 | |||
| 82a885dc44 | |||
| c4be814de5 | |||
| 9f3186e249 | |||
| 5159554697 | |||
| cf690aff08 |
@@ -7,6 +7,8 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_cli:
|
build_cli:
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -19,6 +21,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18.18.2
|
node-version: 18.18.2
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v3
|
||||||
@@ -43,8 +46,8 @@ jobs:
|
|||||||
run: cp -R apps/server/src/external apps/cli/external
|
run: cp -R apps/server/src/external apps/cli/external
|
||||||
|
|
||||||
- name: Publish to NPM
|
- name: Publish to NPM
|
||||||
run: pnpm publish --access public
|
run: pnpm publish --access public --no-git-checks
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
NPM_CONFIG_PROVENANCE: true
|
NPM_CONFIG_PROVENANCE: true
|
||||||
working-directory: ./apps/cli
|
working-directory: ./apps/cli
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ npx install @getontime/cli
|
|||||||
|
|
||||||
## Sponsoring
|
## Sponsoring
|
||||||
You can help the development of this project or say thank you with a one time donation. \
|
You can help the development of this project or say thank you with a one time donation. \
|
||||||
See the [terms of fonations](https://github.com/cpvalente/ontime/blob/master/SPONSOR.md)
|
See the [terms of donations](https://github.com/cpvalente/ontime/blob/master/SPONSOR.md)
|
||||||
|
|
||||||
[](https://github.com/sponsors/cpvalente)
|
[](https://github.com/sponsors/cpvalente)
|
||||||
[](https://www.buymeacoffee.com/cpvalente)
|
[](https://www.buymeacoffee.com/cpvalente)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@getontime/cli",
|
"name": "@getontime/cli",
|
||||||
"version": "3.1.0",
|
"version": "3.3.2",
|
||||||
"author": "Carlos Valente",
|
"author": "Carlos Valente",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"repository": "https://github.com/cpvalente/ontime",
|
"repository": "https://github.com/cpvalente/ontime",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime-ui",
|
"name": "ontime-ui",
|
||||||
"version": "3.3.0",
|
"version": "3.3.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ export default function GeneralPanelForm() {
|
|||||||
<option value='pt'>Portuguese</option>
|
<option value='pt'>Portuguese</option>
|
||||||
<option value='es'>Spanish</option>
|
<option value='es'>Spanish</option>
|
||||||
<option value='sv'>Swedish</option>
|
<option value='sv'>Swedish</option>
|
||||||
|
<option value='pl'>Polish</option>
|
||||||
</Select>
|
</Select>
|
||||||
</Panel.ListItem>
|
</Panel.ListItem>
|
||||||
</Panel.ListGroup>
|
</Panel.ListGroup>
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ $table-header-font-size: calc(1rem - 3px);
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
background-color: $gray-1300;
|
|
||||||
|
|
||||||
font-size: $table-header-font-size;
|
font-size: $table-header-font-size;
|
||||||
color: $gray-700;
|
color: $gray-700;
|
||||||
font-weight: 400;
|
|
||||||
|
th {
|
||||||
|
background-color: $gray-1300;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventRow {
|
.eventRow {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useCallback, useEffect, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { useLocalStorage } from '@mantine/hooks';
|
|
||||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
||||||
@@ -13,7 +12,7 @@ import DelayRow from './cuesheet-table-elements/DelayRow';
|
|||||||
import EventRow from './cuesheet-table-elements/EventRow';
|
import EventRow from './cuesheet-table-elements/EventRow';
|
||||||
import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings';
|
import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings';
|
||||||
import { useCuesheetSettings } from './store/CuesheetSettings';
|
import { useCuesheetSettings } from './store/CuesheetSettings';
|
||||||
import { initialColumnOrder } from './cuesheetCols';
|
import useColumnManager from './useColumnManager';
|
||||||
|
|
||||||
import style from './Cuesheet.module.scss';
|
import style from './Cuesheet.module.scss';
|
||||||
|
|
||||||
@@ -27,23 +26,20 @@ interface CuesheetProps {
|
|||||||
export default function Cuesheet({ data, columns, handleUpdate, selectedId }: CuesheetProps) {
|
export default function Cuesheet({ data, columns, handleUpdate, selectedId }: CuesheetProps) {
|
||||||
const { followSelected, showSettings, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings();
|
const { followSelected, showSettings, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings();
|
||||||
|
|
||||||
const [columnVisibility, setColumnVisibility] = useLocalStorage({ key: 'table-hidden', defaultValue: {} });
|
const {
|
||||||
const [columnOrder, saveColumnOrder] = useLocalStorage<string[]>({
|
columnVisibility,
|
||||||
key: 'table-order',
|
columnOrder,
|
||||||
defaultValue: initialColumnOrder,
|
columnSizing,
|
||||||
});
|
resetColumnOrder,
|
||||||
const [columnSizing, setColumnSizing] = useLocalStorage({ key: 'table-sizes', defaultValue: {} });
|
setColumnVisibility,
|
||||||
|
saveColumnOrder,
|
||||||
|
setColumnSizing,
|
||||||
|
} = useColumnManager(columns);
|
||||||
|
|
||||||
const selectedRef = useRef<HTMLTableRowElement | null>(null);
|
const selectedRef = useRef<HTMLTableRowElement | null>(null);
|
||||||
const tableContainerRef = useRef<HTMLDivElement | null>(null);
|
const tableContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
useFollowComponent({ followRef: selectedRef, scrollRef: tableContainerRef, doFollow: followSelected });
|
useFollowComponent({ followRef: selectedRef, scrollRef: tableContainerRef, doFollow: followSelected });
|
||||||
|
|
||||||
// keep column order in sync with columns
|
|
||||||
useEffect(() => {
|
|
||||||
const order = columns.map((col) => col.id as string);
|
|
||||||
saveColumnOrder(order);
|
|
||||||
}, [columns, saveColumnOrder]);
|
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
columns,
|
columns,
|
||||||
@@ -61,10 +57,6 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const resetColumnOrder = () => {
|
|
||||||
saveColumnOrder(initialColumnOrder);
|
|
||||||
};
|
|
||||||
|
|
||||||
const setAllVisible = () => {
|
const setAllVisible = () => {
|
||||||
table.toggleAllColumnsVisible(true);
|
table.toggleAllColumnsVisible(true);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -117,5 +117,3 @@ export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<Ontim
|
|||||||
...dynamicCustomFields,
|
...dynamicCustomFields,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialColumnOrder: string[] = makeCuesheetColumns({}).map((column) => column.id as string);
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
import { useLocalStorage } from '@mantine/hooks';
|
||||||
|
import { ColumnDef } from '@tanstack/react-table';
|
||||||
|
import { OntimeRundownEntry } from 'ontime-types';
|
||||||
|
|
||||||
|
export default function useColumnManager(columns: ColumnDef<OntimeRundownEntry>[]) {
|
||||||
|
const [columnVisibility, setColumnVisibility] = useLocalStorage({ key: 'table-hidden', defaultValue: {} });
|
||||||
|
const [columnOrder, saveColumnOrder] = useLocalStorage<string[]>({
|
||||||
|
key: 'table-order',
|
||||||
|
defaultValue: columns.map((col) => col.id as string),
|
||||||
|
});
|
||||||
|
const [columnSizing, setColumnSizing] = useLocalStorage({ key: 'table-sizes', defaultValue: {} });
|
||||||
|
|
||||||
|
// if the columns change, we update the dataset
|
||||||
|
useEffect(() => {
|
||||||
|
let shouldReplace = false;
|
||||||
|
const newColumns: string[] = [];
|
||||||
|
|
||||||
|
// iterate through columns to see if there are new ids
|
||||||
|
columns.forEach((column) => {
|
||||||
|
const columnnId = column.id as string;
|
||||||
|
if (!shouldReplace && !columnOrder.includes(columnnId)) {
|
||||||
|
shouldReplace = true;
|
||||||
|
}
|
||||||
|
newColumns.push(columnnId);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldReplace) {
|
||||||
|
saveColumnOrder(newColumns);
|
||||||
|
}
|
||||||
|
}, [columnOrder, columns, saveColumnOrder]);
|
||||||
|
|
||||||
|
const resetColumnOrder = useCallback(() => {
|
||||||
|
saveColumnOrder(columns.map((col) => col.id as string));
|
||||||
|
}, [columns, saveColumnOrder]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
columnVisibility,
|
||||||
|
columnOrder,
|
||||||
|
columnSizing,
|
||||||
|
resetColumnOrder,
|
||||||
|
setColumnVisibility,
|
||||||
|
saveColumnOrder,
|
||||||
|
setColumnSizing,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { langEs } from './languages/es';
|
|||||||
import { langFr } from './languages/fr';
|
import { langFr } from './languages/fr';
|
||||||
import { langIt } from './languages/it';
|
import { langIt } from './languages/it';
|
||||||
import { langNo } from './languages/no';
|
import { langNo } from './languages/no';
|
||||||
|
import { langPl } from './languages/pl';
|
||||||
import { langPt } from './languages/pt';
|
import { langPt } from './languages/pt';
|
||||||
import { langSv } from './languages/sv';
|
import { langSv } from './languages/sv';
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ const translationsList = {
|
|||||||
no: langNo,
|
no: langNo,
|
||||||
pt: langPt,
|
pt: langPt,
|
||||||
sv: langSv,
|
sv: langSv,
|
||||||
|
pl: langPl,
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TranslationContextValue {
|
interface TranslationContextValue {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { TranslationObject } from './en';
|
||||||
|
|
||||||
|
export const langPl: TranslationObject = {
|
||||||
|
'common.end_time': 'Czas zakończenia',
|
||||||
|
'common.expected_finish': 'Zakładany czas zakończenia',
|
||||||
|
'common.minutes': 'min',
|
||||||
|
'common.now': 'Teraz',
|
||||||
|
'common.next': 'Następnie',
|
||||||
|
'common.public_message': 'Wiadomość publiczna',
|
||||||
|
'common.start_time': 'Czas rozpoczęcia',
|
||||||
|
'common.stage_timer': 'Timer Scena',
|
||||||
|
'common.started_at': 'Rozpoczęte o',
|
||||||
|
'common.time_now': 'Aktualny czas',
|
||||||
|
'countdown.ended': 'Zakończone o',
|
||||||
|
'countdown.running': 'Trwa',
|
||||||
|
'countdown.select_event': 'Wybierz event który chcesz śledzić',
|
||||||
|
'countdown.to_start': 'Do rozpoczęcia',
|
||||||
|
'countdown.waiting': 'Oczekiwanie na start',
|
||||||
|
'countdown.overtime': 'ponad czasem',
|
||||||
|
};
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "3.3.0",
|
"version": "3.3.2",
|
||||||
"author": "Carlos Valente",
|
"author": "Carlos Valente",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"repository": "https://github.com/cpvalente/ontime",
|
"repository": "https://github.com/cpvalente/ontime",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "ontime-server",
|
"name": "ontime-server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"version": "3.3.0",
|
"version": "3.3.2",
|
||||||
"exports": "./src/index.js",
|
"exports": "./src/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@googleapis/sheets": "^5.0.5",
|
"@googleapis/sheets": "^5.0.5",
|
||||||
|
|||||||
@@ -208,8 +208,9 @@ export const startServer = async (
|
|||||||
expressServer.listen(serverPort, '0.0.0.0', () => {
|
expressServer.listen(serverPort, '0.0.0.0', () => {
|
||||||
const nif = getNetworkInterfaces();
|
const nif = getNetworkInterfaces();
|
||||||
consoleSuccess(`Local: http://localhost:${serverPort}/editor`);
|
consoleSuccess(`Local: http://localhost:${serverPort}/editor`);
|
||||||
for (const key of Object.keys(nif)) {
|
for (const key in nif) {
|
||||||
consoleSuccess(`Network: http://${nif[key].address}:${serverPort}/editor`);
|
const address = nif[key].address;
|
||||||
|
consoleSuccess(`Network: http://${address}:${serverPort}/editor`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { consoleSubdued, consoleRed } from '../utils/console.js';
|
|||||||
|
|
||||||
class Logger {
|
class Logger {
|
||||||
private queue: Log[];
|
private queue: Log[];
|
||||||
private escalateErrorFn: (error: string) => void | null;
|
private escalateErrorFn: ((error: string) => void) | null;
|
||||||
private canLog = false;
|
private canLog = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -20,7 +20,7 @@ class Logger {
|
|||||||
/**
|
/**
|
||||||
* Enabling setup logger after init
|
* Enabling setup logger after init
|
||||||
*/
|
*/
|
||||||
init(escalateErrorFn: (error: string) => void) {
|
init(escalateErrorFn?: (error: string) => void) {
|
||||||
// flush logs from queue
|
// flush logs from queue
|
||||||
this.queue.forEach((log) => {
|
this.queue.forEach((log) => {
|
||||||
this._push(log);
|
this._push(log);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DatabaseModel, OntimeRundown, Settings, URLPreset } from 'ontime-types';
|
import { DatabaseModel, OntimeRundown, Settings, URLPreset, ViewSettings } from 'ontime-types';
|
||||||
import { safeMerge } from '../DataProvider.utils.js';
|
import { safeMerge } from '../DataProvider.utils.js';
|
||||||
|
|
||||||
describe('safeMerge', () => {
|
describe('safeMerge', () => {
|
||||||
@@ -49,7 +49,7 @@ describe('safeMerge', () => {
|
|||||||
} as DatabaseModel;
|
} as DatabaseModel;
|
||||||
|
|
||||||
it('returns existing data if new data is not provided', () => {
|
it('returns existing data if new data is not provided', () => {
|
||||||
const mergedData = safeMerge(existing, undefined);
|
const mergedData = safeMerge(existing, {});
|
||||||
expect(mergedData).toEqual(existing);
|
expect(mergedData).toEqual(existing);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -136,6 +136,7 @@ describe('safeMerge', () => {
|
|||||||
rundown: [],
|
rundown: [],
|
||||||
project: {
|
project: {
|
||||||
title: '',
|
title: '',
|
||||||
|
description: '',
|
||||||
publicUrl: '',
|
publicUrl: '',
|
||||||
publicInfo: '',
|
publicInfo: '',
|
||||||
backstageUrl: '',
|
backstageUrl: '',
|
||||||
@@ -153,8 +154,9 @@ describe('safeMerge', () => {
|
|||||||
viewSettings: {
|
viewSettings: {
|
||||||
overrideStyles: false,
|
overrideStyles: false,
|
||||||
endMessage: '',
|
endMessage: '',
|
||||||
},
|
} as ViewSettings,
|
||||||
urlPresets: [],
|
urlPresets: [],
|
||||||
|
customFields: {},
|
||||||
osc: {
|
osc: {
|
||||||
portIn: 8888,
|
portIn: 8888,
|
||||||
portOut: 9999,
|
portOut: 9999,
|
||||||
@@ -163,6 +165,10 @@ describe('safeMerge', () => {
|
|||||||
enabledOut: false,
|
enabledOut: false,
|
||||||
subscriptions: [],
|
subscriptions: [],
|
||||||
},
|
},
|
||||||
|
http: {
|
||||||
|
enabledOut: false,
|
||||||
|
subscriptions: [],
|
||||||
|
},
|
||||||
} as DatabaseModel;
|
} as DatabaseModel;
|
||||||
|
|
||||||
const newData = {
|
const newData = {
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ describe('remove() mutation', () => {
|
|||||||
];
|
];
|
||||||
const { newRundown } = remove({ eventIds: ['1', '2', '3'], persistedRundown: testRundown });
|
const { newRundown } = remove({ eventIds: ['1', '2', '3'], persistedRundown: testRundown });
|
||||||
expect(newRundown.length).toBe(3);
|
expect(newRundown.length).toBe(3);
|
||||||
expect(newRundown.at(0).id).toBe('4');
|
expect(newRundown.at(0)?.id).toBe('4');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class RuntimeService {
|
|||||||
integrationService.dispatch(TimerLifeCycle.onUpdate);
|
integrationService.dispatch(TimerLifeCycle.onUpdate);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.lastIntegrationTimerValue = newState.timer.current;
|
this.lastIntegrationTimerValue = newState.timer.current ?? -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldUpdateClock = getShouldClockUpdate(this.lastIntegrationClockUpdate, newState.clock);
|
const shouldUpdateClock = getShouldClockUpdate(this.lastIntegrationClockUpdate, newState.clock);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AuthenticationStatus, CustomFields, LogOrigin, MaybeString, OntimeRundown } from 'ontime-types';
|
import { AuthenticationStatus, CustomFields, LogOrigin, MaybeString, OntimeRundown } from 'ontime-types';
|
||||||
|
import { ImportMap, getErrorMessage } from 'ontime-utils';
|
||||||
|
|
||||||
import { sheets, sheets_v4 } from '@googleapis/sheets';
|
import { sheets, sheets_v4 } from '@googleapis/sheets';
|
||||||
import { Credentials, OAuth2Client } from 'google-auth-library';
|
import { Credentials, OAuth2Client } from 'google-auth-library';
|
||||||
@@ -13,7 +14,6 @@ import got from 'got';
|
|||||||
import { resolveSheetsDirectory } from '../../setup/index.js';
|
import { resolveSheetsDirectory } from '../../setup/index.js';
|
||||||
import { ensureDirectory } from '../../utils/fileManagement.js';
|
import { ensureDirectory } from '../../utils/fileManagement.js';
|
||||||
import { cellRequestFromEvent, type ClientSecret, getA1Notation, validateClientSecret } from './sheetUtils.js';
|
import { cellRequestFromEvent, type ClientSecret, getA1Notation, validateClientSecret } from './sheetUtils.js';
|
||||||
import { ImportMap } from 'ontime-utils';
|
|
||||||
import { parseExcel } from '../../utils/parser.js';
|
import { parseExcel } from '../../utils/parser.js';
|
||||||
import { logger } from '../../classes/Logger.js';
|
import { logger } from '../../classes/Logger.js';
|
||||||
import { parseCustomFields, parseRundown } from '../../utils/parserFunctions.js';
|
import { parseCustomFields, parseRundown } from '../../utils/parserFunctions.js';
|
||||||
@@ -208,7 +208,8 @@ async function verifySheet(
|
|||||||
});
|
});
|
||||||
return { worksheetOptions: spreadsheets.data.sheets.map((i) => i.properties.title) };
|
return { worksheetOptions: spreadsheets.data.sheets.map((i) => i.properties.title) };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to verify sheet: ${error.message}`);
|
const errorMessage = getErrorMessage(error);
|
||||||
|
throw new Error(`Failed to verify sheet: ${errorMessage}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ describe('cellRequestFromEvent()', () => {
|
|||||||
timeDanger: { row: 1, col: 41 },
|
timeDanger: { row: 1, col: 41 },
|
||||||
};
|
};
|
||||||
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
||||||
expect(result.updateCells.rows[0].values[5].userEnteredValue.stringValue).toStrictEqual(event.note);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(5)?.userEnteredValue?.stringValue).toStrictEqual(event.note);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('number to timer', () => {
|
test('number to timer', () => {
|
||||||
@@ -103,9 +103,10 @@ describe('cellRequestFromEvent()', () => {
|
|||||||
timeWarning: { row: 1, col: 40 },
|
timeWarning: { row: 1, col: 40 },
|
||||||
timeDanger: { row: 1, col: 41 },
|
timeDanger: { row: 1, col: 41 },
|
||||||
};
|
};
|
||||||
const result = cellRequestFromEvent(event, 1, 1234, metadata).updateCells.rows[0].values[10].userEnteredValue
|
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
||||||
.stringValue;
|
expect(result.updateCells?.rows?.at(0)?.values?.at(10)?.userEnteredValue?.stringValue).toStrictEqual(
|
||||||
expect(result).toStrictEqual(millisToString(event.duration));
|
millisToString(event.duration),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('boolean to TRUE', () => {
|
test('boolean to TRUE', () => {
|
||||||
@@ -149,8 +150,8 @@ describe('cellRequestFromEvent()', () => {
|
|||||||
timeDanger: { row: 1, col: 41 },
|
timeDanger: { row: 1, col: 41 },
|
||||||
};
|
};
|
||||||
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
||||||
expect(result.updateCells.rows[0].values[11].userEnteredValue.boolValue).toStrictEqual(true);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(11)?.userEnteredValue?.boolValue).toStrictEqual(true);
|
||||||
expect(result.updateCells.rows[0].values[12].userEnteredValue.boolValue).toStrictEqual(false);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(12)?.userEnteredValue?.boolValue).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('spacing in metadata', () => {
|
test('spacing in metadata', () => {
|
||||||
@@ -180,8 +181,8 @@ describe('cellRequestFromEvent()', () => {
|
|||||||
title: { row: 1, col: 6 },
|
title: { row: 1, col: 6 },
|
||||||
};
|
};
|
||||||
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
||||||
expect(result.updateCells.rows[0].values[0].userEnteredValue.stringValue).toStrictEqual(event.cue);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(0)?.userEnteredValue?.stringValue).toStrictEqual(event.cue);
|
||||||
expect(result.updateCells.rows[0].values[6].userEnteredValue.stringValue).toStrictEqual(event.title);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(6)?.userEnteredValue?.stringValue).toStrictEqual(event.title);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('metadata offset from zero', () => {
|
test('metadata offset from zero', () => {
|
||||||
@@ -212,8 +213,8 @@ describe('cellRequestFromEvent()', () => {
|
|||||||
user0: { row: 1, col: 16 },
|
user0: { row: 1, col: 16 },
|
||||||
};
|
};
|
||||||
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
const result = cellRequestFromEvent(event, 1, 1234, metadata);
|
||||||
expect(result.updateCells.rows[0].values[0].userEnteredValue.stringValue).toStrictEqual(event.cue);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(0)?.userEnteredValue?.stringValue).toStrictEqual(event.cue);
|
||||||
expect(result.updateCells.rows[0].values[1].userEnteredValue.stringValue).toStrictEqual(event.title);
|
expect(result.updateCells?.rows?.at(0)?.values?.at(1)?.userEnteredValue?.stringValue).toStrictEqual(event.title);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sheet setup', () => {
|
test('sheet setup', () => {
|
||||||
@@ -243,10 +244,10 @@ describe('cellRequestFromEvent()', () => {
|
|||||||
title: { row: 10, col: 6 },
|
title: { row: 10, col: 6 },
|
||||||
};
|
};
|
||||||
const result1 = cellRequestFromEvent(event, 1, 1234, metadata);
|
const result1 = cellRequestFromEvent(event, 1, 1234, metadata);
|
||||||
expect(result1.updateCells.start.sheetId).toStrictEqual(1234);
|
expect(result1.updateCells?.start?.sheetId).toStrictEqual(1234);
|
||||||
const result2 = cellRequestFromEvent(event, 10, 1234, metadata);
|
const result2 = cellRequestFromEvent(event, 10, 1234, metadata);
|
||||||
expect(result2.updateCells.start.rowIndex).toStrictEqual(21);
|
expect(result2.updateCells?.start?.rowIndex).toStrictEqual(21);
|
||||||
expect(result2.updateCells.start.columnIndex).toStrictEqual(5);
|
expect(result2.updateCells?.start?.columnIndex).toStrictEqual(5);
|
||||||
expect(result2.updateCells.fields).toStrictEqual('userEnteredValue');
|
expect(result2.updateCells?.fields).toStrictEqual('userEnteredValue');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -160,6 +160,10 @@ describe('mutation on runtimeState', () => {
|
|||||||
start();
|
start();
|
||||||
newState = getState();
|
newState = getState();
|
||||||
const firstStart = newState.clock;
|
const firstStart = newState.clock;
|
||||||
|
if (newState.runtime.offset === null) {
|
||||||
|
throw new Error('Value cannot be null at this stage');
|
||||||
|
}
|
||||||
|
|
||||||
expect(newState.runtime.actualStart).toBe(newState.clock);
|
expect(newState.runtime.actualStart).toBe(newState.clock);
|
||||||
expect(newState.runtime.offset).toBe(event1.timeStart - newState.clock);
|
expect(newState.runtime.offset).toBe(event1.timeStart - newState.clock);
|
||||||
expect(newState.runtime.expectedEnd).toBe(event2.timeEnd - newState.runtime.offset);
|
expect(newState.runtime.expectedEnd).toBe(event2.timeEnd - newState.runtime.offset);
|
||||||
@@ -167,7 +171,11 @@ describe('mutation on runtimeState', () => {
|
|||||||
// 3. Next event
|
// 3. Next event
|
||||||
load(event2, [event1, event2]);
|
load(event2, [event1, event2]);
|
||||||
start();
|
start();
|
||||||
|
|
||||||
newState = getState();
|
newState = getState();
|
||||||
|
if (newState.runtime.actualStart === null || newState.runtime.offset === null) {
|
||||||
|
throw new Error('Value cannot be null at this stage');
|
||||||
|
}
|
||||||
|
|
||||||
// there is a case where the calculation time overflows the millisecond which makes
|
// there is a case where the calculation time overflows the millisecond which makes
|
||||||
// tests fail
|
// tests fail
|
||||||
@@ -182,6 +190,10 @@ describe('mutation on runtimeState', () => {
|
|||||||
// 4. Add time
|
// 4. Add time
|
||||||
addTime(10);
|
addTime(10);
|
||||||
newState = getState();
|
newState = getState();
|
||||||
|
if (newState.runtime.offset === null) {
|
||||||
|
throw new Error('Value cannot be null at this stage');
|
||||||
|
}
|
||||||
|
|
||||||
expect(newState.runtime.offset).toBe(delayBefore - 10);
|
expect(newState.runtime.offset).toBe(delayBefore - 10);
|
||||||
expect(newState.runtime.expectedEnd).toBe(event2.timeEnd - newState.runtime.offset);
|
expect(newState.runtime.expectedEnd).toBe(event2.timeEnd - newState.runtime.offset);
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe('mergeObject()', () => {
|
|||||||
test('it handles falsy values', () => {
|
test('it handles falsy values', () => {
|
||||||
const a = {
|
const a = {
|
||||||
first: 'yes',
|
first: 'yes',
|
||||||
second: 'yes',
|
second: 'yes' as string | null,
|
||||||
third: 'yes',
|
third: 'yes',
|
||||||
};
|
};
|
||||||
const b = {
|
const b = {
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ export function getNetworkInterfaces(): { name: string; address: string }[] {
|
|||||||
const results: { name: string; address: string }[] = [];
|
const results: { name: string; address: string }[] = [];
|
||||||
|
|
||||||
for (const name of Object.keys(nets)) {
|
for (const name of Object.keys(nets)) {
|
||||||
for (const net of nets[name]) {
|
const netObjects = nets[name];
|
||||||
|
if (!netObjects) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const net of netObjects) {
|
||||||
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
||||||
if (net.family === 'IPv4' && !net.internal) {
|
if (net.family === 'IPv4' && !net.internal) {
|
||||||
results.push({
|
results.push({
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function mergeObject<T extends object>(a: T, b: Partial<T>): T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof bValue === 'object' && bValue !== null && typeof aValue === 'object' && aValue !== null) {
|
if (typeof bValue === 'object' && bValue !== null && typeof aValue === 'object' && aValue !== null) {
|
||||||
// @ts-expect-error -- library side, ignore for now
|
// @ts-expect-error -- not sure how to type this
|
||||||
merged[key] = deepmerge(aValue, bValue);
|
merged[key] = deepmerge(aValue, bValue);
|
||||||
} else if (bValue !== undefined) {
|
} else if (bValue !== undefined) {
|
||||||
merged[key] = bValue;
|
merged[key] = bValue;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "3.3.0",
|
"version": "3.3.2",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ontime",
|
"ontime",
|
||||||
|
|||||||
Reference in New Issue
Block a user