Compare commits

...

15 Commits

Author SHA1 Message Date
Alex Christoffer Rasmussen b7c48f38a9 hotfix-build (#1091)
* skip  "alwaysStrict": true

* bump to 3.3.2

* remove all new ts check to be sure
2024-06-17 11:44:44 +02:00
Carlos Valente dcb6bfa62d bump version to 3.3.1 2024-06-17 08:21:01 +02:00
Carlos Valente 0abc4de3cd fix: column reordering in cuesheet 2024-06-17 08:14:12 +02:00
Carlos Valente f750ed3cdc style: match table header size 2024-06-17 08:14:12 +02:00
Carlos Valente f026c1c1e3 chore: run linter on imports 2024-06-17 08:10:14 +02:00
Piotr Górski ce176b01a2 Added Polish Translation (#1077) 2024-06-16 14:46:11 +02:00
Carlos Valente 337dd7892a chore: fix typo in donation text 2024-06-16 14:45:16 +02:00
Carlos Valente b7daf2926a refactor: improve typing 2024-06-16 09:07:01 +02:00
jwetzell 81a07099ae Merge pull request #1084 from cpvalente/fix/npm-publish-with-provenance
add permission for provenance publishing
2024-06-15 14:59:28 -05:00
jwetzell 8f88ca5053 add permission for provenance publishing
https://docs.npmjs.com/generating-provenance-statements
2024-06-15 14:59:16 -05:00
jwetzell 82a885dc44 Merge pull request #1082 from cpvalente/fix/publish-action
add registry url for publishing via CI
2024-06-15 13:33:58 -05:00
jwetzell c4be814de5 add registry url for publishing via CI 2024-06-15 13:33:08 -05:00
Carlos Valente 9f3186e249 bump version to 3.3.0 2024-06-15 17:30:58 +02:00
jwetzell 5159554697 Merge pull request #1080 from cpvalente/fix/npm-publish-action
disable git checks for pnpm publish workflow
2024-06-15 08:30:30 -05:00
jwetzell cf690aff08 disable git checks for pnpm publish workflow 2024-06-15 08:25:43 -05:00
25 changed files with 149 additions and 59 deletions
+5 -2
View File
@@ -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
View File
@@ -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://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/cpvalente) [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/cpvalente)
[![](https://img.shields.io/static/v1?label=Buy%20me%20a%20coffee&message=%E2%9D%A4&logo=buymeacoffee&color=%23fe8e86)](https://www.buymeacoffee.com/cpvalente) [![](https://img.shields.io/static/v1?label=Buy%20me%20a%20coffee&message=%E2%9D%A4&logo=buymeacoffee&color=%23fe8e86)](https://www.buymeacoffee.com/cpvalente)
+1 -1
View File
@@ -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 -1
View File
@@ -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 {
+11 -19
View File
@@ -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 -1
View File
@@ -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",
+1 -1
View File
@@ -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",
+3 -2
View File
@@ -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`);
} }
}); });
+2 -2
View File
@@ -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 = {
+5 -1
View File
@@ -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({
+1 -1
View File
@@ -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
View File
@@ -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",