From facce4f096b5eec901e2f385e1b0fc6be44de2c1 Mon Sep 17 00:00:00 2001 From: arc-alex Date: Mon, 20 Nov 2023 17:44:39 +0100 Subject: [PATCH 01/24] trigger doRoll if clock is less than startAt --- apps/server/src/services/TimerService.ts | 2 +- .../src/services/__tests__/rollUtils.test.ts | 20 +++++++++++++++++++ apps/server/src/services/rollUtils.ts | 7 ++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/server/src/services/TimerService.ts b/apps/server/src/services/TimerService.ts index 4f3714cc0..64c8ae577 100644 --- a/apps/server/src/services/TimerService.ts +++ b/apps/server/src/services/TimerService.ts @@ -339,7 +339,7 @@ export class TimerService { this.timer.expectedFinish >= this.timer.startedAt ? this.timer.expectedFinish : this.timer.expectedFinish + dayInMs, - + _startAt: this.timer.startedAt, clock: this.timer.clock, secondaryTimer: this.timer.secondaryTimer, secondaryTarget: this.secondaryTarget, diff --git a/apps/server/src/services/__tests__/rollUtils.test.ts b/apps/server/src/services/__tests__/rollUtils.test.ts index 329ece996..5622661c6 100644 --- a/apps/server/src/services/__tests__/rollUtils.test.ts +++ b/apps/server/src/services/__tests__/rollUtils.test.ts @@ -703,4 +703,24 @@ describe('typical scenarios', () => { expect(updateRoll(timers)).toStrictEqual(expected); }); + + it('rolls backwards', () => { + const timers = { + selectedEventId: '1', + current: 11, + _startAt: 10, + _finishAt: 15, + clock: 9, + secondaryTimer: null, + secondaryTarget: null, + }; + + const expected = { + updatedTimer: timers._finishAt - timers.clock, + updatedSecondaryTimer: null, + doRollLoad: true, + isFinished: false, + }; + expect(updateRoll(timers)).toStrictEqual(expected); + }); }); diff --git a/apps/server/src/services/rollUtils.ts b/apps/server/src/services/rollUtils.ts index 98a6feac2..b3c59c7f7 100644 --- a/apps/server/src/services/rollUtils.ts +++ b/apps/server/src/services/rollUtils.ts @@ -153,6 +153,7 @@ type CurrentTimers = { selectedEventId: string | null; current: number | null; _finishAt: number | null; + _startAt: number | null; clock: number | null; secondaryTimer: number | null; secondaryTarget: number | null; @@ -164,7 +165,7 @@ type CurrentTimers = { * @returns {object} object with selection variables */ export const updateRoll = (currentTimers: CurrentTimers) => { - const { selectedEventId, current, _finishAt, clock, secondaryTimer, secondaryTarget } = currentTimers; + const { selectedEventId, current, _finishAt, _startAt, clock, secondaryTimer, secondaryTarget } = currentTimers; // timers let updatedTimer = current; @@ -182,10 +183,14 @@ export const updateRoll = (currentTimers: CurrentTimers) => { updatedTimer -= dayInMs; } + console.log(Math.floor(_startAt / 1000), Math.floor(clock / 1000)); + if (updatedTimer < 0) { isPrimaryFinished = true; // we need a new event doRollLoad = true; + } else if (clock < _startAt) { + doRollLoad = true; } } else if (secondaryTimer >= 0) { // if secondaryTimer is running we are in waiting to roll From 22d89c6fbca5f2035ee1e4abe36421c6c285edfe Mon Sep 17 00:00:00 2001 From: arc-alex Date: Mon, 20 Nov 2023 17:51:50 +0100 Subject: [PATCH 02/24] add _startAt to all tests --- apps/server/src/services/__tests__/rollUtils.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/server/src/services/__tests__/rollUtils.test.ts b/apps/server/src/services/__tests__/rollUtils.test.ts index 5622661c6..7c1b4a7c8 100644 --- a/apps/server/src/services/__tests__/rollUtils.test.ts +++ b/apps/server/src/services/__tests__/rollUtils.test.ts @@ -562,6 +562,7 @@ describe('typical scenarios', () => { selectedEventId: '1', current: 10, _finishAt: 15, + _startAt: 9, clock: 11, secondaryTimer: null, secondaryTarget: null, @@ -589,6 +590,7 @@ describe('typical scenarios', () => { selectedEventId: null, current: null, _finishAt: null, + _startAt: null, clock: 11, secondaryTimer: 1, secondaryTarget: 15, @@ -609,6 +611,7 @@ describe('typical scenarios', () => { selectedEventId: '1', current: 10, _finishAt: 11, + _startAt: 9, clock: 12, secondaryTimer: null, secondaryTarget: null, @@ -629,6 +632,7 @@ describe('typical scenarios', () => { selectedEventId: null, current: null, _finishAt: null, + _startAt: null, clock: 16, secondaryTimer: 1, secondaryTarget: 15, @@ -649,6 +653,7 @@ describe('typical scenarios', () => { selectedEventId: null, current: null, _finishAt: null, + _startAt: null, clock: 15, secondaryTimer: 0, secondaryTarget: 15, @@ -669,6 +674,7 @@ describe('typical scenarios', () => { selectedEventId: '1', current: 25, _finishAt: 10 + dayInMs, + _startAt: 10, clock: dayInMs - 10, secondaryTimer: null, secondaryTarget: null, @@ -689,6 +695,7 @@ describe('typical scenarios', () => { selectedEventId: '1', current: dayInMs, _finishAt: 10 + dayInMs, + _startAt: 10, clock: 10, secondaryTimer: null, secondaryTarget: null, From 8cabb347e9ecd47152ff859692350383e32b805a Mon Sep 17 00:00:00 2001 From: arc-alex Date: Mon, 20 Nov 2023 18:24:11 +0100 Subject: [PATCH 03/24] remove test log --- apps/server/src/services/rollUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/server/src/services/rollUtils.ts b/apps/server/src/services/rollUtils.ts index b3c59c7f7..1e82eecb4 100644 --- a/apps/server/src/services/rollUtils.ts +++ b/apps/server/src/services/rollUtils.ts @@ -183,7 +183,6 @@ export const updateRoll = (currentTimers: CurrentTimers) => { updatedTimer -= dayInMs; } - console.log(Math.floor(_startAt / 1000), Math.floor(clock / 1000)); if (updatedTimer < 0) { isPrimaryFinished = true; From e6b4f537af47a1e9a71bcb8d07af8cbc00e30361 Mon Sep 17 00:00:00 2001 From: arc-alex Date: Wed, 22 Nov 2023 19:05:08 +0100 Subject: [PATCH 04/24] rollSkipLimit --- apps/server/src/config/config.js | 1 + .../src/services/__tests__/rollUtils.test.ts | 61 +++++++++++++++++++ apps/server/src/services/rollUtils.ts | 6 +- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/apps/server/src/config/config.js b/apps/server/src/config/config.js index f11da3cdc..42ec30e52 100644 --- a/apps/server/src/config/config.js +++ b/apps/server/src/config/config.js @@ -9,4 +9,5 @@ export const config = { filename: 'override.css', }, restoreFile: 'ontime.restore', + rollSkipLimit: 3 * 32, }; diff --git a/apps/server/src/services/__tests__/rollUtils.test.ts b/apps/server/src/services/__tests__/rollUtils.test.ts index 7c1b4a7c8..ced5f1adc 100644 --- a/apps/server/src/services/__tests__/rollUtils.test.ts +++ b/apps/server/src/services/__tests__/rollUtils.test.ts @@ -2,6 +2,7 @@ import { OntimeEvent } from 'ontime-types'; import { dayInMs } from 'ontime-utils'; import { getRollTimers, normaliseEndTime, sortArrayByProperty, updateRoll } from '../rollUtils.js'; +import { config } from '../../config/config.js'; // test sortArrayByProperty() describe('sort simple arrays of objects', () => { @@ -585,6 +586,66 @@ describe('typical scenarios', () => { expect(updateRoll(timers)).toStrictEqual(expected); }); + it('dose not skip isFinished under limit', () => { + const timers = { + selectedEventId: '1', + current: 13, + _finishAt: 15, + _startAt: 9, + clock: 14, + secondaryTimer: null, + secondaryTarget: null, + }; + + const expected = { + updatedTimer: timers._finishAt - timers.clock, + updatedSecondaryTimer: null, + doRollLoad: false, + isFinished: false, + }; + + expect(updateRoll(timers)).toStrictEqual(expected); + + // test that it can jump time + timers._finishAt = 14; + timers.clock += config.rollSkipLimit - 1; + expected.updatedTimer = timers._finishAt - timers.clock; + expected.doRollLoad = true; + expected.isFinished = true; + + expect(updateRoll(timers)).toStrictEqual(expected); + }); + + it('dose skips isFinished over limit', () => { + const timers = { + selectedEventId: '1', + current: 13, + _finishAt: 15, + _startAt: 9, + clock: 14, + secondaryTimer: null, + secondaryTarget: null, + }; + + const expected = { + updatedTimer: timers._finishAt - timers.clock, + updatedSecondaryTimer: null, + doRollLoad: false, + isFinished: false, + }; + + expect(updateRoll(timers)).toStrictEqual(expected); + + // test that it can jump time + timers._finishAt = 14; + timers.clock += config.rollSkipLimit + 1; + expected.updatedTimer = timers._finishAt - timers.clock; + expected.doRollLoad = true; + expected.isFinished = false; + + expect(updateRoll(timers)).toStrictEqual(expected); + }); + it('it updates secondary timer', () => { const timers = { selectedEventId: null, diff --git a/apps/server/src/services/rollUtils.ts b/apps/server/src/services/rollUtils.ts index 1e82eecb4..67c7363fa 100644 --- a/apps/server/src/services/rollUtils.ts +++ b/apps/server/src/services/rollUtils.ts @@ -1,5 +1,6 @@ import { OntimeEvent } from 'ontime-types'; import { dayInMs } from 'ontime-utils'; +import { config } from '../config/config.js'; /** * handle events that span over midnight @@ -167,6 +168,7 @@ type CurrentTimers = { export const updateRoll = (currentTimers: CurrentTimers) => { const { selectedEventId, current, _finishAt, _startAt, clock, secondaryTimer, secondaryTarget } = currentTimers; + console.log(currentTimers); // timers let updatedTimer = current; let updatedSecondaryTimer = secondaryTimer; @@ -183,12 +185,12 @@ export const updateRoll = (currentTimers: CurrentTimers) => { updatedTimer -= dayInMs; } - if (updatedTimer < 0) { - isPrimaryFinished = true; + if (Math.abs(updatedTimer) < config.rollSkipLimit) isPrimaryFinished = true; //Dont trigger Finished if we are over the skip limit // we need a new event doRollLoad = true; } else if (clock < _startAt) { + // we have rolled back befor this evet start so we need a new one doRollLoad = true; } } else if (secondaryTimer >= 0) { From b11041938d43d821be78c12afeb27c806ccfdbc8 Mon Sep 17 00:00:00 2001 From: arc-alex Date: Fri, 24 Nov 2023 14:05:12 +0100 Subject: [PATCH 05/24] self documenting --- apps/server/src/services/rollUtils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/server/src/services/rollUtils.ts b/apps/server/src/services/rollUtils.ts index 67c7363fa..3a5cd13c4 100644 --- a/apps/server/src/services/rollUtils.ts +++ b/apps/server/src/services/rollUtils.ts @@ -168,7 +168,6 @@ type CurrentTimers = { export const updateRoll = (currentTimers: CurrentTimers) => { const { selectedEventId, current, _finishAt, _startAt, clock, secondaryTimer, secondaryTarget } = currentTimers; - console.log(currentTimers); // timers let updatedTimer = current; let updatedSecondaryTimer = secondaryTimer; @@ -186,7 +185,10 @@ export const updateRoll = (currentTimers: CurrentTimers) => { } if (updatedTimer < 0) { - if (Math.abs(updatedTimer) < config.rollSkipLimit) isPrimaryFinished = true; //Dont trigger Finished if we are over the skip limit + const hasSkipped = Math.abs(updatedTimer) > config.rollSkipLimit; + if (!hasSkipped) { + isPrimaryFinished = true; + } // we need a new event doRollLoad = true; } else if (clock < _startAt) { From 41c26778cbe76c7eb939f0b6d188ad261e17afd3 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sat, 25 Nov 2023 21:55:27 +0100 Subject: [PATCH 06/24] fix: prevent shortcut collision with menu (#619) --- .../src/common/components/navigation-menu/NavigationMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx b/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx index 7924291ba..8d72fed80 100644 --- a/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx +++ b/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx @@ -12,7 +12,6 @@ import { IoSwapVertical } from '@react-icons/all-files/io5/IoSwapVertical'; import { navigatorConstants } from '../../../viewerConfig'; import useClickOutside from '../../hooks/useClickOutside'; import useFullscreen from '../../hooks/useFullscreen'; -import { useKeyDown } from '../../hooks/useKeyDown'; import { useViewOptionsStore } from '../../stores/viewOptions'; import RenameClientModal from './rename-client-modal/RenameClientModal'; @@ -28,13 +27,14 @@ function NavigationMenu() { const [searchParams, setSearchParams] = useSearchParams(); const [showMenu, setShowMenu] = useState(false); const menuRef = useRef(null); + useClickOutside(menuRef, () => setShowMenu(false)); const { isOpen, onOpen, onClose } = useDisclosure(); const toggleMenu = () => setShowMenu((prev) => !prev); - useKeyDown(toggleMenu, ' ', { isDisabled: searchParams.get('edit') === 'true' || isOpen }); + // show on mouse move useEffect(() => { let fadeOut: NodeJS.Timeout | null = null; const setShowMenuTrue = () => { From 0660f014c8f6fe4b620e9ad1707c187528bd3a73 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:04:47 +0100 Subject: [PATCH 07/24] fix: prevent autocomplete (#620) --- apps/client/src/common/components/input/time-input/TimeInput.tsx | 1 + .../src/features/event-editor/composite/CountedTextInput.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/client/src/common/components/input/time-input/TimeInput.tsx b/apps/client/src/common/components/input/time-input/TimeInput.tsx index 04fdf5b31..d584b8f02 100644 --- a/apps/client/src/common/components/input/time-input/TimeInput.tsx +++ b/apps/client/src/common/components/input/time-input/TimeInput.tsx @@ -212,6 +212,7 @@ export default function TimeInput(props: TimeInputProps) { onKeyDown={onKeyDownHandler} value={value} maxLength={8} + autoComplete='off' /> ); diff --git a/apps/client/src/features/event-editor/composite/CountedTextInput.tsx b/apps/client/src/features/event-editor/composite/CountedTextInput.tsx index 7c9ebf351..e9dc52cc6 100644 --- a/apps/client/src/features/event-editor/composite/CountedTextInput.tsx +++ b/apps/client/src/features/event-editor/composite/CountedTextInput.tsx @@ -40,6 +40,7 @@ export default function CountedTextInput(props: CountedTextInputProps) { onChange={onChange} onBlur={onBlur} onKeyDown={onKeyDown} + autoComplete='off' /> ); From db56ac80497c71b71b9f6c76d35dcb3ad3b0cd32 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:28:54 +0100 Subject: [PATCH 08/24] style: separe arguments in copy fields (#621) --- apps/client/src/features/event-editor/EventEditor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/client/src/features/event-editor/EventEditor.tsx b/apps/client/src/features/event-editor/EventEditor.tsx index 1163b9a01..f9fe8f4cc 100644 --- a/apps/client/src/features/event-editor/EventEditor.tsx +++ b/apps/client/src/features/event-editor/EventEditor.tsx @@ -73,8 +73,8 @@ export default function EventEditor() { handleSubmit={handleSubmit} > {event.id} - {`/ontime/gotoid/${event.id}`} - {`/ontime/gotocue/${event.cue}`} + {`/ontime/gotoid "${event.id}"`} + {`/ontime/gotocue "${event.cue}"`} ); From 1ccf2108ebe31d3bb11c96b5319555b0f2f87f99 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:31:09 +0100 Subject: [PATCH 09/24] style: tweaks on info data (#622) --- apps/client/src/features/info/Info.module.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/client/src/features/info/Info.module.scss b/apps/client/src/features/info/Info.module.scss index fadabd735..b64b5b141 100644 --- a/apps/client/src/features/info/Info.module.scss +++ b/apps/client/src/features/info/Info.module.scss @@ -5,6 +5,7 @@ display: flex; justify-content: space-between; gap: 1rem; + font-size: $inner-section-text-size; .title { white-space: nowrap; @@ -14,12 +15,12 @@ .selected { min-width: max-content; - font-size: $inner-section-text-size; color: $label-gray; } } .description { + font-size: $inner-section-text-size; color: $label-gray; white-space: nowrap; overflow: hidden; From 9e285ee8f3a7f95527afadf34634243c21441e1c Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:31:22 +0100 Subject: [PATCH 10/24] chore: version bump (#616) --- apps/client/package.json | 2 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index c89afbdf3..68b686d00 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "2.16.2", + "version": "2.21.3", "private": true, "dependencies": { "@chakra-ui/react": "^2.7.0", diff --git a/apps/electron/package.json b/apps/electron/package.json index 33e8c5d24..0f7fdc9e9 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "2.16.2", + "version": "2.21.3", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index 58cbe9152..5476b829d 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "2.16.2", + "version": "2.21.3", "exports": "./src/index.js", "dependencies": { "body-parser": "^1.20.0", diff --git a/package.json b/package.json index b4cb9d1df..766cafbc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "2.16.2", + "version": "2.21.3", "description": "Time keeping for live events", "keywords": [ "lighdev", From f2504072ce576444617a0a5e91aafcb4e5694c9a Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:02:16 +0100 Subject: [PATCH 11/24] feat: add change endpoint to ws (#618) * feat: add change endpoint to ws --- apps/server/src/adapters/OscAdapter.ts | 30 +++++++++++++++++-- apps/server/src/adapters/WebsocketAdapter.ts | 3 +- apps/server/src/app.ts | 6 ++-- .../src/controllers/integrationController.ts | 29 ++++++++---------- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/apps/server/src/adapters/OscAdapter.ts b/apps/server/src/adapters/OscAdapter.ts index 6bbdc0a7b..d07896983 100644 --- a/apps/server/src/adapters/OscAdapter.ts +++ b/apps/server/src/adapters/OscAdapter.ts @@ -3,7 +3,7 @@ import { LogOrigin, OSCSettings } from 'ontime-types'; import { Server } from 'node-osc'; import { IAdapter } from './IAdapter.js'; -import { dispatchFromAdapter } from '../controllers/integrationController.js'; +import { dispatchFromAdapter, type ChangeOptions } from '../controllers/integrationController.js'; import { logger } from '../classes/Logger.js'; export class OscServer implements IAdapter { @@ -36,12 +36,36 @@ export class OscServer implements IAdapter { return; } + let transformedPayload: unknown = args; + // we need to transform the params for the change endpoint + // OSC: ontime/change/{eventID}/{propertyName} value + if (path === 'change') { + if (params.length < 2) { + logger.error(LogOrigin.Rx, 'OSC IN: No params provided for change'); + return; + } + + if (args === undefined) { + logger.error(LogOrigin.Rx, 'OSC IN: No valid payload provided for change'); + return; + } + + const eventId = params[0]; + const property = params[1]; + const value: string | number | boolean = args as string | number | boolean; + + transformedPayload = { + eventId, + property, + value, + } satisfies ChangeOptions; + } + try { const reply = dispatchFromAdapter( path, { - payload: args, - params, + payload: transformedPayload, }, 'osc', ); diff --git a/apps/server/src/adapters/WebsocketAdapter.ts b/apps/server/src/adapters/WebsocketAdapter.ts index 53fe92b80..0383a1bf6 100644 --- a/apps/server/src/adapters/WebsocketAdapter.ts +++ b/apps/server/src/adapters/WebsocketAdapter.ts @@ -17,6 +17,7 @@ import { LogOrigin } from 'ontime-types'; import { WebSocket, WebSocketServer } from 'ws'; +import type { Server } from 'http'; import getRandomName from '../utils/getRandomName.js'; import { IAdapter } from './IAdapter.js'; @@ -43,7 +44,7 @@ export class SocketServer implements IAdapter { this.wss = null; } - init(server) { + init(server: Server) { this.wss = new WebSocketServer({ path: '/ws', server }); this.wss.on('connection', (ws) => { diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 9f142c381..2d0b359d2 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -3,7 +3,7 @@ import { LogOrigin, OSCSettings } from 'ontime-types'; import 'dotenv/config'; import express from 'express'; import expressStaticGzip from 'express-static-gzip'; -import http from 'http'; +import http, { type Server } from 'http'; import cors from 'cors'; // import utils @@ -107,8 +107,8 @@ enum OntimeStartOrder { } let step = OntimeStartOrder.InitAssets; -let expressServer = null; -let oscServer = null; +let expressServer: Server | null = null; +let oscServer: OscServer | null = null; const checkStart = (currentState: OntimeStartOrder) => { if (step !== currentState) { diff --git a/apps/server/src/controllers/integrationController.ts b/apps/server/src/controllers/integrationController.ts index a37579a37..243d60b65 100644 --- a/apps/server/src/controllers/integrationController.ts +++ b/apps/server/src/controllers/integrationController.ts @@ -1,5 +1,3 @@ -import { OntimeEvent } from 'ontime-types'; - import { messageService } from '../services/message-service/MessageService.js'; import { PlaybackService } from '../services/PlaybackService.js'; import { eventStore } from '../stores/EventStore.js'; @@ -7,19 +5,23 @@ import { parse, updateEvent } from './integrationController.config.js'; import { isKeyOfType } from 'ontime-types/src/utils/guards.js'; import { event } from '../models/eventsDefinition.js'; +export type ChangeOptions = { + eventId: string; + property: string; + value: unknown; +}; + //TODO: re-throwing the error does not add any extra information or value export function dispatchFromAdapter( type: string, args: { payload: unknown; - params?: Array; }, _source?: 'osc' | 'ws', ) { const payload = args.payload; const typeComponents = type.toLowerCase().split('/'); const mainType = typeComponents[0]; - const params = args.params || []; switch (mainType) { case 'test-ontime': { @@ -267,21 +269,14 @@ export function dispatchFromAdapter( return { topic: 'timer', payload: timer }; } - // ontime/change/{eventID}/{propertyName} + // WS: {type: 'change', payload: { eventId, property, value } } case 'change': { - if (params.length < 2) { - throw new Error('Too few parameters, 3 expected'); + const { eventId, property, value } = payload as ChangeOptions; + if (!isKeyOfType(property, event)) { + throw new Error(`Cannot update unknown event property ${property}`); } - if (payload === undefined) { - throw new Error('No payload found'); - } - const eventID = params[0]; - const propertyName = params[1] as keyof OntimeEvent; - if (!isKeyOfType(propertyName, event)) { - throw new Error(`Cannot update unknown event property ${propertyName}`); - } - const parsedPayload = parse(propertyName, payload); - return updateEvent(eventID, propertyName, parsedPayload); + const parsedPayload = parse(property, value); + return updateEvent(eventId, property, parsedPayload); } default: { From 27f6d106770e931beef8b47d80bf7c0b5cc29d2a Mon Sep 17 00:00:00 2001 From: arc-alex Date: Sun, 26 Nov 2023 20:41:01 +0100 Subject: [PATCH 12/24] actually disable/enable osc output --- .../src/services/integration-service/OscIntegration.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/server/src/services/integration-service/OscIntegration.ts b/apps/server/src/services/integration-service/OscIntegration.ts index f9c730a28..8c3071cf5 100644 --- a/apps/server/src/services/integration-service/OscIntegration.ts +++ b/apps/server/src/services/integration-service/OscIntegration.ts @@ -26,7 +26,15 @@ export class OscIntegration implements IIntegration { * Initializes oscClient */ init(config: OSCSettings) { - const { targetIP, portOut, subscriptions } = config; + const { targetIP, portOut, subscriptions, enabledOut } = config; + + if (!enabledOut) { + this.oscClient?.close(); + return { + success: false, + message: 'OSC output disabled', + }; + } this.initSubscriptions(subscriptions); From 715fa664447cab273cef4b51b3c88a02d35ec4ac Mon Sep 17 00:00:00 2001 From: arc-alex Date: Sun, 26 Nov 2023 20:41:33 +0100 Subject: [PATCH 13/24] disable/enable from ui without restart --- apps/server/src/controllers/ontimeController.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/server/src/controllers/ontimeController.ts b/apps/server/src/controllers/ontimeController.ts index 9ebb2ae1f..fd2463791 100644 --- a/apps/server/src/controllers/ontimeController.ts +++ b/apps/server/src/controllers/ontimeController.ts @@ -16,6 +16,7 @@ import { deleteAllEvents, notifyChanges } from '../services/rundown-service/Rund import { deepmerge } from 'ontime-utils'; import { runtimeCacheStore } from '../stores/cachingStore.js'; import { delayedRundownCacheKey } from '../services/rundown-service/delayedRundown.utils.js'; +import { integrationService } from '../services/integration-service/IntegrationService.js'; // Create controller for GET request to '/ontime/poll' // Returns data for current state @@ -315,10 +316,16 @@ export const postOSC = async (req, res) => { const oscSettings = req.body; await DataProvider.setOsc(oscSettings); + integrationService.unregister(oscIntegration); + // TODO: this update could be more granular, checking that relevant data was changed - const { message } = oscIntegration.init(oscSettings); + const { success, message } = oscIntegration.init(oscSettings); logger.info(LogOrigin.Tx, message); + if (success) { + integrationService.register(oscIntegration); + } + res.send(oscSettings).status(200); } catch (error) { res.status(400).send({ message: error.toString() }); From edb79d581910a046c87aa3d96359d92e1d56eb2e Mon Sep 17 00:00:00 2001 From: asharonbaltazar <58940073+asharonbaltazar@users.noreply.github.com> Date: Sun, 26 Nov 2023 15:57:18 -0500 Subject: [PATCH 14/24] Default Values in `ParamEditor` (#610) * add `defaultvalue` to `Field` types * add `defaultValue` to constants; turn into functions for time values * update constant imports/calls in view components * use `defaultValue`s in `ParamInput` * change `Clear` to `Reset`to better reflect actions * make `defaultValue` optional rather than `undefined` * update forgotten constants * add `defaultValue` to boolean input * change `101010` to `000000` * add `prefix` property to types * implement `prefix` for `ParamInput`s * change `paramField` to `prop` * add `onEditDrawerClose` to `resetParams` * `ViewParamsEditor` omits default values * undo close on reset * move `useSettings` into `ViewWrapper` * change `settings` to include `undefined` --- .../view-params-editor/ParamInput.tsx | 38 +++++--- .../view-params-editor/ViewParamsEditor.tsx | 26 +++--- .../view-params-editor/constants.ts | 88 ++++++++++++++----- .../components/view-params-editor/types.ts | 12 ++- .../client/src/features/operator/Operator.tsx | 4 +- .../src/features/viewers/ViewWrapper.tsx | 6 +- .../features/viewers/backstage/Backstage.tsx | 11 ++- .../src/features/viewers/clock/Clock.tsx | 11 ++- .../features/viewers/countdown/Countdown.tsx | 11 ++- .../src/features/viewers/public/Public.tsx | 23 +++-- .../features/viewers/studio/StudioClock.tsx | 11 ++- .../src/features/viewers/timer/Timer.tsx | 11 ++- 12 files changed, 180 insertions(+), 72 deletions(-) diff --git a/apps/client/src/common/components/view-params-editor/ParamInput.tsx b/apps/client/src/common/components/view-params-editor/ParamInput.tsx index 54fb5a183..9820e040b 100644 --- a/apps/client/src/common/components/view-params-editor/ParamInput.tsx +++ b/apps/client/src/common/components/view-params-editor/ParamInput.tsx @@ -1,5 +1,5 @@ import { useSearchParams } from 'react-router-dom'; -import { Input, Select, Switch } from '@chakra-ui/react'; +import { Input, InputGroup, InputLeftElement, Select, Switch } from '@chakra-ui/react'; import { isStringBoolean } from '../../utils/viewUtils'; @@ -9,16 +9,22 @@ interface EditFormInputProps { paramField: ParamField; } -export default function ParamInput({ paramField }: EditFormInputProps) { +export default function ParamInput(props: EditFormInputProps) { const [searchParams] = useSearchParams(); - const { id, type } = paramField; + const { paramField } = props; + const { id, type, defaultValue } = paramField; if (type === 'option') { const optionFromParams = searchParams.get(id); - const defaultOptionValue = optionFromParams || undefined; + const defaultOptionValue = optionFromParams || defaultValue; return ( - {Object.entries(paramField.values).map(([key, value]) => (