From 7958d4915345ac6da2539452d2d35b6b3bf47aef Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 7 Mar 2025 23:02:32 +0100 Subject: [PATCH] refactor: remove unused and legacy code - remove legacy migrations - remove unused server code - remove unused UI code --- apps/client/src/common/api/constants.ts | 8 +- .../components/context-menu/ContextMenu.tsx | 2 +- .../error-boundary/ErrorBoundary.jsx | 6 +- .../loader-overlay/LoaderOverlay.module.scss | 45 -- .../loader-overlay/LoaderOverlay.tsx | 9 - .../ProductionNavigationMenu.tsx | 16 - .../components/view-params-editor/types.ts | 2 +- .../src/common/context/useMediaQuery.ts | 32 -- .../hooks-query/useAutomationSettings.ts | 18 +- .../src/common/hooks-query/useProjectList.ts | 2 +- apps/client/src/common/hooks/useMemoisedFn.ts | 2 +- apps/client/src/common/hooks/useSocket.ts | 10 - apps/client/src/common/stores/logger.ts | 2 +- apps/client/src/common/utils/socket.ts | 25 +- apps/client/src/common/utils/time.ts | 2 +- apps/client/src/declarations/test.d.ts | 11 - .../panel/general-panel/GeneralPanelForm.tsx | 4 - .../import-map/importMapUtils.ts | 2 +- .../rundown/event-editor/EventEditor.tsx | 2 - .../src/features/rundown/useEventSelection.ts | 2 +- .../src/features/viewers/common/animation.ts | 15 - .../src/translation/TranslationProvider.tsx | 2 +- .../timeline-section/TimelineSection.tsx | 2 +- .../src/views/timeline/timeline.utils.ts | 8 - apps/server/src/adapters/WebsocketAdapter.ts | 2 +- .../server/src/api-data/excel/excel.router.ts | 2 - .../api-data/rundown/rundown.controller.ts | 44 +- .../src/api-data/rundown/rundown.router.ts | 3 - .../api-data/rundown/rundown.validation.ts | 13 +- .../__tests__/integration.legacy.test.ts | 36 -- .../api-integration/integration.controller.ts | 9 +- .../src/api-integration/integration.legacy.ts | 67 --- apps/server/src/app.ts | 2 +- apps/server/src/classes/Logger.ts | 4 +- apps/server/src/services/Clock.ts | 60 --- .../aux-timer-service/AuxTimerService.ts | 4 +- .../__tests__/rundownCache.test.ts | 407 ------------------ .../__tests__/rundownUtils.test.ts | 39 -- .../services/rundown-service/delayUtils.ts | 90 +--- .../rundown-service/rundownCacheUtils.ts | 6 +- .../services/rundown-service/rundownUtils.ts | 16 - apps/server/src/stores/runtimeState.ts | 14 +- .../utils/__tests__/parserFunctions.test.ts | 46 -- apps/server/src/utils/parser.ts | 2 +- apps/server/src/utils/parserFunctions.ts | 22 +- apps/server/src/utils/removeFileExtension.ts | 9 - apps/server/src/utils/time.ts | 14 + .../ontime-controller/BackendResponse.type.ts | 6 - packages/types/src/index.ts | 1 - 49 files changed, 64 insertions(+), 1083 deletions(-) delete mode 100644 apps/client/src/common/components/loader-overlay/LoaderOverlay.module.scss delete mode 100644 apps/client/src/common/components/loader-overlay/LoaderOverlay.tsx delete mode 100644 apps/client/src/common/components/navigation-menu/ProductionNavigationMenu.tsx delete mode 100644 apps/client/src/common/context/useMediaQuery.ts delete mode 100644 apps/client/src/declarations/test.d.ts delete mode 100644 apps/client/src/features/viewers/common/animation.ts delete mode 100644 apps/server/src/api-integration/__tests__/integration.legacy.test.ts delete mode 100644 apps/server/src/api-integration/integration.legacy.ts delete mode 100644 apps/server/src/services/Clock.ts delete mode 100644 apps/server/src/services/rundown-service/__tests__/rundownUtils.test.ts delete mode 100644 apps/server/src/utils/removeFileExtension.ts diff --git a/apps/client/src/common/api/constants.ts b/apps/client/src/common/api/constants.ts index 52f281211..a5968445c 100644 --- a/apps/client/src/common/api/constants.ts +++ b/apps/client/src/common/api/constants.ts @@ -10,7 +10,6 @@ export const PROJECT_DATA = ['project']; export const PROJECT_LIST = ['projectList']; export const RUNDOWN = ['rundown']; export const RUNTIME = ['runtimeStore']; -export const SHEET_STATE = ['sheetState']; export const URL_PRESETS = ['urlpresets']; export const VIEW_SETTINGS = ['viewSettings']; export const CLIENT_LIST = ['clientList']; @@ -19,11 +18,8 @@ export const REPORT = ['report']; // API URLs export const apiEntryUrl = `${serverURL}/data`; -export const projectDataURL = `${serverURL}/project`; -export const rundownURL = `${serverURL}/events`; -export const ontimeURL = `${serverURL}/ontime`; +const userAssetsPath = 'user'; +const cssOverridePath = 'styles/override.css'; -export const userAssetsPath = 'user'; -export const cssOverridePath = 'styles/override.css'; export const overrideStylesURL = `${serverURL}/${userAssetsPath}/${cssOverridePath}`; export const projectLogoPath = `${serverURL}/${userAssetsPath}/logo`; diff --git a/apps/client/src/common/components/context-menu/ContextMenu.tsx b/apps/client/src/common/components/context-menu/ContextMenu.tsx index 3ed5a842a..331532ee4 100644 --- a/apps/client/src/common/components/context-menu/ContextMenu.tsx +++ b/apps/client/src/common/components/context-menu/ContextMenu.tsx @@ -23,7 +23,7 @@ export type OptionWithoutGroup = { withDivider?: boolean; }; -export type OptionWithGroup = { +type OptionWithGroup = { label: string; group: Omit[]; }; diff --git a/apps/client/src/common/components/error-boundary/ErrorBoundary.jsx b/apps/client/src/common/components/error-boundary/ErrorBoundary.jsx index f0d3e9477..0cf4d228e 100644 --- a/apps/client/src/common/components/error-boundary/ErrorBoundary.jsx +++ b/apps/client/src/common/components/error-boundary/ErrorBoundary.jsx @@ -3,8 +3,8 @@ import React from 'react'; // skipcq: JS-C1003 - sentry does not expose itself as an ES Module. import * as Sentry from '@sentry/react'; -import { runtimeStore } from '@/common/stores/runtime'; -import { hasConnected, reconnectAttempts, shouldReconnect } from '@/common/utils/socket'; +import { hasConnected, reconnectAttempts } from '../../../common/utils/socket'; +import { runtimeStore } from '../../stores/runtime'; import style from './ErrorBoundary.module.scss'; @@ -37,7 +37,7 @@ class ErrorBoundary extends React.Component { scope.setExtras({ error, store: appState, - hasSocket: { hasConnected, shouldReconnect, reconnectAttempts }, + hasSocket: { hasConnected, reconnectAttempts }, }); const eventId = Sentry.captureException(error); this.setState({ eventId, info }); diff --git a/apps/client/src/common/components/loader-overlay/LoaderOverlay.module.scss b/apps/client/src/common/components/loader-overlay/LoaderOverlay.module.scss deleted file mode 100644 index 074e32f2f..000000000 --- a/apps/client/src/common/components/loader-overlay/LoaderOverlay.module.scss +++ /dev/null @@ -1,45 +0,0 @@ -$loader-size: 4rem; - -.overlay { - position: absolute; - z-index: 10; - width: 100%; - height: 100%; - display: grid; - place-content: center; - background-color: $black-10; - backdrop-filter: blur(5px); -} - - -.loader { - width: $loader-size; - height: $loader-size; - background: $blue-500; - display: inline-block; - border-radius: 50%; - box-sizing: border-box; - animation: animloader 1s ease-in infinite; -} - -@keyframes animloader { - 0% { - transform: scale(0); - opacity: 0.6; - } - 100% { - transform: scale(1); - opacity: 0; - } -} - -@keyframes animloader { - 0% { - transform: scale(0); - opacity: 0.6; - } - 100% { - transform: scale(1); - opacity: 0; - } -} diff --git a/apps/client/src/common/components/loader-overlay/LoaderOverlay.tsx b/apps/client/src/common/components/loader-overlay/LoaderOverlay.tsx deleted file mode 100644 index bc77a2814..000000000 --- a/apps/client/src/common/components/loader-overlay/LoaderOverlay.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import style from './LoaderOverlay.module.scss'; - -export default function LoaderOverlay() { - return ( -
- -
- ); -} diff --git a/apps/client/src/common/components/navigation-menu/ProductionNavigationMenu.tsx b/apps/client/src/common/components/navigation-menu/ProductionNavigationMenu.tsx deleted file mode 100644 index 2841ba069..000000000 --- a/apps/client/src/common/components/navigation-menu/ProductionNavigationMenu.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { memo } from 'react'; - -import NavigationMenu from './NavigationMenu'; - -interface ProductionNavigationMenuProps { - isMenuOpen: boolean; - onMenuClose: () => void; -} - -function ProductionNavigationMenu(props: ProductionNavigationMenuProps) { - const { isMenuOpen, onMenuClose } = props; - - return ; -} - -export default memo(ProductionNavigationMenu); diff --git a/apps/client/src/common/components/view-params-editor/types.ts b/apps/client/src/common/components/view-params-editor/types.ts index 51d8a2ad1..84ab3ff68 100644 --- a/apps/client/src/common/components/view-params-editor/types.ts +++ b/apps/client/src/common/components/view-params-editor/types.ts @@ -12,7 +12,7 @@ type OptionsField = { defaultValue?: string; }; -export type MultiselectOption = { value: string; label: string; colour: string }; +type MultiselectOption = { value: string; label: string; colour: string }; export type MultiselectOptions = Record; type MultiOptionsField = { type: 'multi-option'; diff --git a/apps/client/src/common/context/useMediaQuery.ts b/apps/client/src/common/context/useMediaQuery.ts deleted file mode 100644 index e2d282529..000000000 --- a/apps/client/src/common/context/useMediaQuery.ts +++ /dev/null @@ -1,32 +0,0 @@ -// roughly from https://github.com/juliencrn/usehooks-ts/blob/master/packages/usehooks-ts/src/useMediaQuery/useMediaQuery.ts - -import { useCallback, useEffect, useState } from 'react'; - -function getMatches(query: string): boolean { - return window.matchMedia(query).matches; -} - -// TODO: debounce handleChange -export default function useMediaQuery(query: string): boolean { - const [matches, setMatches] = useState(getMatches(query)); - - const handleChange = useCallback(() => { - setMatches(getMatches(query)); - }, [query]); - - useEffect(() => { - const matchMedia = window.matchMedia(query); - - // Triggered at the first client-side load and if query changes - handleChange(); - - // Listen matchMedia - matchMedia.addEventListener('change', handleChange); - - return () => { - matchMedia.removeEventListener('change', handleChange); - }; - }, [handleChange, query]); - - return matches; -} diff --git a/apps/client/src/common/hooks-query/useAutomationSettings.ts b/apps/client/src/common/hooks-query/useAutomationSettings.ts index 60fffa64b..18d9f81ab 100644 --- a/apps/client/src/common/hooks-query/useAutomationSettings.ts +++ b/apps/client/src/common/hooks-query/useAutomationSettings.ts @@ -1,11 +1,9 @@ -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { queryRefetchIntervalSlow } from '../../ontimeConfig'; -import { editAutomationSettings, getAutomationSettings } from '../api/automation'; +import { getAutomationSettings } from '../api/automation'; import { AUTOMATION } from '../api/constants'; -import { logAxiosError } from '../api/utils'; import { automationPlaceholderSettings } from '../models/AutomationSettings'; -import { ontimeQueryClient } from '../queryClient'; export default function useAutomationSettings() { const { data, status, isFetching, isError, refetch } = useQuery({ @@ -20,15 +18,3 @@ export default function useAutomationSettings() { return { data: data ?? automationPlaceholderSettings, status, isFetching, isError, refetch }; } - -export function useAutomationSettingsMutation() { - const { isPending, mutateAsync } = useMutation({ - mutationFn: editAutomationSettings, - onError: (error) => logAxiosError('Error saving Automation settings', error), - onSuccess: (data) => { - ontimeQueryClient.setQueryData(AUTOMATION, data); - }, - onSettled: () => ontimeQueryClient.invalidateQueries({ queryKey: AUTOMATION }), - }); - return { isPending, mutateAsync }; -} diff --git a/apps/client/src/common/hooks-query/useProjectList.ts b/apps/client/src/common/hooks-query/useProjectList.ts index 57d3b6f01..329bba44b 100644 --- a/apps/client/src/common/hooks-query/useProjectList.ts +++ b/apps/client/src/common/hooks-query/useProjectList.ts @@ -11,7 +11,7 @@ const placeholderProjectList: ProjectFileListResponse = { lastLoadedProject: '', }; -export function useProjectList() { +function useProjectList() { const { data, status, refetch } = useQuery({ queryKey: PROJECT_LIST, queryFn: getProjects, diff --git a/apps/client/src/common/hooks/useMemoisedFn.ts b/apps/client/src/common/hooks/useMemoisedFn.ts index 179c00e0c..b1a1545b5 100644 --- a/apps/client/src/common/hooks/useMemoisedFn.ts +++ b/apps/client/src/common/hooks/useMemoisedFn.ts @@ -12,7 +12,7 @@ type noop = (this: any, ...args: any[]) => any; type PickFunction = (this: ThisParameterType, ...args: Parameters) => ReturnType; -export const isFunction = (value: unknown): value is (...args: any) => any => typeof value === 'function'; +const isFunction = (value: unknown): value is (...args: any) => any => typeof value === 'function'; export default function useMemoisedFn(fn: T) { if (isDev) { diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index e4cab2010..c71befc99 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -91,14 +91,6 @@ export const setPlayback = { }, }; -export const useInfoPanel = createSelector((state: RuntimeStore) => ({ - eventNow: state.eventNow, - eventNext: state.eventNext, - playback: state.timer.playback, - selectedEventIndex: state.runtime.selectedEventIndex, - numEvents: state.runtime.numEvents, -})); - export const useAuxTimerTime = createSelector((state: RuntimeStore) => state.auxtimer1.current); export const useAuxTimerControl = createSelector((state: RuntimeStore) => ({ @@ -145,8 +137,6 @@ export const useProgressData = createSelector((state: RuntimeStore) => ({ timeDanger: state.eventNow?.timeDanger ?? null, })); -export const setClientName = (newName: string) => socketSendJson('set-client-name', newName); - export const useRuntimeOverview = createSelector((state: RuntimeStore) => ({ plannedStart: state.runtime.plannedStart, actualStart: state.runtime.actualStart, diff --git a/apps/client/src/common/stores/logger.ts b/apps/client/src/common/stores/logger.ts index fb60d07c4..3e919cf46 100644 --- a/apps/client/src/common/stores/logger.ts +++ b/apps/client/src/common/stores/logger.ts @@ -11,7 +11,7 @@ type LogStore = { logs: Log[]; }; -export const logger = createStore(() => ({ +const logger = createStore(() => ({ logs: [], })); diff --git a/apps/client/src/common/utils/socket.ts b/apps/client/src/common/utils/socket.ts index 5358ee78e..1de34adcf 100644 --- a/apps/client/src/common/utils/socket.ts +++ b/apps/client/src/common/utils/socket.ts @@ -16,11 +16,10 @@ import { addDialog } from '../stores/dialogStore'; import { addLog } from '../stores/logger'; import { addToBatchUpdates, flushBatchUpdates, patchRuntime, patchRuntimeProperty } from '../stores/runtime'; -export let websocket: WebSocket | null = null; +let websocket: WebSocket | null = null; let reconnectTimeout: NodeJS.Timeout | null = null; const reconnectInterval = 1000; -export let shouldReconnect = true; export let hasConnected = false; export let reconnectAttempts = 0; @@ -50,15 +49,14 @@ export const connectSocket = () => { console.warn('WebSocket disconnected'); setOnlineStatus(false); - if (shouldReconnect) { - reconnectTimeout = setTimeout(() => { - console.warn('WebSocket: attempting reconnect'); - if (websocket && websocket.readyState === WebSocket.CLOSED) { - reconnectAttempts += 1; - connectSocket(); - } - }, reconnectInterval); - } + // we decide to allows reconnect + reconnectTimeout = setTimeout(() => { + console.warn('WebSocket: attempting reconnect'); + if (websocket && websocket.readyState === WebSocket.CLOSED) { + reconnectAttempts += 1; + connectSocket(); + } + }, reconnectInterval); }; websocket.onerror = (error) => { @@ -224,11 +222,6 @@ export const connectSocket = () => { }; }; -export const disconnectSocket = () => { - shouldReconnect = false; - websocket?.close(); -}; - export const socketSend = (message: any) => { if (websocket && websocket.readyState === WebSocket.OPEN) { websocket.send(message); diff --git a/apps/client/src/common/utils/time.ts b/apps/client/src/common/utils/time.ts index 4c5ee9ed7..9918ec9df 100644 --- a/apps/client/src/common/utils/time.ts +++ b/apps/client/src/common/utils/time.ts @@ -35,7 +35,7 @@ function getFormatFromParams() { * Gets the format options from the applicaton settings * @returns a string equivalent to the format, ie: hh:mm:ss a or HH:mm:ss */ -export function getFormatFromSettings(): TimeFormat { +function getFormatFromSettings(): TimeFormat { const settings: Settings | undefined = ontimeQueryClient.getQueryData(APP_SETTINGS); return settings?.timeFormat ?? '24'; } diff --git a/apps/client/src/declarations/test.d.ts b/apps/client/src/declarations/test.d.ts deleted file mode 100644 index bf28ed90f..000000000 --- a/apps/client/src/declarations/test.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { TestingLibraryMatchers } from '@testing-library/jest-dom/matchers'; - -import 'vitest'; - -// ugly hack because vite and pnpm are not playing ball with jest -// https://github.com/testing-library/jest-dom/issues/123 -declare global { - namespace Vi { - type Assertion = TestingLibraryMatchers; - } -} diff --git a/apps/client/src/features/app-settings/panel/general-panel/GeneralPanelForm.tsx b/apps/client/src/features/app-settings/panel/general-panel/GeneralPanelForm.tsx index 47fca788c..e041094c1 100644 --- a/apps/client/src/features/app-settings/panel/general-panel/GeneralPanelForm.tsx +++ b/apps/client/src/features/app-settings/panel/general-panel/GeneralPanelForm.tsx @@ -13,10 +13,6 @@ import * as Panel from '../../panel-utils/PanelUtils'; import GeneralPinInput from './GeneralPinInput'; -export type GeneralPanelFormValues = { - filename: string; -}; - export default function GeneralPanelForm() { const { data, status, refetch } = useSettings(); const { diff --git a/apps/client/src/features/app-settings/panel/sources-panel/import-map/importMapUtils.ts b/apps/client/src/features/app-settings/panel/sources-panel/import-map/importMapUtils.ts index 0f786355f..3a1d4c48f 100644 --- a/apps/client/src/features/app-settings/panel/sources-panel/import-map/importMapUtils.ts +++ b/apps/client/src/features/app-settings/panel/sources-panel/import-map/importMapUtils.ts @@ -3,7 +3,7 @@ import { ImportCustom, ImportMap } from 'ontime-utils'; export type NamedImportMap = typeof namedImportMap; // Record of label and import name -export const namedImportMap = { +const namedImportMap = { Worksheet: 'event schedule', Start: 'time start', 'Link start': 'link start', diff --git a/apps/client/src/features/rundown/event-editor/EventEditor.tsx b/apps/client/src/features/rundown/event-editor/EventEditor.tsx index 4e4a3558e..3c0306ce5 100644 --- a/apps/client/src/features/rundown/event-editor/EventEditor.tsx +++ b/apps/client/src/features/rundown/event-editor/EventEditor.tsx @@ -16,8 +16,6 @@ import EventEditorEmpty from './EventEditorEmpty'; import style from './EventEditor.module.scss'; -export type EventEditorSubmitActions = keyof OntimeEvent; - export type EditorUpdateFields = 'cue' | 'title' | 'note' | 'colour' | CustomFieldLabel; interface EventEditorProps { diff --git a/apps/client/src/features/rundown/useEventSelection.ts b/apps/client/src/features/rundown/useEventSelection.ts index 8602a859c..d286abb71 100644 --- a/apps/client/src/features/rundown/useEventSelection.ts +++ b/apps/client/src/features/rundown/useEventSelection.ts @@ -6,7 +6,7 @@ import { RUNDOWN } from '../../common/api/constants'; import { ontimeQueryClient } from '../../common/queryClient'; import { isMacOS } from '../../common/utils/deviceUtils'; -export type SelectionMode = 'shift' | 'click' | 'ctrl'; +type SelectionMode = 'shift' | 'click' | 'ctrl'; interface EventSelectionStore { selectedEvents: Set; diff --git a/apps/client/src/features/viewers/common/animation.ts b/apps/client/src/features/viewers/common/animation.ts deleted file mode 100644 index cbc9c6621..000000000 --- a/apps/client/src/features/viewers/common/animation.ts +++ /dev/null @@ -1,15 +0,0 @@ -// used in both sm and public views -export const titleVariants = { - hidden: { - x: -1500, - }, - visible: { - x: 0, - transition: { - duration: 1, - }, - }, - exit: { - x: -1500, - }, -}; diff --git a/apps/client/src/translation/TranslationProvider.tsx b/apps/client/src/translation/TranslationProvider.tsx index 7aa37cb01..ca0d471ad 100644 --- a/apps/client/src/translation/TranslationProvider.tsx +++ b/apps/client/src/translation/TranslationProvider.tsx @@ -32,7 +32,7 @@ interface TranslationContextValue { getLocalizedString: (key: keyof typeof langEn, lang?: string) => string; } -export const TranslationContext = createContext({ +const TranslationContext = createContext({ getLocalizedString: () => '', }); diff --git a/apps/client/src/views/timeline/timeline-section/TimelineSection.tsx b/apps/client/src/views/timeline/timeline-section/TimelineSection.tsx index 1e01f98f3..2bdeac5ad 100644 --- a/apps/client/src/views/timeline/timeline-section/TimelineSection.tsx +++ b/apps/client/src/views/timeline/timeline-section/TimelineSection.tsx @@ -12,7 +12,7 @@ interface SectionProps { export default memo(Section); -export function Section(props: SectionProps) { +function Section(props: SectionProps) { const { category, content, title, status } = props; const sectionClasses = cx(['section', category === 'now' && 'section--now']); diff --git a/apps/client/src/views/timeline/timeline.utils.ts b/apps/client/src/views/timeline/timeline.utils.ts index c361d5111..fd43ffd2e 100644 --- a/apps/client/src/views/timeline/timeline.utils.ts +++ b/apps/client/src/views/timeline/timeline.utils.ts @@ -11,7 +11,6 @@ import { MILLIS_PER_HOUR, } from 'ontime-utils'; -import { clamp } from '../../common/utils/math'; import { formatDuration } from '../../common/utils/time'; import { isStringBoolean } from '../../features/viewers/common/viewUtils'; @@ -22,13 +21,6 @@ type CSSPosition = { width: number; }; -/** - * Calculates the position (in %) of an element relative to a schedule - */ -export function getRelativePositionX(scheduleStart: number, scheduleEnd: number, now: number): number { - return clamp(((now - scheduleStart) / (scheduleEnd - scheduleStart)) * 100, 0, 100); -} - /** * Calculates an absolute position of an element based on a schedule */ diff --git a/apps/server/src/adapters/WebsocketAdapter.ts b/apps/server/src/adapters/WebsocketAdapter.ts index 5e16796dd..849c0884a 100644 --- a/apps/server/src/adapters/WebsocketAdapter.ts +++ b/apps/server/src/adapters/WebsocketAdapter.ts @@ -29,7 +29,7 @@ import { authenticateSocket } from '../middleware/authenticate.js'; let instance: SocketServer | null = null; -export class SocketServer implements IAdapter { +class SocketServer implements IAdapter { private readonly MAX_PAYLOAD = 1024 * 256; // 256Kb private wss: WebSocketServer | null; diff --git a/apps/server/src/api-data/excel/excel.router.ts b/apps/server/src/api-data/excel/excel.router.ts index 799396276..5e8541af6 100644 --- a/apps/server/src/api-data/excel/excel.router.ts +++ b/apps/server/src/api-data/excel/excel.router.ts @@ -12,5 +12,3 @@ export const router = express.Router(); router.post('/upload', uploadExcel, validateFileExists, postExcel); router.get('/worksheets', getWorksheets); router.post('/preview', validateImportMapOptions, previewExcel); - -// TODO: validate import map diff --git a/apps/server/src/api-data/rundown/rundown.controller.ts b/apps/server/src/api-data/rundown/rundown.controller.ts index 3575ebc51..f40ab53b6 100644 --- a/apps/server/src/api-data/rundown/rundown.controller.ts +++ b/apps/server/src/api-data/rundown/rundown.controller.ts @@ -1,11 +1,4 @@ -import { - ErrorResponse, - MessageResponse, - OntimeRundown, - OntimeRundownEntry, - RundownCached, - RundownPaginated, -} from 'ontime-types'; +import { ErrorResponse, MessageResponse, OntimeRundown, OntimeRundownEntry, RundownCached } from 'ontime-types'; import { getErrorMessage } from 'ontime-utils'; import type { Request, Response } from 'express'; @@ -21,12 +14,7 @@ import { reorderEvent, swapEvents, } from '../../services/rundown-service/RundownService.js'; -import { - getEventWithId, - getNormalisedRundown, - getPaginated, - getRundown, -} from '../../services/rundown-service/rundownUtils.js'; +import { getEventWithId, getNormalisedRundown, getRundown } from '../../services/rundown-service/rundownUtils.js'; export async function rundownGetAll(_req: Request, res: Response) { const rundown = getRundown(); @@ -55,34 +43,6 @@ export async function rundownGetById(req: Request, res: Response) { - const { limit, offset } = req.query; - - if (limit == null && offset == null) { - return res.json({ - rundown: getRundown(), - total: getRundown().length, - }); - } - - try { - let parsedOffset = Number(offset); - if (Number.isNaN(parsedOffset)) { - parsedOffset = 0; - } - let parsedLimit = Number(limit); - if (Number.isNaN(parsedLimit)) { - parsedLimit = Infinity; - } - const paginatedRundown = getPaginated(parsedOffset, parsedLimit); - - res.status(200).json(paginatedRundown); - } catch (error) { - const message = getErrorMessage(error); - res.status(400).json({ message }); - } -} - export async function rundownPost(req: Request, res: Response) { if (failEmptyObjects(req.body, res)) { return; diff --git a/apps/server/src/api-data/rundown/rundown.router.ts b/apps/server/src/api-data/rundown/rundown.router.ts index ebac101cb..38b6cd15a 100644 --- a/apps/server/src/api-data/rundown/rundown.router.ts +++ b/apps/server/src/api-data/rundown/rundown.router.ts @@ -8,7 +8,6 @@ import { rundownGetAll, rundownGetById, rundownGetNormalised, - rundownGetPaginated, rundownPost, rundownPut, rundownReorder, @@ -18,7 +17,6 @@ import { paramsMustHaveEventId, rundownArrayOfIds, rundownBatchPutValidator, - rundownGetPaginatedQueryParams, rundownPostValidator, rundownPutValidator, rundownReorderValidator, @@ -28,7 +26,6 @@ import { export const router = express.Router(); router.get('/', rundownGetAll); // not used in Ontime frontend -router.get('/paginated', rundownGetPaginatedQueryParams, rundownGetPaginated); // not used in Ontime frontend router.get('/normalised', rundownGetNormalised); router.get('/:eventId', paramsMustHaveEventId, rundownGetById); // not used in Ontime frontend diff --git a/apps/server/src/api-data/rundown/rundown.validation.ts b/apps/server/src/api-data/rundown/rundown.validation.ts index d815bb576..1f6c1b17a 100644 --- a/apps/server/src/api-data/rundown/rundown.validation.ts +++ b/apps/server/src/api-data/rundown/rundown.validation.ts @@ -1,4 +1,4 @@ -import { body, param, query, validationResult } from 'express-validator'; +import { body, param, validationResult } from 'express-validator'; import type { Request, Response, NextFunction } from 'express'; export const rundownPostValidator = [ @@ -77,14 +77,3 @@ export const rundownArrayOfIds = [ next(); }, ]; - -export const rundownGetPaginatedQueryParams = [ - query('offset').isNumeric().optional(), - query('limit').isNumeric().optional(), - - (req: Request, res: Response, next: NextFunction) => { - const errors = validationResult(req); - if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() }); - next(); - }, -]; diff --git a/apps/server/src/api-integration/__tests__/integration.legacy.test.ts b/apps/server/src/api-integration/__tests__/integration.legacy.test.ts deleted file mode 100644 index 6dd81fa28..000000000 --- a/apps/server/src/api-integration/__tests__/integration.legacy.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { handleLegacyMessageConversion } from '../integration.legacy.js'; - -describe('handleLegacyConversion', () => { - it('should return the payload as is if it is not a legacy message', () => { - expect(handleLegacyMessageConversion({})).toEqual({}); - const newPayload = { - timer: { - text: 'text', - visible: true, - blink: true, - blackout: true, - }, - external: 'text', - }; - expect(handleLegacyMessageConversion(newPayload)).toEqual(newPayload); - }); - - it('should convert a legacy payload with external message', () => { - expect(handleLegacyMessageConversion({ external: { text: 'text', visible: true } })).toEqual({ - external: 'text', - timer: { - secondarySource: 'external', - }, - }); - - expect(handleLegacyMessageConversion({ external: { visible: true } })).toEqual({ - timer: { - secondarySource: 'external', - }, - }); - - expect(handleLegacyMessageConversion({ external: { text: 'text' } })).toEqual({ - external: 'text', - }); - }); -}); diff --git a/apps/server/src/api-integration/integration.controller.ts b/apps/server/src/api-integration/integration.controller.ts index ded76835e..10e7b4ebc 100644 --- a/apps/server/src/api-integration/integration.controller.ts +++ b/apps/server/src/api-integration/integration.controller.ts @@ -16,8 +16,6 @@ import { socket } from '../adapters/WebsocketAdapter.js'; import { throttle } from '../utils/throttle.js'; import { willCauseRegeneration } from '../services/rundown-service/rundownCacheUtils.js'; -import { handleLegacyMessageConversion } from './integration.legacy.js'; - const throttledUpdateEvent = throttle(updateEvent, 20); let lastRequest: Date | null = null; @@ -89,12 +87,9 @@ const actionHandlers: Record = { message: (payload) => { assert.isObject(payload); - // TODO: remove this once we feel its been enough time, ontime 3.6.0, 20/09/2024 - const migratedPayload = handleLegacyMessageConversion(payload); - const patch: DeepPartial = { - timer: 'timer' in migratedPayload ? validateTimerMessage(migratedPayload.timer) : undefined, - external: 'external' in migratedPayload ? validateMessage(migratedPayload.external) : undefined, + timer: 'timer' in payload ? validateTimerMessage(payload.timer) : undefined, + external: 'external' in payload ? validateMessage(payload.external) : undefined, }; const newMessage = messageService.patch(patch); diff --git a/apps/server/src/api-integration/integration.legacy.ts b/apps/server/src/api-integration/integration.legacy.ts deleted file mode 100644 index d24a58080..000000000 --- a/apps/server/src/api-integration/integration.legacy.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { MessageState } from 'ontime-types'; -import { DeepPartial } from 'ts-essentials'; - -export type LegacyMessageState = DeepPartial<{ - timer: { - text: string; - visible: boolean; - blink: boolean; - blackout: boolean; - }; - external: { - text: string; - visible: boolean; - }; -}>; - -function isLegacyMessageState(value: object): value is LegacyMessageState { - // @ts-expect-error -- good enough here - return value?.external?.text !== undefined || value?.external?.visible !== undefined; -} - -/** - * This function is used to maintain support for legacy data in the /message endpoint - * The previous message endpoint expected a patch of the message state - * @example { - * timer: { blink: boolean, blackout: boolean, text: string, visible: boolean }, - * external: { visible: boolean, text: string } - * } - * - * This change is introduced in version 3.6.0 - */ -export function handleLegacyMessageConversion(payload: object): object | Partial { - // if it is not a legacy message, we pass it as is - if (!isLegacyMessageState(payload)) { - return payload; - } - - /** - * The current migration only needs to handle the cases - * for the deprecated external message controls - */ - - // Migrate external message - // 2.1 the user gives us the text and a visible flag - if (payload?.external?.text !== undefined && payload.external.visible !== undefined) { - return { - timer: { secondarySource: payload.external.visible ? 'external' : null }, - external: payload.external.text, - } as Partial; - } - // 2.2 the user gives us the text - else if (payload?.external?.text !== undefined) { - return { - external: payload.external.text, - } as Partial; - } - // 2.3 the user gives us the visible flag - else if (payload?.external?.visible !== undefined) { - return { - timer: { secondarySource: payload.external.visible ? 'external' : null }, - } as Partial; - } - - // there should be no case for us to reach this since - // the type guard would have ensured one of the above states - return payload; -} diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 5dda9aa1e..1055e3a1e 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -245,7 +245,7 @@ export const startIntegrations = async () => { * @param {number} exitCode * @return {Promise} */ -export const shutdown = async (exitCode = 0) => { +const shutdown = async (exitCode = 0) => { consoleHighlight(`Ontime shutting down with code ${exitCode}`); // clear the restore file if it was a normal exit diff --git a/apps/server/src/classes/Logger.ts b/apps/server/src/classes/Logger.ts index 5c21d77e0..27cb734f3 100644 --- a/apps/server/src/classes/Logger.ts +++ b/apps/server/src/classes/Logger.ts @@ -1,9 +1,9 @@ import { Log, LogLevel } from 'ontime-types'; import { generateId, millisToString } from 'ontime-utils'; -import { clock } from '../services/Clock.js'; import { socket } from '../adapters/WebsocketAdapter.js'; import { consoleSubdued, consoleError } from '../utils/console.js'; +import { timeNow } from '../utils/time.js'; import { isProduction } from '../externals.js'; class Logger { @@ -75,7 +75,7 @@ class Logger { level, origin, text, - time: millisToString(clock.getSystemTime() || 0), + time: millisToString(timeNow()), }; this._push(log); } diff --git a/apps/server/src/services/Clock.ts b/apps/server/src/services/Clock.ts deleted file mode 100644 index c19bad194..000000000 --- a/apps/server/src/services/Clock.ts +++ /dev/null @@ -1,60 +0,0 @@ -enum Source { - System = 'system', - MIDI = 'MIDI', -} - -/** - * Service manages retrieving current time from a managed time source - */ -class Clock { - private static instance: Clock; - private readonly source: Source; - - constructor(source?: Source) { - if (Clock.instance) { - return Clock.instance; - } - - Clock.instance = this; - - this.source = source || Source.System; - } - - /** - * Get current time from source - */ - timeNow(): number { - switch (this.source) { - case Source.System: - return this.getSystemTime(); - case Source.MIDI: - // @ts-expect-error -- not implemented - return this.getMidiTime(); - default: - throw new Error('Invalid time source'); - } - } - - /** - * Get current time from system - */ - getSystemTime() { - const now = new Date(); - - // extract milliseconds since midnight - let elapsed = now.getHours() * 3600000; - elapsed += now.getMinutes() * 60000; - elapsed += now.getSeconds() * 1000; - elapsed += now.getMilliseconds(); - return elapsed; - } - - /** - * Get current time from MIDI - */ - getMidiTime() { - throw new Error('Not implemented'); - } -} - -export const clock = new Clock(); diff --git a/apps/server/src/services/aux-timer-service/AuxTimerService.ts b/apps/server/src/services/aux-timer-service/AuxTimerService.ts index e0b4c59e5..7b04ae4f7 100644 --- a/apps/server/src/services/aux-timer-service/AuxTimerService.ts +++ b/apps/server/src/services/aux-timer-service/AuxTimerService.ts @@ -4,8 +4,8 @@ import { SimpleTimer } from '../../classes/simple-timer/SimpleTimer.js'; import { eventStore } from '../../stores/EventStore.js'; import { timerConfig } from '../../config/config.js'; -export type EmitFn = (state: SimpleTimerState) => void; -export type GetTimeFn = () => number; +type EmitFn = (state: SimpleTimerState) => void; +type GetTimeFn = () => number; export class AuxTimerService { private timer: SimpleTimer; diff --git a/apps/server/src/services/rundown-service/__tests__/rundownCache.test.ts b/apps/server/src/services/rundown-service/__tests__/rundownCache.test.ts index 3e9684587..ce4dbec6a 100644 --- a/apps/server/src/services/rundown-service/__tests__/rundownCache.test.ts +++ b/apps/server/src/services/rundown-service/__tests__/rundownCache.test.ts @@ -1,6 +1,5 @@ import { CustomFields, - EndAction, EventCustomFields, OntimeBlock, OntimeDelay, @@ -8,11 +7,9 @@ import { OntimeRundown, SupportedEvent, TimeStrategy, - TimerType, } from 'ontime-types'; import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, dayInMs } from 'ontime-utils'; -import { calculateRuntimeDelays, getDelayAt, calculateRuntimeDelaysFrom } from '../delayUtils.js'; import { add, batchEdit, @@ -557,410 +554,6 @@ describe('swap() mutation', () => { }); }); -describe('calculateRuntimeDelays', () => { - it('calculates all delays in a given rundown', () => { - const rundown: OntimeRundown = [ - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 600000, - timeEnd: 1200000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '659e1', - cue: '1', - custom: {}, - }, - { - duration: 600000, - type: SupportedEvent.Delay, - id: '07986', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 1200000, - timeEnd: 1200000, - duration: 0, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '1c48f', - cue: '2', - custom: {}, - }, - { - duration: 1200000, - type: SupportedEvent.Delay, - id: '7db42', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 600000, - timeEnd: 1200000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: 'd48c2', - cue: '3', - custom: {}, - }, - { - title: '', - type: SupportedEvent.Block, - id: '9870d', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 1200000, - timeEnd: 1800000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '2f185', - cue: '4', - custom: {}, - }, - ]; - - const updatedRundown = calculateRuntimeDelays(rundown); - - expect(rundown.length).toBe(updatedRundown.length); - expect((updatedRundown[0] as OntimeEvent).delay).toBe(0); - expect((updatedRundown[2] as OntimeEvent).delay).toBe(600000); - expect((updatedRundown[4] as OntimeEvent).delay).toBe(600000 + 1200000); - expect((updatedRundown[6] as OntimeEvent).delay).toBe(0); - }); -}); - -describe('getDelayAt()', () => { - const delayedRundown: OntimeRundown = [ - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 600000, - timeEnd: 1200000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '659e1', - delay: 0, - dayOffset: 0, - gap: 0, - cue: '1', - custom: {}, - }, - { - duration: 600000, - type: SupportedEvent.Delay, - id: '07986', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 1200000, - timeEnd: 1200000, - duration: 0, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '1c48f', - delay: 600000, - cue: '2', - custom: {}, - }, - { - duration: 1200000, - type: SupportedEvent.Delay, - id: '7db42', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 600000, - timeEnd: 1200000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: 'd48c2', - delay: 1800000, - cue: '3', - custom: {}, - }, - { - title: '', - type: SupportedEvent.Block, - id: '9870d', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 1200000, - timeEnd: 1800000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '2f185', - delay: 0, - cue: '4', - custom: {}, - }, - ]; - - it('calculates delay in a rundown', () => { - const delayAtStart = getDelayAt(0, delayedRundown); - const delayOnFirstEvent = getDelayAt(2, delayedRundown); - const delayOnSecondEvent = getDelayAt(4, delayedRundown); - const delayOnBlockedEvent = getDelayAt(0, delayedRundown); - - expect(delayAtStart).toBe(0); - expect(delayOnFirstEvent).toBe(600000); - expect(delayOnSecondEvent).toBe(600000 + 1200000); - expect(delayOnBlockedEvent).toBe(0); - }); - it('finds delay before a delay block', () => { - const valueOnFirstDelayBlock = getDelayAt(1, delayedRundown); - const valueOnSecondDelayBlock = getDelayAt(3, delayedRundown); - const valueAfterSecondDelayBlock = getDelayAt(4, delayedRundown); - - expect(valueOnFirstDelayBlock).toBe(0); - expect(valueOnSecondDelayBlock).toBe(600000); - expect(valueAfterSecondDelayBlock).toBe(600000 + 1200000); - }); - it('returns 0 after blocks', () => { - const valueOnBlock = getDelayAt(6, delayedRundown); - expect(valueOnBlock).toBe(0); - }); -}); - -describe('calculateRuntimeDelaysFrom()', () => { - it('updates delays from given id', () => { - const delayedRundown: OntimeRundown = [ - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 600000, - timeEnd: 1200000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '659e1', - delay: 0, - cue: '1', - custom: {}, - }, - { - duration: 600000, - type: SupportedEvent.Delay, - id: '07986', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 1200000, - timeEnd: 1200000, - duration: 0, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '1c48f', - delay: 0, - cue: '2', - custom: {}, - }, - { - duration: 1200000, - type: SupportedEvent.Delay, - id: '7db42', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 600000, - timeEnd: 1200000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: 'd48c2', - delay: 1800000, - cue: '3', - custom: {}, - }, - { - title: '', - type: SupportedEvent.Block, - id: '9870d', - }, - { - title: '', - note: '', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - timeStrategy: TimeStrategy.LockEnd, - linkStart: null, - timeStart: 1200000, - timeEnd: 1800000, - duration: 600000, - isPublic: true, - skip: false, - colour: '', - type: SupportedEvent.Event, - revision: 0, - dayOffset: 0, - gap: 0, - timeWarning: 120000, - timeDanger: 60000, - id: '2f185', - delay: 0, - cue: '4', - custom: {}, - }, - ]; - - const updatedRundown = calculateRuntimeDelaysFrom('07986', delayedRundown); - - // we only update from the 4th on - expect((updatedRundown[0] as OntimeEvent).delay).toBe(0); - // 1 + 3 - expect((updatedRundown[4] as OntimeEvent).delay).toBe(600000 + 1200000); - }); -}); - describe('custom fields', () => { describe('createCustomField()', () => { it('creates a field from given parameters', () => { diff --git a/apps/server/src/services/rundown-service/__tests__/rundownUtils.test.ts b/apps/server/src/services/rundown-service/__tests__/rundownUtils.test.ts deleted file mode 100644 index e917d8f6a..000000000 --- a/apps/server/src/services/rundown-service/__tests__/rundownUtils.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { OntimeRundown } from 'ontime-types'; -import { getPaginated } from '../rundownUtils.js'; - -describe('getPaginated', () => { - // mock cache so we dont run data functions - beforeAll(() => { - vi.mock('../rundownCache.js', () => ({})); - }); - - // @ts-expect-error -- we know this is not correct, but good enough for the test - const getData = () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as OntimeRundown; - - it('should return the correct paginated rundown', () => { - const offset = 0; - const limit = 1; - const result = getPaginated(offset, limit, getData); - - expect(result.rundown).toHaveLength(1); - expect(result.total).toBe(10); - }); - - it('should handle overflows', () => { - const offset = 0; - const limit = 20; - const result = getPaginated(offset, limit, getData); - - expect(result.rundown).toHaveLength(10); - expect(result.total).toBe(10); - }); - - it('should handle out of range', () => { - const offset = 11; - const limit = Infinity; - const result = getPaginated(offset, limit, getData); - - expect(result.rundown).toHaveLength(0); - expect(result.total).toBe(10); - }); -}); diff --git a/apps/server/src/services/rundown-service/delayUtils.ts b/apps/server/src/services/rundown-service/delayUtils.ts index f625263fd..f5264dc4d 100644 --- a/apps/server/src/services/rundown-service/delayUtils.ts +++ b/apps/server/src/services/rundown-service/delayUtils.ts @@ -1,94 +1,6 @@ -import { OntimeRundown, isOntimeDelay, isOntimeBlock, isOntimeEvent, OntimeEvent } from 'ontime-types'; +import { OntimeRundown, isOntimeDelay, isOntimeEvent, OntimeEvent } from 'ontime-types'; import { deleteAtIndex } from 'ontime-utils'; -/** - * Calculates all delays in a given rundown - * @param rundown - */ -export function calculateRuntimeDelays(rundown: OntimeRundown) { - let accumulatedDelay = 0; - const updatedRundown = [...rundown]; - - for (const [index, event] of updatedRundown.entries()) { - if (isOntimeDelay(event)) { - accumulatedDelay += event.duration; - } else if (isOntimeBlock(event)) { - accumulatedDelay = 0; - } else if (isOntimeEvent(event)) { - updatedRundown[index] = { - ...event, - delay: accumulatedDelay, - }; - } - } - return updatedRundown; -} -/** - * Calculate delays in rundown from a given index - * @param eventIndex - * @param rundown - */ -export function calculateRuntimeDelaysFromIndex(eventIndex: number, rundown: OntimeRundown) { - if (eventIndex === -1) { - throw new Error('ID not found at index'); - } - - let accumulatedDelay = getDelayAt(eventIndex, rundown); - const updatedRundown = [...rundown]; - - for (let i = eventIndex; i < rundown.length; i++) { - const event = rundown[i]; - if (isOntimeDelay(event)) { - accumulatedDelay += event.duration; - } else if (isOntimeBlock(event)) { - if (i === eventIndex) { - accumulatedDelay = 0; - } else { - break; - } - } else if (isOntimeEvent(event)) { - updatedRundown[i] = { - ...event, - delay: accumulatedDelay, - }; - } - } - return updatedRundown; -} - -/** - * Calculate delays in rundown from an event with given id - * @param eventId - * @param rundown - */ -export function calculateRuntimeDelaysFrom(eventId: string, rundown: OntimeRundown) { - const index = rundown.findIndex((event) => event.id === eventId); - return calculateRuntimeDelaysFromIndex(index, rundown); -} - -/** - * Calculates delay to an event at a given index - * @param eventIndex - * @param rundown - */ -export function getDelayAt(eventIndex: number, rundown: OntimeRundown): number { - if (eventIndex < 1) { - return 0; - } - - // we need to check the event before - const event = rundown[eventIndex - 1]; - - if (isOntimeDelay(event)) { - return event.duration + getDelayAt(eventIndex - 1, rundown); - } else if (isOntimeBlock(event)) { - return 0; - } else if (isOntimeEvent(event)) { - return event.delay ?? 0; - } - return 0; -} - /** * Applies delay from given event ID, deletes the delay event after * @throws {Error} if event ID not found or is not a delay diff --git a/apps/server/src/services/rundown-service/rundownCacheUtils.ts b/apps/server/src/services/rundown-service/rundownCacheUtils.ts index 8f165fc81..c3b7fff19 100644 --- a/apps/server/src/services/rundown-service/rundownCacheUtils.ts +++ b/apps/server/src/services/rundown-service/rundownCacheUtils.ts @@ -105,7 +105,7 @@ export function handleCustomField( } /** List of event properties which do not need the rundown to be regenerated */ -export enum regenerateWhitelist { +enum RegenerateWhitelist { 'id', 'cue', 'title', @@ -125,7 +125,7 @@ export enum regenerateWhitelist { * @param path */ export function isDataStale(patch: Partial): boolean { - return Object.keys(patch).some((key) => !(key in regenerateWhitelist)); + return Object.keys(patch).some((key) => !(key in RegenerateWhitelist)); } /** @@ -133,7 +133,7 @@ export function isDataStale(patch: Partial): boolean { * @param path */ export function willCauseRegeneration(key: keyof OntimeEvent): boolean { - return !(key in regenerateWhitelist); + return !(key in RegenerateWhitelist); } /** diff --git a/apps/server/src/services/rundown-service/rundownUtils.ts b/apps/server/src/services/rundown-service/rundownUtils.ts index 44021a733..b00668186 100644 --- a/apps/server/src/services/rundown-service/rundownUtils.ts +++ b/apps/server/src/services/rundown-service/rundownUtils.ts @@ -101,19 +101,3 @@ export function findNext(currentEventId?: string): PlayableEvent | null { const nextEvent = playableEvents.at(newIndex); return nextEvent ?? null; } - -/** - * Returns a paginated rundown - * Exposes a getter function for the rundown for testing - */ -export function getPaginated( - offset: number, - limit: number, - source = getRundown, -): { rundown: OntimeRundownEntry[]; total: number } { - const rundown = source(); - return { - rundown: rundown.slice(Math.min(offset, rundown.length), Math.min(offset + limit, rundown.length)), - total: rundown.length, - }; -} diff --git a/apps/server/src/stores/runtimeState.ts b/apps/server/src/stores/runtimeState.ts index 3c01871e1..2029023f4 100644 --- a/apps/server/src/stores/runtimeState.ts +++ b/apps/server/src/stores/runtimeState.ts @@ -21,7 +21,7 @@ import { isPlaybackActive, } from 'ontime-utils'; -import { clock } from '../services/Clock.js'; +import { timeNow } from '../utils/time.js'; import type { RestorePoint } from '../services/RestoreService.js'; import { getCurrent, @@ -52,7 +52,7 @@ export type RuntimeState = { }; const runtimeState: RuntimeState = { - clock: clock.timeNow(), + clock: timeNow(), currentBlock: { ...runtimeStorePlaceholder.currentBlock }, eventNow: null, publicEventNow: null, @@ -98,7 +98,7 @@ export function clear() { runtimeState.runtime.selectedEventIndex = null; runtimeState.timer.playback = Playback.Stop; - runtimeState.clock = clock.timeNow(); + runtimeState.clock = timeNow(); runtimeState.timer = { ...runtimeStorePlaceholder.timer }; // when clearing, we maintain the total delay from the rundown @@ -357,7 +357,7 @@ export function start(state: RuntimeState = runtimeState): boolean { if (state.timer.playback === Playback.Play) { return false; } - state.clock = clock.timeNow(); + state.clock = timeNow(); state.timer.secondaryTimer = null; // add paused time if it exists @@ -400,7 +400,7 @@ export function pause(state: RuntimeState = runtimeState): boolean { } state.timer.playback = Playback.Pause; - state.clock = clock.timeNow(); + state.clock = timeNow(); state._timer.pausedAt = state.clock; return true; } @@ -438,7 +438,7 @@ export function addTime(amount: number) { if (willGoNegative && !hasFinished) { // set finished time so side effects are triggered - runtimeState._timer.forceFinish = clock.timeNow(); + runtimeState._timer.forceFinish = timeNow(); } else { const willGoPositive = runtimeState.timer.current < 0 && runtimeState.timer.current + amount > 0; if (willGoPositive) { @@ -466,7 +466,7 @@ export type UpdateResult = { export function update(): UpdateResult { // 0. there are some things we always do const previousClock = runtimeState.clock; - runtimeState.clock = clock.timeNow(); // we update the clock on every update call + runtimeState.clock = timeNow(); // we update the clock on every update call // 1. is playback idle? if (!isPlaybackActive(runtimeState.timer.playback)) { diff --git a/apps/server/src/utils/__tests__/parserFunctions.test.ts b/apps/server/src/utils/__tests__/parserFunctions.test.ts index 0121d1c6d..03b39f46f 100644 --- a/apps/server/src/utils/__tests__/parserFunctions.test.ts +++ b/apps/server/src/utils/__tests__/parserFunctions.test.ts @@ -1,13 +1,10 @@ import { CustomFields, DatabaseModel, - EndAction, OntimeEvent, OntimeRundown, Settings, SupportedEvent, - TimeStrategy, - TimerType, URLPreset, } from 'ontime-types'; @@ -360,46 +357,3 @@ describe('parseRundown() linking', () => { }); }); }); - -describe('parseRundown() migrations', () => { - const legacyEvent = { - id: '1', - type: SupportedEvent.Event, - cue: '', - title: '', - note: '', - endAction: EndAction.None, - timerType: 'time-to-end', - linkStart: null, - timeStrategy: TimeStrategy.LockDuration, - timeStart: 0, - timeEnd: 0, - duration: 0, - isPublic: false, - skip: false, - colour: '', - revision: 0, - timeWarning: 120000, - timeDanger: 60000, - custom: {}, - }; - - it('migrates an event with time-to-end', () => { - const result = parseRundown({ rundown: [legacyEvent] as OntimeRundown }); - expect(result.rundown[0]).toMatchObject({ - id: '1', - timerType: TimerType.CountDown, - countToEnd: true, - }); - }); - - it('migrates an event without time-to-end', () => { - const countdownEvent = { ...legacyEvent, timerType: TimerType.CountDown }; - const result = parseRundown({ rundown: [countdownEvent] as OntimeRundown }); - expect(result.rundown[0]).toMatchObject({ - id: '1', - timerType: TimerType.CountDown, - countToEnd: false, - }); - }); -}); diff --git a/apps/server/src/utils/parser.ts b/apps/server/src/utils/parser.ts index 11680f5f6..6c724b4a1 100644 --- a/apps/server/src/utils/parser.ts +++ b/apps/server/src/utils/parser.ts @@ -303,7 +303,7 @@ export const parseExcel = ( }; }; -export type ParsingError = { +type ParsingError = { context: string; message: string; }; diff --git a/apps/server/src/utils/parserFunctions.ts b/apps/server/src/utils/parserFunctions.ts index 7c8cce9d5..3f4d1f3bf 100644 --- a/apps/server/src/utils/parserFunctions.ts +++ b/apps/server/src/utils/parserFunctions.ts @@ -8,7 +8,6 @@ import { OntimeRundown, ProjectData, Settings, - TimerType, URLPreset, ViewSettings, isOntimeBlock, @@ -53,7 +52,7 @@ export function parseRundown( let newEvent: OntimeEvent | OntimeDelay | OntimeBlock | null; if (isOntimeEvent(event)) { - const maybeEvent = runEventMigrations({ ...event, id }); + const maybeEvent = { ...event, id }; if (event.linkStart) { maybeEvent.linkStart = previousId; @@ -246,22 +245,3 @@ export function sanitiseCustomFields(data: object): CustomFields { return newCustomFields; } - -/** - * Time to end was moved from a TimerType to a standalone boolean named count to end - * Released as part of v3.10.0 - */ -function migrateTimeToEnd(event: any): OntimeEvent { - if (event.timerType === 'time-to-end') { - event.timerType = TimerType.CountDown; - event.countToEnd = true; - } - return event; -} - -/** - * Mutating function migrates event data entries - */ -function runEventMigrations(event: any): OntimeEvent { - return migrateTimeToEnd(event); -} diff --git a/apps/server/src/utils/removeFileExtension.ts b/apps/server/src/utils/removeFileExtension.ts deleted file mode 100644 index 4c577950f..000000000 --- a/apps/server/src/utils/removeFileExtension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { parse } from 'path'; - -/** - * @description Takes a filename and removes the extension - * @param {string} filename - filename with extension - */ -export const removeFileExtension = (filename: string): string => { - return parse(filename).name; -}; diff --git a/apps/server/src/utils/time.ts b/apps/server/src/utils/time.ts index cb9e72e0a..5b1ffdbfd 100644 --- a/apps/server/src/utils/time.ts +++ b/apps/server/src/utils/time.ts @@ -60,3 +60,17 @@ export function getTimezoneLabel(date: Date): string { return `GMT ${sign}${pad(hours)}:${pad(minutes)} ${tzName}`; } + +/** + * Get current time from system + */ +export function timeNow() { + const now = new Date(); + + // extract milliseconds since midnight + let elapsed = now.getHours() * 3600000; + elapsed += now.getMinutes() * 60000; + elapsed += now.getSeconds() * 1000; + elapsed += now.getMilliseconds(); + return elapsed; +} diff --git a/packages/types/src/api/ontime-controller/BackendResponse.type.ts b/packages/types/src/api/ontime-controller/BackendResponse.type.ts index 577094682..5793798f9 100644 --- a/packages/types/src/api/ontime-controller/BackendResponse.type.ts +++ b/packages/types/src/api/ontime-controller/BackendResponse.type.ts @@ -1,4 +1,3 @@ -import type { OntimeRundown } from '../../definitions/core/Rundown.type.js'; import type { Playback } from '../../definitions/runtime/Playback.type.js'; import type { MaybeString } from '../../utils/utils.type.js'; @@ -51,8 +50,3 @@ export type ProjectLogoResponse = { export type ErrorResponse = MessageResponse; export type AuthenticationStatus = 'authenticated' | 'not_authenticated' | 'pending'; - -export type RundownPaginated = { - rundown: OntimeRundown; - total: number; -}; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index f7a216a61..58611539c 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -67,7 +67,6 @@ export type { ErrorResponse, ProjectFileListResponse, MessageResponse, - RundownPaginated, SessionStats, ProjectLogoResponse, } from './api/ontime-controller/BackendResponse.type.js';