diff --git a/apps/client/src/common/api/apiConstants.ts b/apps/client/src/common/api/apiConstants.ts index 9005a1b0c..287e4d800 100644 --- a/apps/client/src/common/api/apiConstants.ts +++ b/apps/client/src/common/api/apiConstants.ts @@ -1,7 +1,7 @@ export const STATIC_PORT = 4001; // REST stuff -export const EVENT_TABLE = ['event']; +export const EVENTDATA_TABLE = ['eventdata']; export const ALIASES = ['aliases']; export const USERFIELDS = ['userFields']; export const RUNDOWN_TABLE_KEY = 'rundown'; @@ -17,17 +17,16 @@ export const FEAT_INFO = 'feat-info'; export const FEAT_MESSAGECONTROL = 'feat-messagecontrol'; export const FEAT_PLAYBACKCONTROL = 'feat-playbackcontrol'; export const FEAT_RUNDOWN = 'feat-rundown'; -export const TIMER = 'ontime-timer'; +export const TIMER = 'timer'; /** * @description finds server path given the current location, it * @return {*} */ -export const calculateServer = () => - import.meta.env.DEV ? `http://localhost:${STATIC_PORT}` : window.location.origin; +export const calculateServer = () => (import.meta.env.DEV ? `http://localhost:${STATIC_PORT}` : window.location.origin); export const serverURL = calculateServer(); -export const eventURL = `${serverURL}/event`; +export const eventURL = `${serverURL}/eventdata`; export const rundownURL = `${serverURL}/eventlist`; export const ontimeURL = `${serverURL}/ontime`; diff --git a/apps/client/src/common/api/eventApi.ts b/apps/client/src/common/api/eventDataApi.ts similarity index 65% rename from apps/client/src/common/api/eventApi.ts rename to apps/client/src/common/api/eventDataApi.ts index f7d0490e1..9e29750ea 100644 --- a/apps/client/src/common/api/eventApi.ts +++ b/apps/client/src/common/api/eventDataApi.ts @@ -1,6 +1,5 @@ import axios from 'axios'; - -import { EventDataType } from '../models/EventData.type'; +import { EventData } from 'ontime-types'; import { eventURL } from './apiConstants'; @@ -8,7 +7,7 @@ import { eventURL } from './apiConstants'; * @description HTTP request to fetch event data * @return {Promise} */ -export async function fetchEvent(): Promise { +export async function fetchEventData(): Promise { const res = await axios.get(eventURL); return res.data; } @@ -17,6 +16,6 @@ export async function fetchEvent(): Promise { * @description HTTP request to mutate event data * @return {Promise} */ -export async function postEvent(data: EventDataType) { +export async function postEventData(data: EventData) { return axios.post(eventURL, data); } diff --git a/apps/client/src/common/api/eventsApi.ts b/apps/client/src/common/api/eventsApi.ts index e0a8b0055..fd8c406bd 100644 --- a/apps/client/src/common/api/eventsApi.ts +++ b/apps/client/src/common/api/eventsApi.ts @@ -1,6 +1,5 @@ import axios from 'axios'; - -import { OntimeRundown, OntimeRundownEntry } from '../models/EventTypes'; +import { OntimeRundown, OntimeRundownEntry } from 'ontime-types'; import { rundownURL } from './apiConstants'; @@ -37,12 +36,12 @@ export async function requestPatchEvent(data: OntimeRundownEntry) { return axios.patch(rundownURL, data); } - export type ReorderEntry = { - eventId: string, - from: number, - to: number, -} + eventId: string; + from: number; + to: number; +}; + /** * @description HTTP request to reorder events * @return {Promise} diff --git a/apps/client/src/common/api/ontimeApi.ts b/apps/client/src/common/api/ontimeApi.ts index 915e91279..9f90da5d0 100644 --- a/apps/client/src/common/api/ontimeApi.ts +++ b/apps/client/src/common/api/ontimeApi.ts @@ -1,11 +1,7 @@ import axios from 'axios'; +import { Alias, OSCSettings, Settings, UserFields, ViewSettings } from 'ontime-types'; -import { URLAliasType } from '../models/Alias.type'; -import { InfoType } from '../models/Info.types'; -import { OntimeSettingsType } from '../models/OntimeSettings.type'; -import { OSCSettings } from '../models/OscSettings.type'; -import { UserFieldsType } from '../models/UserFields.type'; -import { ViewSettingsType } from '../models/ViewSettings.type'; +import { InfoType } from '../models/Info'; import { ontimeURL } from './apiConstants'; @@ -13,7 +9,7 @@ import { ontimeURL } from './apiConstants'; * @description HTTP request to retrieve application settings * @return {Promise} */ -export async function getSettings(): Promise { +export async function getSettings(): Promise { const res = await axios.get(`${ontimeURL}/settings`); return res.data; } @@ -22,7 +18,7 @@ export async function getSettings(): Promise { * @description HTTP request to mutate application settings * @return {Promise} */ -export async function postSettings(data: OntimeSettingsType) { +export async function postSettings(data: Settings) { return axios.post(`${ontimeURL}/settings`, data); } @@ -39,7 +35,7 @@ export async function getInfo(): Promise { * @description HTTP request to retrieve view settings * @return {Promise} */ -export async function getView(): Promise { +export async function getView(): Promise { const res = await axios.get(`${ontimeURL}/views`); return res.data; } @@ -48,7 +44,7 @@ export async function getView(): Promise { * @description HTTP request to mutate view settings * @return {Promise} */ -export async function postView(data: ViewSettingsType) { +export async function postView(data: ViewSettings) { return axios.post(`${ontimeURL}/views`, data); } @@ -56,7 +52,7 @@ export async function postView(data: ViewSettingsType) { * @description HTTP request to retrieve aliases * @return {Promise} */ -export async function getAliases(): Promise { +export async function getAliases(): Promise { const res = await axios.get(`${ontimeURL}/aliases`); return res.data; } @@ -65,7 +61,7 @@ export async function getAliases(): Promise { * @description HTTP request to mutate aliases * @return {Promise} */ -export async function postAliases(data: URLAliasType[]) { +export async function postAliases(data: Alias[]) { return axios.post(`${ontimeURL}/aliases`, data); } @@ -73,7 +69,7 @@ export async function postAliases(data: URLAliasType[]) { * @description HTTP request to retrieve user fields * @return {Promise} */ -export async function getUserFields(): Promise { +export async function getUserFields(): Promise { const res = await axios.get(`${ontimeURL}/userfields`); return res.data; } @@ -82,7 +78,7 @@ export async function getUserFields(): Promise { * @description HTTP request to mutate user fields * @return {Promise} */ -export async function postUserFields(data: UserFieldsType) { +export async function postUserFields(data: UserFields) { return axios.post(`${ontimeURL}/userfields`, data); } diff --git a/apps/client/src/common/components/buttons/QuitIconBtn.tsx b/apps/client/src/common/components/buttons/QuitIconBtn.tsx index 1c16afc50..78281928a 100644 --- a/apps/client/src/common/components/buttons/QuitIconBtn.tsx +++ b/apps/client/src/common/components/buttons/QuitIconBtn.tsx @@ -13,7 +13,7 @@ import { import { FiPower } from '@react-icons/all-files/fi/FiPower'; import { LoggingContext } from '../../context/LoggingContext'; -import { Size } from '../../models/UtilTypes'; +import { Size } from '../../models/Util.type'; interface QuitIconBtnProps { clickHandler: () => void; diff --git a/apps/client/src/common/components/copy-tag/CopyTag.tsx b/apps/client/src/common/components/copy-tag/CopyTag.tsx index aa3e8c328..54799e5fa 100644 --- a/apps/client/src/common/components/copy-tag/CopyTag.tsx +++ b/apps/client/src/common/components/copy-tag/CopyTag.tsx @@ -3,7 +3,7 @@ import { Button, ButtonGroup, IconButton, Tooltip } from '@chakra-ui/react'; import { IoCopy } from '@react-icons/all-files/io5/IoCopy'; import { tooltipDelayFast } from '../../../ontimeConfig'; -import { Size } from '../../models/UtilTypes'; +import { Size } from '../../models/Util.type'; interface CopyTagProps { label: string; diff --git a/apps/client/src/common/components/input/text-input/TextInput.tsx b/apps/client/src/common/components/input/text-input/TextInput.tsx index def0f858c..5533c1b40 100644 --- a/apps/client/src/common/components/input/text-input/TextInput.tsx +++ b/apps/client/src/common/components/input/text-input/TextInput.tsx @@ -2,7 +2,7 @@ import { useCallback, useRef } from 'react'; import { Input, Textarea } from '@chakra-ui/react'; import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor'; -import { Size } from '../../../models/UtilTypes'; +import { Size } from '../../../models/Util.type'; import useReactiveTextInput from './useReactiveTextInput'; diff --git a/apps/client/src/common/components/schedule/ScheduleContext.tsx b/apps/client/src/common/components/schedule/ScheduleContext.tsx index 8925b120f..889cef72e 100644 --- a/apps/client/src/common/components/schedule/ScheduleContext.tsx +++ b/apps/client/src/common/components/schedule/ScheduleContext.tsx @@ -1,7 +1,7 @@ import { createContext, PropsWithChildren, useContext, useState } from 'react'; +import { OntimeEvent } from 'ontime-types'; import { useInterval } from '../../hooks/useInterval'; -import { OntimeEvent } from '../../models/EventTypes'; interface ScheduleContextState { events: OntimeEvent[]; diff --git a/apps/client/src/common/hooks-query/useEvent.ts b/apps/client/src/common/hooks-query/useEventData.ts similarity index 59% rename from apps/client/src/common/hooks-query/useEvent.ts rename to apps/client/src/common/hooks-query/useEventData.ts index 8274a65c3..79b6645d0 100644 --- a/apps/client/src/common/hooks-query/useEvent.ts +++ b/apps/client/src/common/hooks-query/useEventData.ts @@ -1,14 +1,14 @@ import { useQuery } from '@tanstack/react-query'; import { queryRefetchIntervalSlow } from '../../ontimeConfig'; -import { EVENT_TABLE } from '../api/apiConstants'; -import { fetchEvent } from '../api/eventApi'; -import { eventDataPlaceholder } from '../models/EventData.type'; +import { EVENTDATA_TABLE } from '../api/apiConstants'; +import { fetchEventData } from '../api/eventDataApi'; +import { eventDataPlaceholder } from '../models/EventData'; -export default function useEvent() { +export default function useEventData() { const { data, status, isError, refetch } = useQuery({ - queryKey: EVENT_TABLE, - queryFn: fetchEvent, + queryKey: EVENTDATA_TABLE, + queryFn: fetchEventData, placeholderData: eventDataPlaceholder, retry: 5, retryDelay: (attempt) => attempt * 2500, diff --git a/apps/client/src/common/hooks-query/useInfo.ts b/apps/client/src/common/hooks-query/useInfo.ts index 765237c72..3cf946c24 100644 --- a/apps/client/src/common/hooks-query/useInfo.ts +++ b/apps/client/src/common/hooks-query/useInfo.ts @@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query'; import { queryRefetchIntervalSlow } from '../../ontimeConfig'; import { APP_INFO } from '../api/apiConstants'; import { getInfo } from '../api/ontimeApi'; -import { ontimePlaceholderInfo } from '../models/Info.types'; +import { ontimePlaceholderInfo } from '../models/Info'; export default function useInfo() { const { data, status, isError, refetch } = useQuery({ diff --git a/apps/client/src/common/hooks-query/useOscSettings.ts b/apps/client/src/common/hooks-query/useOscSettings.ts index b69e0c078..77fdb3b3b 100644 --- a/apps/client/src/common/hooks-query/useOscSettings.ts +++ b/apps/client/src/common/hooks-query/useOscSettings.ts @@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query'; import { queryRefetchIntervalSlow } from '../../ontimeConfig'; import { OSC_SETTINGS } from '../api/apiConstants'; import { getOSC } from '../api/ontimeApi'; -import { oscPlaceholderSettings } from '../models/OscSettings.type'; +import { oscPlaceholderSettings } from '../models/OscSettings'; export default function useOscSettings() { const { data, status, isError, refetch } = useQuery({ diff --git a/apps/client/src/common/hooks-query/useSettings.ts b/apps/client/src/common/hooks-query/useSettings.ts index 3bdfbf45c..e2918d8d1 100644 --- a/apps/client/src/common/hooks-query/useSettings.ts +++ b/apps/client/src/common/hooks-query/useSettings.ts @@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query'; import { queryRefetchIntervalSlow } from '../../ontimeConfig'; import { APP_SETTINGS } from '../api/apiConstants'; import { getSettings } from '../api/ontimeApi'; -import { ontimePlaceholderSettings } from '../models/OntimeSettings.type'; +import { ontimePlaceholderSettings } from '../models/OntimeSettings'; export default function useSettings() { const { data, status, isError, refetch } = useQuery({ diff --git a/apps/client/src/common/hooks-query/useUserFields.ts b/apps/client/src/common/hooks-query/useUserFields.ts index 71260bb71..784e5f65c 100644 --- a/apps/client/src/common/hooks-query/useUserFields.ts +++ b/apps/client/src/common/hooks-query/useUserFields.ts @@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query'; import { queryRefetchInterval } from '../../ontimeConfig'; import { USERFIELDS } from '../api/apiConstants'; import { getUserFields } from '../api/ontimeApi'; -import { userFieldsPlaceholder } from '../models/UserFields.type'; +import { userFieldsPlaceholder } from '../models/UserFields'; export default function useUserFields() { const { data, status, isError, refetch } = useQuery({ diff --git a/apps/client/src/common/hooks/useEventAction.ts b/apps/client/src/common/hooks/useEventAction.ts index 6a8ce1692..f89dcbfb6 100644 --- a/apps/client/src/common/hooks/useEventAction.ts +++ b/apps/client/src/common/hooks/useEventAction.ts @@ -2,6 +2,7 @@ import { useCallback, useContext } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import axios, { AxiosError } from 'axios'; import { useAtomValue } from 'jotai'; +import { OntimeRundown, OntimeRundownEntry, SupportedEvent } from 'ontime-types'; import { RUNDOWN_TABLE, RUNDOWN_TABLE_KEY } from '../api/apiConstants'; import { @@ -15,7 +16,6 @@ import { } from '../api/eventsApi'; import { defaultPublicAtom, startTimeIsLastEndAtom } from '../atoms/LocalEventSettings'; import { LoggingContext } from '../context/LoggingContext'; -import { OntimeRundown, OntimeRundownEntry, SupportedEvent } from '../models/EventTypes'; /** * @description Set of utilities for events @@ -88,7 +88,6 @@ export const useEventAction = () => { } try { - // @ts-expect-error we know that the event here is one of the defined types await _addEventMutation.mutateAsync(newEvent); } catch (error) { if (!axios.isAxiosError(error)) { diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index 475b241ab..094cb2d84 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -1,6 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import { ontimeQueryClient as queryClient } from '../queryClient'; -import socket, { subscribeOnce } from '../utils/socket'; +import { Playback } from 'ontime-types'; import { FEAT_CUESHEET, @@ -10,7 +9,8 @@ import { FEAT_RUNDOWN, TIMER, } from '../api/apiConstants'; -import { Playback } from '../models/OntimeTypes'; +import { ontimeQueryClient as queryClient } from '../queryClient'; +import socket, { subscribeOnce } from '../utils/socket'; function createSocketHook(key: string, defaultValue: T | null = null) { subscribeOnce(key, (data) => queryClient.setQueryData([key], data)); @@ -37,17 +37,19 @@ const emptyRundown: IRundown = { export const useRundownEditor = createSocketHook(FEAT_RUNDOWN, emptyRundown); const emptyMessageControl = { - presenter: { - text: '', - visible: false, - }, - public: { - text: '', - visible: false, - }, - lower: { - text: '', - visible: false, + messages: { + presenter: { + text: '', + visible: false, + }, + public: { + text: '', + visible: false, + }, + lower: { + text: '', + visible: false, + }, }, onAir: false, }; @@ -124,7 +126,6 @@ export const emptyCuesheet = { export const useCuesheet = createSocketHook(FEAT_CUESHEET, emptyCuesheet); - export const setEventPlayback = { loadEvent: (eventId: string) => socket.emit('set-loadid', eventId), startEvent: (eventId: string) => socket.emit('set-startid', eventId), diff --git a/apps/client/src/common/models/Alias.ts b/apps/client/src/common/models/Alias.ts new file mode 100644 index 000000000..a5bd50985 --- /dev/null +++ b/apps/client/src/common/models/Alias.ts @@ -0,0 +1,7 @@ +import { Alias } from 'ontime-types'; + +export const aliasPlaceholder: Alias = { + enabled: false, + alias: '', + pathAndParams: '', +}; diff --git a/apps/client/src/common/models/Alias.type.ts b/apps/client/src/common/models/Alias.type.ts deleted file mode 100644 index 3f4b9a32e..000000000 --- a/apps/client/src/common/models/Alias.type.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type URLAliasType = { - enabled: boolean; - alias: string; - pathAndParams: string; -} - -export const aliasPlaceholder: URLAliasType = { - enabled: false, - alias: '', - pathAndParams: '', -}; diff --git a/apps/client/src/common/models/EventData.ts b/apps/client/src/common/models/EventData.ts new file mode 100644 index 000000000..4a13c33f3 --- /dev/null +++ b/apps/client/src/common/models/EventData.ts @@ -0,0 +1,10 @@ +import { EventData } from 'ontime-types'; + +export const eventDataPlaceholder: EventData = { + title: '', + publicUrl: '', + publicInfo: '', + backstageUrl: '', + backstageInfo: '', + endMessage: '', +}; diff --git a/apps/client/src/common/models/EventData.type.ts b/apps/client/src/common/models/EventData.type.ts deleted file mode 100644 index 9c966be12..000000000 --- a/apps/client/src/common/models/EventData.type.ts +++ /dev/null @@ -1,17 +0,0 @@ -export type EventDataType = { - title: string; - publicUrl: string; - publicInfo: string; - backstageUrl: string; - backstageInfo: string; - endMessage: string; -}; - -export const eventDataPlaceholder: EventDataType = { - title: '', - publicUrl: '', - publicInfo: '', - backstageUrl: '', - backstageInfo: '', - endMessage: '', -}; diff --git a/apps/client/src/common/models/EventTypes.ts b/apps/client/src/common/models/EventTypes.ts deleted file mode 100644 index 7800279a5..000000000 --- a/apps/client/src/common/models/EventTypes.ts +++ /dev/null @@ -1,50 +0,0 @@ -export enum SupportedEvent { - Event = 'event', - Delay = 'delay', - Block = 'block' -} - -export interface OntimeBaseEvent { - type: SupportedEvent; - id: string; - after?: string; // used when creating an event to indicate its position in rundown -} - -export type OntimeDelay = OntimeBaseEvent & { - type: SupportedEvent.Delay; - duration: number; - revision: number; -} - -export type OntimeBlock = OntimeBaseEvent & { - type: SupportedEvent.Block; -} - -export type OntimeEvent = OntimeBaseEvent & { - type: SupportedEvent.Event; - title: string, - subtitle: string, - presenter: string, - note: string, - timeType?: string, - timeStart: number, - timeEnd: number, - duration: number, - isPublic: boolean, - skip: boolean, - colour: string, - user0: string, - user1: string, - user2: string, - user3: string, - user4: string, - user5: string, - user6: string, - user7: string, - user8: string, - user9: string, - revision: number, -} - -export type OntimeRundownEntry = OntimeDelay | OntimeBlock | OntimeEvent; -export type OntimeRundown = OntimeRundownEntry[] \ No newline at end of file diff --git a/apps/client/src/common/models/Http.type.ts b/apps/client/src/common/models/Http.ts similarity index 100% rename from apps/client/src/common/models/Http.type.ts rename to apps/client/src/common/models/Http.ts diff --git a/apps/client/src/common/models/Info.types.ts b/apps/client/src/common/models/Info.ts similarity index 63% rename from apps/client/src/common/models/Info.types.ts rename to apps/client/src/common/models/Info.ts index 5d0ec61a8..6051cd115 100644 --- a/apps/client/src/common/models/Info.types.ts +++ b/apps/client/src/common/models/Info.ts @@ -1,19 +1,19 @@ -import { OntimeSettingsType } from './OntimeSettings.type'; +import { Settings } from 'ontime-types'; type NetworkInterfaceType = { name: string; address: string; -} +}; export type InfoType = { networkInterfaces: NetworkInterfaceType[]; - settings: Pick -} + settings: Pick; +}; export const ontimePlaceholderInfo: InfoType = { networkInterfaces: [], settings: { - version: 0, + version: 2, serverPort: 4001, }, -}; \ No newline at end of file +}; diff --git a/apps/client/src/common/models/OntimeSettings.ts b/apps/client/src/common/models/OntimeSettings.ts new file mode 100644 index 000000000..2839cdc4e --- /dev/null +++ b/apps/client/src/common/models/OntimeSettings.ts @@ -0,0 +1,10 @@ +import { Settings } from 'ontime-types'; + +export const ontimePlaceholderSettings: Settings = { + app: 'ontime', + version: 2, + serverPort: 4001, + lock: null, + pinCode: null, + timeFormat: '24', +}; diff --git a/apps/client/src/common/models/OntimeSettings.type.ts b/apps/client/src/common/models/OntimeSettings.type.ts deleted file mode 100644 index a67be1823..000000000 --- a/apps/client/src/common/models/OntimeSettings.type.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TimeFormat } from './OntimeTypes'; - -export type OntimeSettingsType = { - app: string; - version: number; - serverPort: number; - lock: null | boolean; - pinCode: null | number | string; - timeFormat: TimeFormat; -} - -export const ontimePlaceholderSettings: OntimeSettingsType = { - app: 'ontime', - version: 1, - serverPort: 4001, - lock: null, - pinCode: null, - timeFormat: '24', -}; diff --git a/apps/client/src/common/models/OscSettings.type.ts b/apps/client/src/common/models/OscSettings.ts similarity index 100% rename from apps/client/src/common/models/OscSettings.type.ts rename to apps/client/src/common/models/OscSettings.ts diff --git a/apps/client/src/common/models/PresenterMessage.type.ts b/apps/client/src/common/models/PresenterMessage.type.ts deleted file mode 100644 index 98b461d6f..000000000 --- a/apps/client/src/common/models/PresenterMessage.type.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type PresenterMessageType = { - text: string; - visible: boolean; -} diff --git a/apps/client/src/common/models/TimeManager.type.ts b/apps/client/src/common/models/TimeManager.type.ts index 94b7e77fa..b96ddc92a 100644 --- a/apps/client/src/common/models/TimeManager.type.ts +++ b/apps/client/src/common/models/TimeManager.type.ts @@ -1,4 +1,4 @@ -import { Playback } from './OntimeTypes'; +import { Playback } from 'ontime-types'; export type TimeManagerType = { clock: number; @@ -12,4 +12,4 @@ export type TimeManagerType = { finished: boolean; playback: Playback; -} +}; diff --git a/apps/client/src/common/models/UserFields.ts b/apps/client/src/common/models/UserFields.ts new file mode 100644 index 000000000..c2be66f5b --- /dev/null +++ b/apps/client/src/common/models/UserFields.ts @@ -0,0 +1,14 @@ +import { UserFields } from 'ontime-types'; + +export const userFieldsPlaceholder: UserFields = { + user0: '', + user1: '', + user2: '', + user3: '', + user4: '', + user5: '', + user6: '', + user7: '', + user8: '', + user9: '', +}; diff --git a/apps/client/src/common/models/UserFields.type.ts b/apps/client/src/common/models/UserFields.type.ts deleted file mode 100644 index f84d7e267..000000000 --- a/apps/client/src/common/models/UserFields.type.ts +++ /dev/null @@ -1,25 +0,0 @@ -export type UserFieldsType = { - user0: string; - user1: string; - user2: string; - user3: string; - user4: string; - user5: string; - user6: string; - user7: string; - user8: string; - user9: string; -} - -export const userFieldsPlaceholder: UserFieldsType = { - user0: '', - user1: '', - user2: '', - user3: '', - user4: '', - user5: '', - user6: '', - user7: '', - user8: '', - user9: '', -}; diff --git a/apps/client/src/common/models/UtilTypes.ts b/apps/client/src/common/models/Util.type.ts similarity index 100% rename from apps/client/src/common/models/UtilTypes.ts rename to apps/client/src/common/models/Util.type.ts diff --git a/apps/client/src/common/models/ViewTypes.ts b/apps/client/src/common/models/View.types.ts similarity index 100% rename from apps/client/src/common/models/ViewTypes.ts rename to apps/client/src/common/models/View.types.ts diff --git a/apps/client/src/common/models/ViewSettings.type.ts b/apps/client/src/common/models/ViewSettings.type.ts index e7cbe4e9d..c1dc5ded9 100644 --- a/apps/client/src/common/models/ViewSettings.type.ts +++ b/apps/client/src/common/models/ViewSettings.type.ts @@ -1,7 +1,5 @@ -export type ViewSettingsType = { - overrideStyles: boolean; -} +import { ViewSettings } from 'ontime-types'; -export const viewsSettingsPlaceholder: ViewSettingsType = { +export const viewsSettingsPlaceholder: ViewSettings = { overrideStyles: false, }; diff --git a/apps/client/src/common/utils/eventsManager.ts b/apps/client/src/common/utils/eventsManager.ts index 17a7cba01..867060726 100644 --- a/apps/client/src/common/utils/eventsManager.ts +++ b/apps/client/src/common/utils/eventsManager.ts @@ -1,4 +1,4 @@ -import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../models/EventTypes'; +import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from 'ontime-types'; import { formatTime } from './time'; diff --git a/apps/client/src/features/control/message/MessageControl.tsx b/apps/client/src/features/control/message/MessageControl.tsx index d79c2f4fd..f62906fe3 100644 --- a/apps/client/src/features/control/message/MessageControl.tsx +++ b/apps/client/src/features/control/message/MessageControl.tsx @@ -16,26 +16,26 @@ export default function MessageControl() { setMessage.presenterText(newValue)} - actionHandler={() => setMessage.presenterVisible(!data?.presenter.visible)} + actionHandler={() => setMessage.presenterVisible(!data?.messages.presenter.visible)} /> setMessage.publicText(newValue)} - actionHandler={() => setMessage.publicVisible(!data?.public.visible)} + actionHandler={() => setMessage.publicVisible(!data?.messages.public.visible)} /> setMessage.lowerText(newValue)} - actionHandler={() => setMessage.lowerVisible(!data?.lower.visible)} + actionHandler={() => setMessage.lowerVisible(!data?.messages.lower.visible)} />
diff --git a/apps/client/src/features/control/playback/PlaybackButtons.tsx b/apps/client/src/features/control/playback/PlaybackButtons.tsx index 8902ebd7a..3fcffaefa 100644 --- a/apps/client/src/features/control/playback/PlaybackButtons.tsx +++ b/apps/client/src/features/control/playback/PlaybackButtons.tsx @@ -1,4 +1,4 @@ -import { Playback } from '../../../common/models/OntimeTypes'; +import { Playback } from 'ontime-types'; import PlaybackDisplay from './PlaybackDisplay'; import Transport from './Transport'; diff --git a/apps/client/src/features/control/playback/PlaybackControl.tsx b/apps/client/src/features/control/playback/PlaybackControl.tsx index 9f8f2ba25..aa8115709 100644 --- a/apps/client/src/features/control/playback/PlaybackControl.tsx +++ b/apps/client/src/features/control/playback/PlaybackControl.tsx @@ -1,5 +1,6 @@ +import { Playback } from 'ontime-types'; + import { usePlaybackControl } from '../../../common/hooks/useSocket'; -import { Playback } from '../../../common/models/OntimeTypes'; import PlaybackButtons from './PlaybackButtons'; import PlaybackTimer from './PlaybackTimer'; diff --git a/apps/client/src/features/control/playback/PlaybackDisplay.tsx b/apps/client/src/features/control/playback/PlaybackDisplay.tsx index 65a5ef6e2..f6f979ab4 100644 --- a/apps/client/src/features/control/playback/PlaybackDisplay.tsx +++ b/apps/client/src/features/control/playback/PlaybackDisplay.tsx @@ -1,9 +1,9 @@ import { IoPause } from '@react-icons/all-files/io5/IoPause'; import { IoPlay } from '@react-icons/all-files/io5/IoPlay'; import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline'; +import { Playback } from 'ontime-types'; import { setPlayback } from '../../../common/hooks/useSocket'; -import { Playback } from '../../../common/models/OntimeTypes'; import TapButton from './TapButton'; diff --git a/apps/client/src/features/control/playback/PlaybackTimer.tsx b/apps/client/src/features/control/playback/PlaybackTimer.tsx index 0af6d276b..98276ddd2 100644 --- a/apps/client/src/features/control/playback/PlaybackTimer.tsx +++ b/apps/client/src/features/control/playback/PlaybackTimer.tsx @@ -1,8 +1,8 @@ import { Tooltip } from '@chakra-ui/react'; +import { Playback } from 'ontime-types'; import TimerDisplay from '../../../common/components/timer-display/TimerDisplay'; import { setPlayback, useTimer } from '../../../common/hooks/useSocket'; -import { Playback } from '../../../common/models/OntimeTypes'; import { stringFromMillis } from '../../../common/utils/time'; import { tooltipDelayMid } from '../../../ontimeConfig'; diff --git a/apps/client/src/features/control/playback/TapButton.tsx b/apps/client/src/features/control/playback/TapButton.tsx index fc447a1fd..a0c7aa73d 100644 --- a/apps/client/src/features/control/playback/TapButton.tsx +++ b/apps/client/src/features/control/playback/TapButton.tsx @@ -1,6 +1,5 @@ import { ForwardedRef, forwardRef, PropsWithChildren } from 'react'; - -import { Playback } from '../../../common/models/OntimeTypes'; +import { Playback } from 'ontime-types'; import style from './TapButton.module.scss'; diff --git a/apps/client/src/features/control/playback/Transport.tsx b/apps/client/src/features/control/playback/Transport.tsx index 6cff7e1db..0eb74f38b 100644 --- a/apps/client/src/features/control/playback/Transport.tsx +++ b/apps/client/src/features/control/playback/Transport.tsx @@ -3,9 +3,9 @@ import { IoPlaySkipBack } from '@react-icons/all-files/io5/IoPlaySkipBack'; import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward'; import { IoReload } from '@react-icons/all-files/io5/IoReload'; import { IoStop } from '@react-icons/all-files/io5/IoStop'; +import { Playback } from 'ontime-types'; import { setPlayback } from '../../../common/hooks/useSocket'; -import { Playback } from '../../../common/models/OntimeTypes'; import { tooltipDelayMid } from '../../../ontimeConfig'; import TapButton from './TapButton'; diff --git a/apps/client/src/features/event-editor/EventEditor.tsx b/apps/client/src/features/event-editor/EventEditor.tsx index 20c0773ce..b97b81fb5 100644 --- a/apps/client/src/features/event-editor/EventEditor.tsx +++ b/apps/client/src/features/event-editor/EventEditor.tsx @@ -2,6 +2,7 @@ import { useCallback, useContext, useEffect, useState } from 'react'; import { Button, Select, Switch } from '@chakra-ui/react'; import { IoBan } from '@react-icons/all-files/io5/IoBan'; import { useAtom } from 'jotai'; +import { OntimeEvent } from 'ontime-types'; import { editorEventId } from '../../common/atoms/LocalEventSettings'; import CopyTag from '../../common/components/copy-tag/CopyTag'; @@ -11,7 +12,6 @@ import TimeInput from '../../common/components/input/time-input/TimeInput'; import { LoggingContext } from '../../common/context/LoggingContext'; import { useEventAction } from '../../common/hooks/useEventAction'; import useRundown from '../../common/hooks-query/useRundown'; -import { OntimeEvent } from '../../common/models/EventTypes'; import { millisToMinutes } from '../../common/utils/dateConfig'; import getDelayTo from '../../common/utils/getDelayTo'; import { stringFromMillis } from '../../common/utils/time'; diff --git a/apps/client/src/features/menu/RundownMenu.tsx b/apps/client/src/features/menu/RundownMenu.tsx index 10f4a15a2..47dcad255 100644 --- a/apps/client/src/features/menu/RundownMenu.tsx +++ b/apps/client/src/features/menu/RundownMenu.tsx @@ -4,10 +4,10 @@ import { FiMinusCircle } from '@react-icons/all-files/fi/FiMinusCircle'; import { FiTrash2 } from '@react-icons/all-files/fi/FiTrash2'; import { IoAdd } from '@react-icons/all-files/io5/IoAdd'; import { IoTimerOutline } from '@react-icons/all-files/io5/IoTimerOutline'; +import { SupportedEvent } from 'ontime-types'; import { CursorContext } from '../../common/context/CursorContext'; import { useEventAction } from '../../common/hooks/useEventAction'; -import { SupportedEvent } from '../../common/models/EventTypes'; import style from './RundownMenu.module.scss'; diff --git a/apps/client/src/features/modals/AppSettingsModal.jsx b/apps/client/src/features/modals/AppSettingsModal.jsx index f541302e3..8ecc39434 100644 --- a/apps/client/src/features/modals/AppSettingsModal.jsx +++ b/apps/client/src/features/modals/AppSettingsModal.jsx @@ -21,7 +21,7 @@ import { eventSettingsAtom } from '../../common/atoms/LocalEventSettings'; import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn'; import { LoggingContext } from '../../common/context/LoggingContext'; import useSettings from '../../common/hooks-query/useSettings'; -import { ontimePlaceholderSettings } from '../../common/models/OntimeSettings.type'; +import { ontimePlaceholderSettings } from '../../common/models/OntimeSettings'; import { inputProps } from './modalHelper'; import SubmitContainer from './SubmitContainer'; diff --git a/apps/client/src/features/modals/EventSettingsModal.jsx b/apps/client/src/features/modals/EventSettingsModal.jsx index da12197d9..b6f15c3af 100644 --- a/apps/client/src/features/modals/EventSettingsModal.jsx +++ b/apps/client/src/features/modals/EventSettingsModal.jsx @@ -1,10 +1,10 @@ import { useCallback, useContext, useEffect, useState } from 'react'; import { FormLabel, Input, ModalBody, Textarea } from '@chakra-ui/react'; -import { postEvent } from '../../common/api/eventApi'; +import { postEventData } from '../../common/api/eventDataApi'; import { LoggingContext } from '../../common/context/LoggingContext'; -import useEvent from '../../common/hooks-query/useEvent'; -import { eventDataPlaceholder } from '../../common/models/EventData.type'; +import useEventData from '../../common/hooks-query/useEventData'; +import { eventDataPlaceholder } from '../../common/models/EventData'; import { inputProps } from './modalHelper'; import SubmitContainer from './SubmitContainer'; @@ -12,7 +12,7 @@ import SubmitContainer from './SubmitContainer'; import style from './Modals.module.scss'; export default function SettingsModal() { - const { data, status, refetch } = useEvent(); + const { data, status, refetch } = useEventData(); const { emitError } = useContext(LoggingContext); const [formData, setFormData] = useState(eventDataPlaceholder); const [changed, setChanged] = useState(false); @@ -44,7 +44,7 @@ export default function SettingsModal() { setSubmitting(true); try { - await postEvent(formData); + await postEventData(formData); } catch (error) { emitError(`Error saving event settings: ${error}`); } finally { diff --git a/apps/client/src/features/modals/IntegrationSettingsModal.jsx b/apps/client/src/features/modals/IntegrationSettingsModal.jsx index 75af2b0a9..97030cc6c 100644 --- a/apps/client/src/features/modals/IntegrationSettingsModal.jsx +++ b/apps/client/src/features/modals/IntegrationSettingsModal.jsx @@ -4,7 +4,7 @@ import { FiInfo } from '@react-icons/all-files/fi/FiInfo'; import { LoggingContext } from '../../common/context/LoggingContext'; import useInfo from '../../common/hooks-query/useInfo'; -import { httpPlaceholder } from '../../common/models/Http.type'; +import { httpPlaceholder } from '../../common/models/Http'; import { ontimeVars } from '../../common/models/OntimeVars'; import { inputProps } from './modalHelper'; diff --git a/apps/client/src/features/modals/TableOptionsModal.jsx b/apps/client/src/features/modals/TableOptionsModal.jsx index 89c6c55d5..fd7193a9d 100644 --- a/apps/client/src/features/modals/TableOptionsModal.jsx +++ b/apps/client/src/features/modals/TableOptionsModal.jsx @@ -5,7 +5,7 @@ import { IoInformationCircleOutline } from '@react-icons/all-files/io5/IoInforma import { postUserFields } from '../../common/api/ontimeApi'; import { LoggingContext } from '../../common/context/LoggingContext'; import useUserFields from '../../common/hooks-query/useUserFields'; -import { userFieldsPlaceholder } from '../../common/models/UserFields.type'; +import { userFieldsPlaceholder } from '../../common/models/UserFields'; import { handleLinks, host } from '../../common/utils/linkUtils'; import SubmitContainer from './SubmitContainer'; diff --git a/apps/client/src/features/modals/integration-modal/OscIntegrationSettings.tsx b/apps/client/src/features/modals/integration-modal/OscIntegrationSettings.tsx index 390d1fbdb..917e7d02b 100644 --- a/apps/client/src/features/modals/integration-modal/OscIntegrationSettings.tsx +++ b/apps/client/src/features/modals/integration-modal/OscIntegrationSettings.tsx @@ -5,7 +5,7 @@ import { Button, FormControl, Input, ModalBody, ModalFooter, Switch } from '@cha import { postOSC } from '../../../common/api/ontimeApi'; import { LoggingContext } from '../../../common/context/LoggingContext'; import useOscSettings from '../../../common/hooks-query/useOscSettings'; -import { PlaceholderSettings } from '../../../common/models/OscSettings.type'; +import { PlaceholderSettings } from '../../../common/models/OscSettings'; import { isIPAddress, isOnlyNumbers } from '../../../common/utils/regex'; import styles from '../Modal.module.scss'; diff --git a/apps/client/src/features/modals/integration-modal/OscSettingsModal.jsx b/apps/client/src/features/modals/integration-modal/OscSettingsModal.jsx index 1ca63ae8f..a6d4f64e2 100644 --- a/apps/client/src/features/modals/integration-modal/OscSettingsModal.jsx +++ b/apps/client/src/features/modals/integration-modal/OscSettingsModal.jsx @@ -6,7 +6,7 @@ import { postOSC } from '../../../common/api/ontimeApi'; import EnableBtn from '../../../common/components/buttons/EnableBtn'; import { LoggingContext } from '../../../common/context/LoggingContext'; import useOscSettings from '../../../common/hooks-query/useOscSettings'; -import { oscPlaceholderSettings } from '../../../common/models/OscSettings.type'; +import { oscPlaceholderSettings } from '../../../common/models/OscSettings'; import { inputProps, portInputProps } from '../modalHelper'; import SubmitContainer from '../SubmitContainer'; diff --git a/apps/client/src/features/rundown/Rundown.tsx b/apps/client/src/features/rundown/Rundown.tsx index ed0a94de9..862341f83 100644 --- a/apps/client/src/features/rundown/Rundown.tsx +++ b/apps/client/src/features/rundown/Rundown.tsx @@ -3,14 +3,13 @@ import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd'; import { Button } from '@chakra-ui/react'; import { IoAdd } from '@react-icons/all-files/io5/IoAdd'; import { useAtomValue } from 'jotai'; -import PropTypes from 'prop-types'; +import { OntimeRundown, SupportedEvent } from 'ontime-types'; import { defaultPublicAtom, showQuickEntryAtom, startTimeIsLastEndAtom } from '../../common/atoms/LocalEventSettings'; import Empty from '../../common/components/state/Empty'; import { CursorContext } from '../../common/context/CursorContext'; import { useEventAction } from '../../common/hooks/useEventAction'; import { useRundownEditor } from '../../common/hooks/useSocket'; -import { OntimeRundown, SupportedEvent } from '../../common/models/EventTypes'; import { cloneEvent } from '../../common/utils/eventsManager'; import QuickAddBlock from './quick-add-block/QuickAddBlock'; @@ -25,8 +24,7 @@ interface RundownProps { export default function Rundown(props: RundownProps) { const { entries } = props; const { data } = useRundownEditor(); - const { cursor, moveCursorUp, moveCursorDown, moveCursorTo, isCursorLocked } = - useContext(CursorContext); + const { cursor, moveCursorUp, moveCursorDown, moveCursorTo, isCursorLocked } = useContext(CursorContext); const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom); const defaultPublic = useAtomValue(defaultPublicAtom); const { addEvent, reorderEvent } = useEventAction(); @@ -260,7 +258,3 @@ export default function Rundown(props: RundownProps) {
); } - -Rundown.propTypes = { - entries: PropTypes.array, -}; diff --git a/apps/client/src/features/rundown/RundownEntry.tsx b/apps/client/src/features/rundown/RundownEntry.tsx index c6f2e64e2..534ac88a5 100644 --- a/apps/client/src/features/rundown/RundownEntry.tsx +++ b/apps/client/src/features/rundown/RundownEntry.tsx @@ -1,12 +1,11 @@ import { useCallback, useContext } from 'react'; import { useAtom, useAtomValue } from 'jotai'; +import { OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent } from 'ontime-types'; import { defaultPublicAtom, editorEventId, startTimeIsLastEndAtom } from '../../common/atoms/LocalEventSettings'; import { CursorContext } from '../../common/context/CursorContext'; import { LoggingContext } from '../../common/context/LoggingContext'; import { useEventAction } from '../../common/hooks/useEventAction'; -import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../../common/models/EventTypes'; -import { Playback } from '../../common/models/OntimeTypes'; import { cloneEvent } from '../../common/utils/eventsManager'; import { calculateDuration } from '../../common/utils/timesManager'; @@ -14,14 +13,7 @@ import BlockBlock from './block-block/BlockBlock'; import DelayBlock from './delay-block/DelayBlock'; import EventBlock from './event-block/EventBlock'; -export type EventItemActions = - 'set-cursor' - | 'event' - | 'delay' - | 'block' - | 'delete' - | 'clone' - | 'update' +export type EventItemActions = 'set-cursor' | 'event' | 'delay' | 'block' | 'delete' | 'clone' | 'update'; interface RundownEntryProps { type: SupportedEvent; @@ -38,18 +30,7 @@ interface RundownEntryProps { } export default function RundownEntry(props: RundownEntryProps) { - const { - index, - eventIndex, - data, - selected, - hasCursor, - next, - delay, - previousEnd, - previousEventId, - playback, - } = props; + const { index, eventIndex, data, selected, hasCursor, next, delay, previousEnd, previousEventId, playback } = props; const { emitError } = useContext(LoggingContext); const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom); const defaultPublic = useAtomValue(defaultPublicAtom); @@ -61,7 +42,7 @@ export default function RundownEntry(props: RundownEntryProps) { type FieldValue = { field: keyof Omit | 'durationOverride'; value: unknown; - } + }; const actionHandler = useCallback( (action: EventItemActions, payload?: number | FieldValue) => { switch (action) { @@ -171,19 +152,11 @@ export default function RundownEntry(props: RundownEntryProps) { /> ); } else if (data.type === SupportedEvent.Block) { - return ; + // @ts-expect-error -- revise types here + return ; } else if (data.type === SupportedEvent.Delay) { - return ; + // @ts-expect-error -- revise types here + return ; } return null; } diff --git a/apps/client/src/features/rundown/block-block/BlockBlock.tsx b/apps/client/src/features/rundown/block-block/BlockBlock.tsx index 72abcfcf5..c319efcc2 100644 --- a/apps/client/src/features/rundown/block-block/BlockBlock.tsx +++ b/apps/client/src/features/rundown/block-block/BlockBlock.tsx @@ -1,8 +1,8 @@ import { useEffect, useRef } from 'react'; import { Draggable } from 'react-beautiful-dnd'; import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo'; +import { OntimeBlock, OntimeEvent } from 'ontime-types'; -import { OntimeBlock, OntimeEvent } from '../../../common/models/EventTypes'; import { cx } from '../../../common/utils/styleUtils'; import BlockActionMenu from '../event-block/composite/BlockActionMenu'; import { EventItemActions } from '../RundownEntry'; diff --git a/apps/client/src/features/rundown/delay-block/DelayBlock.tsx b/apps/client/src/features/rundown/delay-block/DelayBlock.tsx index 053806e8c..07a748fd0 100644 --- a/apps/client/src/features/rundown/delay-block/DelayBlock.tsx +++ b/apps/client/src/features/rundown/delay-block/DelayBlock.tsx @@ -3,11 +3,11 @@ import { Draggable } from 'react-beautiful-dnd'; import { Button, HStack } from '@chakra-ui/react'; import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark'; import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo'; +import { OntimeDelay, OntimeEvent } from 'ontime-types'; + import DelayInput from '../../../common/components/input/delay-input/DelayInput'; import { useEventAction } from '../../../common/hooks/useEventAction'; import { millisToMinutes } from '../../../common/utils/dateConfig'; - -import { OntimeDelay, OntimeEvent } from '../../../common/models/EventTypes'; import { cx } from '../../../common/utils/styleUtils'; import BlockActionMenu from '../event-block/composite/BlockActionMenu'; import { EventItemActions } from '../RundownEntry'; @@ -15,10 +15,10 @@ import { EventItemActions } from '../RundownEntry'; import style from './DelayBlock.module.scss'; interface DelayBlockProps { - data: OntimeDelay, + data: OntimeDelay; index: number; hasCursor: boolean; - actionHandler: (action: EventItemActions, payload?: number | { field: keyof OntimeEvent, value: unknown }) => void; + actionHandler: (action: EventItemActions, payload?: number | { field: keyof OntimeEvent; value: unknown }) => void; } export default function DelayBlock(props: DelayBlockProps) { @@ -30,7 +30,7 @@ export default function DelayBlock(props: DelayBlockProps) { if (hasCursor) { onFocusRef?.current?.focus(); } - }, [hasCursor]) + }, [hasCursor]); const applyDelayHandler = useCallback(() => { applyDelay(data.id); @@ -48,10 +48,7 @@ export default function DelayBlock(props: DelayBlockProps) { [data.id, updateEvent], ); - const blockClasses = cx([ - style.delay, - hasCursor ? style.hasCursor : null, - ]); + const blockClasses = cx([style.delay, hasCursor ? style.hasCursor : null]); const delayValue = data.duration != null ? millisToMinutes(data.duration) : undefined; @@ -62,17 +59,9 @@ export default function DelayBlock(props: DelayBlockProps) { - + - diff --git a/apps/client/src/features/rundown/event-block/EventBlock.tsx b/apps/client/src/features/rundown/event-block/EventBlock.tsx index 3a3c9219b..dd101ddcb 100644 --- a/apps/client/src/features/rundown/event-block/EventBlock.tsx +++ b/apps/client/src/features/rundown/event-block/EventBlock.tsx @@ -10,14 +10,14 @@ import { IoReload } from '@react-icons/all-files/io5/IoReload'; import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle'; import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline'; import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo'; +import { useAtom } from 'jotai'; +import { Playback } from 'ontime-types'; + import { editorEventId } from '../../../common/atoms/LocalEventSettings'; import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn'; -import { cx, getAccessibleColour } from '../../../common/utils/styleUtils'; -import { useAtom } from 'jotai'; - import { useEventAction } from '../../../common/hooks/useEventAction'; import { setEventPlayback } from '../../../common/hooks/useSocket'; -import { Playback } from '../../../common/models/OntimeTypes'; +import { cx, getAccessibleColour } from '../../../common/utils/styleUtils'; import { tooltipDelayMid } from '../../../ontimeConfig'; import { EventItemActions } from '../RundownEntry'; @@ -129,11 +129,7 @@ export default function EventBlock(props: EventBlockProps) { return ( {(provided) => ( -
+
-
- +
+ - + - + @@ -234,7 +221,7 @@ export default function EventBlock(props: EventBlockProps) { variant='ontime-subtle-white' size='sm' icon={} - clickHandler={() => setOpenId((prev) => prev === eventId ? null : eventId)} + clickHandler={() => setOpenId((prev) => (prev === eventId ? null : eventId))} tooltip='Event options' aria-label='Event options' tabIndex={-1} diff --git a/apps/client/src/features/rundown/event-block/composite/EventBlockProgressBar.tsx b/apps/client/src/features/rundown/event-block/composite/EventBlockProgressBar.tsx index 37fc124ce..13574382c 100644 --- a/apps/client/src/features/rundown/event-block/composite/EventBlockProgressBar.tsx +++ b/apps/client/src/features/rundown/event-block/composite/EventBlockProgressBar.tsx @@ -1,5 +1,6 @@ +import { Playback } from 'ontime-types'; + import { useTimer } from '../../../../common/hooks/useSocket'; -import { Playback } from '../../../../common/models/OntimeTypes'; import { clamp } from '../../../../common/utils/math'; import style from './EventBlockProgressBar.module.scss'; diff --git a/apps/client/src/features/rundown/quick-add-block/QuickAddBlock.tsx b/apps/client/src/features/rundown/quick-add-block/QuickAddBlock.tsx index fe0bcb237..cb534c0c3 100644 --- a/apps/client/src/features/rundown/quick-add-block/QuickAddBlock.tsx +++ b/apps/client/src/features/rundown/quick-add-block/QuickAddBlock.tsx @@ -1,11 +1,11 @@ import { useCallback, useContext, useRef } from 'react'; import { Button, Checkbox, Tooltip } from '@chakra-ui/react'; +import { useAtomValue } from 'jotai'; +import { SupportedEvent } from 'ontime-types'; + import { defaultPublicAtom, startTimeIsLastEndAtom } from '../../../common/atoms/LocalEventSettings'; import { LoggingContext } from '../../../common/context/LoggingContext'; import { useEventAction } from '../../../common/hooks/useEventAction'; -import { SupportedEvent } from '../../../common/models/EventTypes'; -import { useAtomValue } from 'jotai'; - import { tooltipDelayMid } from '../../../ontimeConfig'; import style from './QuickAddBlock.module.scss'; @@ -19,13 +19,7 @@ interface QuickAddBlockProps { } export default function QuickAddBlock(props: QuickAddBlockProps) { - const { - showKbd, - eventId, - previousEventId, - disableAddDelay = true, - disableAddBlock, - } = props; + const { showKbd, eventId, previousEventId, disableAddDelay = true, disableAddBlock } = props; const { addEvent } = useEventAction(); const { emitError } = useContext(LoggingContext); const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom); @@ -33,45 +27,47 @@ export default function QuickAddBlock(props: QuickAddBlockProps) { const doStartTime = useRef(null); const doPublic = useRef(null); - const handleCreateEvent = useCallback((eventType: SupportedEvent) => { - switch (eventType) { - case 'event': { - const isPublicOption = doPublic?.current?.checked; - const startTimeIsLastEndOption = doStartTime?.current?.checked; + const handleCreateEvent = useCallback( + (eventType: SupportedEvent) => { + switch (eventType) { + case 'event': { + const isPublicOption = doPublic?.current?.checked; + const startTimeIsLastEndOption = doStartTime?.current?.checked; - const newEvent = { type: SupportedEvent.Event }; - const options = { - defaultPublic: isPublicOption, - startTimeIsLastEnd: startTimeIsLastEndOption, - lastEventId: previousEventId, - after: eventId, - }; - addEvent(newEvent, options); - break; - } - case 'delay': { - const options = { - lastEventId: previousEventId, - after: eventId, + const newEvent = { type: SupportedEvent.Event }; + const options = { + defaultPublic: isPublicOption, + startTimeIsLastEnd: startTimeIsLastEndOption, + lastEventId: previousEventId, + after: eventId, + }; + addEvent(newEvent, options); + break; } - addEvent({ type: SupportedEvent.Delay }, options); - break; - } - case 'block': { - const options= { - lastEventId: previousEventId, - after: eventId, + case 'delay': { + const options = { + lastEventId: previousEventId, + after: eventId, + }; + addEvent({ type: SupportedEvent.Delay }, options); + break; + } + case 'block': { + const options = { + lastEventId: previousEventId, + after: eventId, + }; + addEvent({ type: SupportedEvent.Block }, options); + break; + } + default: { + emitError(`Cannot create unknown event type: ${eventType}`); + break; } - addEvent({ type: SupportedEvent.Block }, options); - break; } - default: { - emitError(`Cannot create unknown event type: ${eventType}`); - break; - } - } - - }, [previousEventId, eventId, addEvent, emitError]); + }, + [previousEventId, eventId, addEvent, emitError], + ); return (
@@ -110,20 +106,10 @@ export default function QuickAddBlock(props: QuickAddBlockProps) {
- + Start time is last end - + Event is public
diff --git a/apps/client/src/features/table/TableHeader.jsx b/apps/client/src/features/table/TableHeader.jsx index 771f6a5f2..7f78787be 100644 --- a/apps/client/src/features/table/TableHeader.jsx +++ b/apps/client/src/features/table/TableHeader.jsx @@ -10,7 +10,7 @@ import PropTypes from 'prop-types'; import { TableSettingsContext } from '../../common/context/TableSettingsContext'; import useFullscreen from '../../common/hooks/useFullscreen'; import { useTimer } from '../../common/hooks/useSocket'; -import useEvent from '../../common/hooks-query/useEvent'; +import useEventData from '../../common/hooks-query/useEventData'; import { formatDisplay, millisToSeconds } from '../../common/utils/dateConfig'; import { formatTime } from '../../common/utils/time'; import { tooltipDelayFast } from '../../ontimeConfig'; @@ -24,7 +24,7 @@ export default function TableHeader({ handleCSVExport, featureData }) { useContext(TableSettingsContext); const { data: timer } = useTimer(); const { isFullScreen, toggleFullScreen } = useFullscreen(); - const { data: event } = useEvent(); + const { data: event } = useEventData(); const selected = !featureData.numEvents ? 'No events' diff --git a/apps/client/src/features/viewers/ViewWrapper.jsx b/apps/client/src/features/viewers/ViewWrapper.jsx index 6eb743f87..90a58348b 100644 --- a/apps/client/src/features/viewers/ViewWrapper.jsx +++ b/apps/client/src/features/viewers/ViewWrapper.jsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'react'; import { useMessageControl } from '../../common/hooks/useSocket'; import useSubscription from '../../common/hooks/useSubscription'; -import useEvent from '../../common/hooks-query/useEvent'; +import useEventData from '../../common/hooks-query/useEventData'; import useRundown from '../../common/hooks-query/useRundown'; import useViewSettings from '../../common/hooks-query/useViewSettings'; import socket from '../../common/utils/socket'; @@ -11,13 +11,13 @@ import socket from '../../common/utils/socket'; const withSocket = (Component) => { return (props) => { const { data: eventsData } = useRundown(); - const { data: genData } = useEvent(); + const { data: genData } = useEventData(); const { data: viewSettings } = useViewSettings(); - const { data: messages } = useMessageControl(); + const { data: messageControl } = useMessageControl(); const [publicSelectedId, setPublicSelectedId] = useState(null); - const [timer] = useSubscription('ontime-timer', { + const [timer] = useSubscription('timer', { clock: null, current: null, elapsed: null , @@ -123,9 +123,9 @@ const withSocket = (Component) => { return ( { viewSettings={viewSettings} nextId={nextId} general={genData} - onAir={messages.onAir} + onAir={messageControl.onAir} /> ); }; diff --git a/apps/client/src/features/viewers/clock/Clock.tsx b/apps/client/src/features/viewers/clock/Clock.tsx index 1715c41b3..59bf0506e 100644 --- a/apps/client/src/features/viewers/clock/Clock.tsx +++ b/apps/client/src/features/viewers/clock/Clock.tsx @@ -1,21 +1,21 @@ import { useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useAtom } from 'jotai'; +import { ViewSettings } from 'ontime-types'; import { overrideStylesURL } from '../../../common/api/apiConstants'; import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings'; import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu'; import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet'; import { TimeManagerType } from '../../../common/models/TimeManager.type'; -import { ViewSettingsType } from '../../../common/models/ViewSettings.type'; -import { OverridableOptions } from '../../../common/models/ViewTypes'; +import { OverridableOptions } from '../../../common/models/View.types'; import { formatTime } from '../../../common/utils/time'; import './Clock.scss'; interface ClockProps { time: TimeManagerType; - viewSettings: ViewSettingsType; + viewSettings: ViewSettings; } const formatOptions = { diff --git a/apps/client/src/features/viewers/countdown/Countdown.tsx b/apps/client/src/features/viewers/countdown/Countdown.tsx index 39f8d8b9e..c7d457d08 100644 --- a/apps/client/src/features/viewers/countdown/Countdown.tsx +++ b/apps/client/src/features/viewers/countdown/Countdown.tsx @@ -1,13 +1,13 @@ import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useAtom } from 'jotai'; +import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from 'ontime-types'; import PropTypes from 'prop-types'; import { overrideStylesURL } from '../../../common/api/apiConstants'; import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings'; import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu'; import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet'; -import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../../../common/models/EventTypes'; import { formatDisplay, millisToSeconds } from '../../../common/utils/dateConfig'; import getDelayTo from '../../../common/utils/getDelayTo'; import { formatTime } from '../../../common/utils/time'; diff --git a/apps/client/src/features/viewers/countdown/CountdownSelect.tsx b/apps/client/src/features/viewers/countdown/CountdownSelect.tsx index 0006b5cc2..b5091ccd0 100644 --- a/apps/client/src/features/viewers/countdown/CountdownSelect.tsx +++ b/apps/client/src/features/viewers/countdown/CountdownSelect.tsx @@ -1,7 +1,7 @@ import { Link } from 'react-router-dom'; +import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from 'ontime-types'; import Empty from '../../../common/components/state/Empty'; -import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../../../common/models/EventTypes'; import { formatTime } from '../../../common/utils/time'; import { sanitiseTitle } from './countdown.helpers'; diff --git a/apps/client/src/features/viewers/countdown/countdown.helpers.ts b/apps/client/src/features/viewers/countdown/countdown.helpers.ts index df14c6f2e..a39e193f8 100644 --- a/apps/client/src/features/viewers/countdown/countdown.helpers.ts +++ b/apps/client/src/features/viewers/countdown/countdown.helpers.ts @@ -1,4 +1,5 @@ -import { OntimeEvent } from '../../../common/models/EventTypes'; +import { OntimeEvent } from 'ontime-types'; + import { TimeManagerType } from '../../../common/models/TimeManager.type'; export enum TimerMessage { diff --git a/apps/client/src/features/viewers/minimal-timer/MinimalTimer.tsx b/apps/client/src/features/viewers/minimal-timer/MinimalTimer.tsx index 3d2efcb51..0d232c076 100644 --- a/apps/client/src/features/viewers/minimal-timer/MinimalTimer.tsx +++ b/apps/client/src/features/viewers/minimal-timer/MinimalTimer.tsx @@ -1,25 +1,23 @@ import { useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { EventDataType } from 'common/models/EventData.type'; import { useAtom } from 'jotai'; +import { EventData, Message, ViewSettings } from 'ontime-types'; import { overrideStylesURL } from '../../../common/api/apiConstants'; import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings'; import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu'; import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet'; -import { PresenterMessageType } from '../../../common/models/PresenterMessage.type'; import { TimeManagerType } from '../../../common/models/TimeManager.type'; -import { ViewSettingsType } from '../../../common/models/ViewSettings.type'; -import { OverridableOptions } from '../../../common/models/ViewTypes'; +import { OverridableOptions } from '../../../common/models/View.types'; import { formatDisplay, millisToSeconds } from '../../../common/utils/dateConfig'; import './MinimalTimer.scss'; interface MinimalTimerProps { - pres: PresenterMessageType; + pres: Message; time: TimeManagerType; - viewSettings: ViewSettingsType; - general: EventDataType; + viewSettings: ViewSettings; + general: EventData; } export default function MinimalTimer(props: MinimalTimerProps) { diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index e90117ffd..d97cdb6af 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -14,7 +14,7 @@ import { OSCSettings } from 'ontime-types'; // Import Routes import { router as rundownRouter } from './routes/rundownRouter.js'; -import { router as eventRouter } from './routes/eventRouter.js'; +import { router as eventDataRouter } from './routes/eventDataRouter.js'; import { router as ontimeRouter } from './routes/ontimeRouter.js'; import { router as playbackRouter } from './routes/playbackRouter.js'; @@ -54,7 +54,7 @@ app.use(express.json({ limit: '1mb' })); // Implement route endpoints app.use('/eventlist', rundownRouter); -app.use('/event', eventRouter); +app.use('/eventdata', eventDataRouter); app.use('/ontime', ontimeRouter); app.use('/playback', playbackRouter); @@ -100,7 +100,7 @@ enum OntimeStartOrder { } let step = OntimeStartOrder.InitDB; -const checkStart = (currentState) => { +const checkStart = (currentState: OntimeStartOrder) => { if (step !== currentState) { step = OntimeStartOrder.Error; throw new Error('Init order error: startDb > startServer > startOsc > startIntegrations'); @@ -131,8 +131,6 @@ export const startServer = async () => { expressServer.listen(serverPort, '0.0.0.0'); socketServer.initServer(expressServer); - socketServer.info('SERVER', 'Socket initialised'); - socketServer.info('SERVER', returnMessage); socketServer.startListener(); diff --git a/apps/server/src/classes/data-provider/DataProvider.ts b/apps/server/src/classes/data-provider/DataProvider.ts index 120f4f5d4..00eea2053 100644 --- a/apps/server/src/classes/data-provider/DataProvider.ts +++ b/apps/server/src/classes/data-provider/DataProvider.ts @@ -2,6 +2,8 @@ * Class Event Provider is a mediator for handling the local db * and adds logic specific to ontime data */ +import { EventData, ViewSettings } from 'ontime-types'; + import { data, db } from '../../modules/loadDb.js'; import { safeMerge } from './DataProvider.utils.js'; @@ -10,14 +12,14 @@ export class DataProvider { return data; } - static async setEventData(newData) { - data.event = { ...data.event, ...newData }; + static async setEventData(newData: EventData) { + data.eventData = { ...data.eventData, ...newData }; await this.persist(); - return data.event; + return data.eventData; } static getEventData() { - return data.event; + return data.eventData; } static async setRundown(newData) { @@ -40,7 +42,6 @@ export class DataProvider { } static async deleteEvent(eventId) { - // @ts-expect-error -- this will go away once we type db data.rundown = Array.from(data.rundown).filter((e) => e.id !== eventId); await this.persist(); } @@ -128,12 +129,12 @@ export class DataProvider { return { ...data.userFields }; } - static getViews() { - return { ...data.views }; + static getViewSettings() { + return { ...data.viewSettings }; } - static async setViews(newData) { - data.views = { ...newData }; + static async setViewSettings(newData: ViewSettings) { + data.viewSettings = { ...newData }; await this.persist(); } @@ -158,8 +159,9 @@ export class DataProvider { static async mergeIntoData(newData) { const mergedData = safeMerge(data, newData); - data.event = mergedData.event; + data.eventData = mergedData.event; data.settings = mergedData.settings; + data.viewSettings = mergedData.viewSettings; data.osc = mergedData.osc; data.http = mergedData.http; data.aliases = mergedData.aliases; diff --git a/apps/server/src/classes/data-provider/DataProvider.utils.ts b/apps/server/src/classes/data-provider/DataProvider.utils.ts index 6df6c5cff..f2ecd7560 100644 --- a/apps/server/src/classes/data-provider/DataProvider.utils.ts +++ b/apps/server/src/classes/data-provider/DataProvider.utils.ts @@ -4,15 +4,13 @@ * @param {object} newData */ export function safeMerge(existing, newData) { - const { rundown, event, settings, osc, http, aliases, userFields } = newData || {}; + const { rundown, event, settings, viewSettings, osc, http, aliases, userFields } = newData || {}; return { ...existing, rundown: rundown ?? existing.rundown, event: { ...existing.event, ...event }, settings: { ...existing.settings, ...settings }, - views: { - overrideStyles: false, - }, + viewSettings: { ...existing.viewSettings, ...viewSettings }, aliases: aliases ?? existing.aliases, userFields: { ...existing.userFields, diff --git a/apps/server/src/classes/event-loader/EventLoader.js b/apps/server/src/classes/event-loader/EventLoader.ts similarity index 87% rename from apps/server/src/classes/event-loader/EventLoader.js rename to apps/server/src/classes/event-loader/EventLoader.ts index 9e9c24fd5..1f278be38 100644 --- a/apps/server/src/classes/event-loader/EventLoader.js +++ b/apps/server/src/classes/event-loader/EventLoader.ts @@ -1,12 +1,34 @@ -import { DataProvider } from '../data-provider/DataProvider.ts'; +import { DataProvider } from '../data-provider/DataProvider.js'; import { getRollTimers } from '../../services/rollUtils.js'; +import { eventStore } from '../../stores/EventStore.js'; let instance; +type TitleBlock = { + titleNow: string | null; + subtitleNow: string | null; + presenterNow: string | null; + noteNow: string | null; + titleNext: string | null; + subtitleNext: string | null; + presenterNext: string | null; + noteNext: string | null; +}; + /** * Manages business logic around loading events */ export class EventLoader { + loadedEvent: object | null; + numEvents: number | null; + selectedEventIndex: number | null; + selectedEventId: string | null; + selectedPublicEventId: string | null; + nextEventId: string | null; + nextPublicEventId: string | null; + titles: TitleBlock; + titlesPublic: TitleBlock; + constructor() { if (instance) { throw new Error('There can be only one'); @@ -14,7 +36,7 @@ export class EventLoader { // eslint-disable-next-line @typescript-eslint/no-this-alias -- this logic is used to ensure singleton instance = this; - this.reset(); + this.reset(false); this.loadedEvent = null; } @@ -119,11 +141,7 @@ export class EventLoader { */ findNext() { const timedEvents = EventLoader.getPlayableEvents(); - if ( - timedEvents === null || - !timedEvents.length || - this.selectedEventIndex === this.numEvents - 1 - ) { + if (timedEvents === null || !timedEvents.length || this.selectedEventIndex === this.numEvents - 1) { return null; } @@ -145,15 +163,8 @@ export class EventLoader { return null; } - const { - nowIndex, - timers, - timeToNext, - nextEvent, - nextPublicEvent, - currentEvent, - currentPublicEvent, - } = getRollTimers(timedEvents, timeNow); + const { nowIndex, timers, timeToNext, nextEvent, nextPublicEvent, currentEvent, currentPublicEvent } = + getRollTimers(timedEvents, timeNow); this.loadedEvent = currentEvent; this.selectedEventIndex = nowIndex; @@ -187,7 +198,10 @@ export class EventLoader { }; } - reset() { + /** + * Resets instance state + */ + reset(emit?: boolean) { this.loadedEvent = null; this.selectedEventIndex = null; this.selectedEventId = null; @@ -209,10 +223,17 @@ export class EventLoader { titleNow: null, subtitleNow: null, presenterNow: null, + noteNow: null, titleNext: null, subtitleNext: null, presenterNext: null, + noteNext: null, }; + + // workaround for socket not being ready in constructor + if (emit) { + this._loadEvent(); + } } /** @@ -236,16 +257,26 @@ export class EventLoader { this._loadTitlesNow(event, playableEvents); this._loadTitlesNext(playableEvents); + this._loadEvent(); + return this.getLoaded(); } + /** + * Handle side effects from event loading + */ + private _loadEvent() { + eventStore.set('titles', this.titles); + eventStore.set('titlesPublic', this.titlesPublic); + } + /** * @description loads given title (now) * @private * @param {object} event * @param {array} rundown */ - _loadTitlesNow(event, rundown) { + private _loadTitlesNow(event, rundown) { // private title is always current // check if current is also public if (event.isPublic) { @@ -276,8 +307,7 @@ export class EventLoader { * @description look for next titles to load * @private */ - _loadTitlesNext(rundown) { - // Todo: is there a scenario where this gets called without an event? + private _loadTitlesNext(rundown) { // maybe there is nothing to load if (this.selectedEventIndex === null) return; @@ -324,7 +354,7 @@ export class EventLoader { * @param type * @private */ - _loadThisTitles(event, type) { + private _loadThisTitles(event, type) { if (!event) { return; } @@ -336,6 +366,7 @@ export class EventLoader { this.titlesPublic.titleNow = event.title; this.titlesPublic.subtitleNow = event.subtitle; this.titlesPublic.presenterNow = event.presenter; + this.titlesPublic.noteNow = event.note; this.selectedPublicEventId = event.id; // private @@ -350,6 +381,7 @@ export class EventLoader { this.titlesPublic.titleNow = event.title; this.titlesPublic.subtitleNow = event.subtitle; this.titlesPublic.presenterNow = event.presenter; + this.titlesPublic.noteNow = event.note; this.selectedPublicEventId = event.id; break; @@ -367,6 +399,7 @@ export class EventLoader { this.titlesPublic.titleNext = event.title; this.titlesPublic.subtitleNext = event.subtitle; this.titlesPublic.presenterNext = event.presenter; + this.titlesPublic.noteNext = event.note; this.nextPublicEventId = event.id; // private @@ -381,6 +414,7 @@ export class EventLoader { this.titlesPublic.titleNext = event.title; this.titlesPublic.subtitleNext = event.subtitle; this.titlesPublic.presenterNext = event.presenter; + this.titlesPublic.noteNext = event.note; this.nextPublicEventId = event.id; break; diff --git a/apps/server/src/classes/message-manager/MessageManager.js b/apps/server/src/classes/message-manager/MessageManager.js deleted file mode 100644 index 3a88aa762..000000000 --- a/apps/server/src/classes/message-manager/MessageManager.js +++ /dev/null @@ -1,104 +0,0 @@ -let instance; - -class MessageService { - constructor() { - if (instance) { - throw new Error('There can be only one'); - } - - // eslint-disable-next-line @typescript-eslint/no-this-alias -- this logic is used to ensure singleton - instance = this; - this.socket = null; - - this.presenter = { - text: '', - visible: false, - }; - this.public = { - text: '', - visible: false, - }; - this.lower = { - text: '', - visible: false, - }; - this.onAir = false; - } - - /** - * @description sets message on stage timer screen - * @param payload {string} - */ - setTimerText(payload) { - this.presenter.text = payload; - return this.getAll(); - } - - /** - * @description sets message visibility on stage timer screen - * @param status {boolean} - */ - setTimerVisibility(status) { - this.presenter.visible = status; - return this.getAll(); - } - - /** - * @description sets message on public screen - * @param payload {string} - */ - setPublicText(payload) { - this.public.text = payload; - return this.getAll(); - } - - /** - * @description sets message visibility on public screen - * @param status {boolean} - */ - setPublicVisibility(status) { - this.public.visible = status; - return this.getAll(); - } - - /** - * @description sets message on lower third screen - * @param payload {string} - */ - setLowerText(payload) { - this.lower.text = payload; - return this.getAll(); - } - - /** - * @description sets message visibility on lower third screen - * @param status {boolean} - */ - setLowerVisibility(status) { - this.lower.visible = status; - return this.getAll(); - } - - /** - * @description set state of onAir - * @param status {boolean} - */ - setOnAir(status) { - this.onAir = status; - return this.getAll(); - } - - /** - * @description Returns feature data - */ - getAll() { - return { - presenter: this.presenter, - public: this.public, - lower: this.lower, - onAir: this.onAir, - }; - } -} - -export const messageManager = new MessageService(); diff --git a/apps/server/src/classes/message-manager/MessageManager.ts b/apps/server/src/classes/message-manager/MessageManager.ts new file mode 100644 index 000000000..12b54b315 --- /dev/null +++ b/apps/server/src/classes/message-manager/MessageManager.ts @@ -0,0 +1,109 @@ +import { MessageControl } from 'ontime-types'; + +import { eventStore } from '../../stores/EventStore.js'; + +let instance; + +class MessageService { + messages: MessageControl; + onAir: boolean; + + constructor() { + if (instance) { + throw new Error('There can be only one'); + } + + // eslint-disable-next-line @typescript-eslint/no-this-alias -- this logic is used to ensure singleton + instance = this; + + this.messages = { + presenter: { + text: '', + visible: false, + }, + public: { + text: '', + visible: false, + }, + lower: { + text: '', + visible: false, + }, + }; + this.onAir = false; + } + + /** + * @description sets message on stage timer screen + */ + setTimerText(payload: string) { + this.messages.presenter.text = payload; + eventStore.set('feat-messagecontrol', { messages: this.messages }); + return this.getAll(); + } + + /** + * @description sets message visibility on stage timer screen + */ + setTimerVisibility(status: boolean) { + this.messages.presenter.visible = status; + eventStore.set('feat-messagecontrol', { messages: this.messages }); + return this.getAll(); + } + + /** + * @description sets message on public screen + */ + setPublicText(payload: string) { + this.messages.public.text = payload; + eventStore.set('feat-messagecontrol', { messages: this.messages }); + return this.getAll(); + } + + /** + * @description sets message visibility on public screen + */ + setPublicVisibility(status: boolean) { + this.messages.public.visible = status; + eventStore.set('feat-messagecontrol', { messages: this.messages }); + return this.getAll(); + } + + /** + * @description sets message on lower third screen + */ + setLowerText(payload: string) { + this.messages.lower.text = payload; + eventStore.set('feat-messagecontrol', { messages: this.messages }); + return this.getAll(); + } + + /** + * @description sets message visibility on lower third screen + */ + setLowerVisibility(status: boolean) { + this.messages.lower.visible = status; + eventStore.set('feat-messagecontrol', { messages: this.messages }); + return this.getAll(); + } + + /** + * @description set state of onAir + */ + setOnAir(status: boolean) { + this.onAir = status; + return this.getAll(); + } + + /** + * @description Returns feature data + */ + getAll() { + return { + messages: this.messages, + onAir: this.onAir, + }; + } +} + +export const messageManager = new MessageService(); diff --git a/apps/server/src/classes/socket/SocketController.js b/apps/server/src/classes/socket/SocketController.js index bfc48ba09..97ad8d41d 100644 --- a/apps/server/src/classes/socket/SocketController.js +++ b/apps/server/src/classes/socket/SocketController.js @@ -6,8 +6,7 @@ import { stringFromMillis } from '../../utils/time.js'; import { messageManager } from '../message-manager/MessageManager.js'; import { PlaybackService } from '../../services/PlaybackService.js'; -import { ADDRESS_MESSAGE_CONTROL } from './socketConfig.js'; -import { eventTimer, TimerService } from '../../services/TimerService.ts'; +import { eventTimer, TimerService } from '../../services/TimerService.js'; import { EventLoader, eventLoader } from '../event-loader/EventLoader.js'; class SocketController { @@ -55,9 +54,7 @@ class SocketController { // keep track of connections this.numClients++; this._clientNames[socket.id] = getRandomName(); - const message = `${this.numClients} Clients with new connection: ${ - this._clientNames[socket.id] - }`; + const message = `${this.numClients} Clients with new connection: ${this._clientNames[socket.id]}`; this.info('CLIENT', message); // Todo: review in favour of features @@ -78,9 +75,7 @@ class SocketController { */ socket.on('disconnect', () => { this.numClients--; - const message = `${this.numClients} Clients with disconnection: ${ - this._clientNames[socket.id] - }`; + const message = `${this.numClients} Clients with disconnection: ${this._clientNames[socket.id]}`; delete this._clientNames[socket.id]; this.info('CLIENT', message); }); @@ -215,12 +210,10 @@ class SocketController { try { const featureData = messageManager.setOnAir(data); this.info('PLAYBACK', featureData.onAir ? 'Going On Air' : 'Going Off Air'); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); } catch (error) { this.error('RX', `Failed to parse message ${data} : ${error}`); } } - this.send('onAir', messageManager.onAir); }); // Presenter message @@ -228,16 +221,14 @@ class SocketController { if (typeof data !== 'string') { return; } - const featureData = messageManager.setTimerText(data); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setTimerText(data); }); socket.on('set-timer-message-visible', (data) => { if (typeof data !== 'boolean') { return; } - const featureData = messageManager.setTimerVisibility(data); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setTimerVisibility(data); }); /*******************************************/ @@ -246,16 +237,14 @@ class SocketController { if (typeof data !== 'string') { return; } - const featureData = messageManager.setPublicText(data); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setPublicText(data); }); socket.on('set-public-message-visible', (data) => { if (typeof data !== 'boolean') { return; } - const featureData = messageManager.setPublicVisibility(data); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setPublicVisibility(data); }); /*******************************************/ @@ -264,16 +253,14 @@ class SocketController { if (typeof data !== 'string') { return; } - const featureData = messageManager.setLowerText(data); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setLowerText(data); }); socket.on('set-lower-message-visible', (data) => { if (typeof data !== 'boolean') { return; } - const featureData = messageManager.setLowerVisibility(data); - this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setLowerVisibility(data); }); /* MOLECULAR ENDPOINTS @@ -312,8 +299,9 @@ class SocketController { }); // 6. TIMER - socket.on('get-ontime-timer', () => { - this.broadcastTimer(); + socket.on('get-timer', () => { + // TODO: Not ideal workaround + socket.emit('timer', eventTimer.timer); }); }); } @@ -373,7 +361,7 @@ class SocketController { */ broadcastFeatureMessageControl() { const featureData = messageManager.getAll(); - this.send(ADDRESS_MESSAGE_CONTROL, featureData); + this.send('feat-messagecontrol', featureData); } /** @@ -416,21 +404,14 @@ class SocketController { this.send('feat-cuesheet', featureData); } - /** - * Broadcast Timer feature - */ - broadcastTimer() { - const featureData = eventTimer.timer; - this.send('ontime-timer', featureData); - } - + // TODO: ouch, services should update the store + // make middleware to maintain the features OR remove the feature endpoints broadcastState() { this.broadcastFeatureRundown(); this.broadcastFeatureMessageControl(); this.broadcastFeaturePlaybackControl(); this.broadcastFeatureInfo(); this.broadcastFeatureCuesheet(); - this.broadcastTimer(); } /** diff --git a/apps/server/src/classes/socket/socketConfig.js b/apps/server/src/classes/socket/socketConfig.js deleted file mode 100644 index f82131e75..000000000 --- a/apps/server/src/classes/socket/socketConfig.js +++ /dev/null @@ -1 +0,0 @@ -export const ADDRESS_MESSAGE_CONTROL = 'feat-messagecontrol'; diff --git a/apps/server/src/controllers/OscController.ts b/apps/server/src/controllers/OscController.ts index 5354eb9c5..bd2bc41eb 100644 --- a/apps/server/src/controllers/OscController.ts +++ b/apps/server/src/controllers/OscController.ts @@ -4,7 +4,6 @@ import { OSCSettings } from 'ontime-types'; import { PlaybackService } from '../services/PlaybackService.js'; import { messageManager } from '../classes/message-manager/MessageManager.js'; import { socketProvider } from '../classes/socket/SocketController.js'; -import { ADDRESS_MESSAGE_CONTROL } from '../classes/socket/socketConfig.js'; let oscServer = null; @@ -47,13 +46,11 @@ export const initiateOSC = (config: OSCSettings) => { switch (path.toLowerCase()) { case 'onair': { - const featureData = messageManager.setOnAir(true); - socketProvider.send(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setOnAir(true); break; } case 'offair': { - const featureData = messageManager.setOnAir(false); - socketProvider.send(ADDRESS_MESSAGE_CONTROL, featureData); + messageManager.setOnAir(false); break; } case 'play': { diff --git a/apps/server/src/controllers/eventController.js b/apps/server/src/controllers/eventDataController.js similarity index 100% rename from apps/server/src/controllers/eventController.js rename to apps/server/src/controllers/eventDataController.js diff --git a/apps/server/src/controllers/eventController.validate.js b/apps/server/src/controllers/eventDataController.validate.js similarity index 100% rename from apps/server/src/controllers/eventController.validate.js rename to apps/server/src/controllers/eventDataController.validate.js diff --git a/apps/server/src/controllers/ontimeController.js b/apps/server/src/controllers/ontimeController.js index 393e48671..2a258c8ae 100644 --- a/apps/server/src/controllers/ontimeController.js +++ b/apps/server/src/controllers/ontimeController.js @@ -2,18 +2,18 @@ import fs from 'fs'; import { networkInterfaces } from 'os'; import { generateId } from 'ontime-utils'; import { fileHandler } from '../utils/parser.js'; -import { DataProvider } from '../classes/data-provider/DataProvider.ts'; +import { DataProvider } from '../classes/data-provider/DataProvider.js'; import { failEmptyObjects, failIsNotArray } from '../utils/routerUtils.js'; import { mergeObject } from '../utils/parserUtils.js'; import { PlaybackService } from '../services/PlaybackService.js'; -import { runtimeState } from '../stores/EventStore.js'; +import { eventStore } from '../stores/EventStore.js'; import { resolveDbPath } from '../setup.js'; // Create controller for GET request to '/ontime/poll' // Returns data for current state export const poll = async (req, res) => { try { - const s = runtimeState.poll(); + const s = eventStore.poll(); res.status(200).send(s); } catch (error) { res.status(500).send({ @@ -225,7 +225,7 @@ export const postSettings = async (req, res) => { * @method GET */ export const getViewSettings = async (req, res) => { - const views = DataProvider.getViews(); + const views = DataProvider.getViewSettings(); res.status(200).send(views); }; @@ -240,7 +240,7 @@ export const postViewSettings = async (req, res) => { try { const newData = { overrideStyles: req.body.overrideStyles }; - await DataProvider.setViews(newData); + await DataProvider.setViewSettings(newData); res.status(200).send(newData); } catch (error) { res.status(400).send(error); diff --git a/apps/server/src/controllers/rundownController.js b/apps/server/src/controllers/rundownController.js index 32e7bbcfa..24c652572 100644 --- a/apps/server/src/controllers/rundownController.js +++ b/apps/server/src/controllers/rundownController.js @@ -7,7 +7,7 @@ import { deleteEvent, editEvent, reorderEvent, -} from '../services/RundownService.js'; +} from '../services/RundownService.ts'; // Create controller for GET request to '/eventlist' // Returns - diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 6b270bd10..68f4c4df6 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -3,10 +3,7 @@ import { startDb, startIntegrations, startOSCServer, startServer } from './app.j async function startOntime() { try { await startDb(); - - const loaded = await startServer(); - console.log(loaded); - + await startServer(); await startOSCServer(); await startIntegrations(); } catch (error) { diff --git a/apps/server/src/models/dataModel.ts b/apps/server/src/models/dataModel.ts index 014a7c954..573f896da 100644 --- a/apps/server/src/models/dataModel.ts +++ b/apps/server/src/models/dataModel.ts @@ -2,7 +2,7 @@ import { DatabaseModel } from 'ontime-types'; export const dbModel: DatabaseModel = { rundown: [], - event: { + eventData: { title: '', publicUrl: '', publicInfo: '', @@ -18,7 +18,7 @@ export const dbModel: DatabaseModel = { pinCode: null, timeFormat: '24', }, - views: { + viewSettings: { overrideStyles: false, }, aliases: [], diff --git a/apps/server/src/routes/eventRouter.js b/apps/server/src/routes/eventDataRouter.js similarity index 65% rename from apps/server/src/routes/eventRouter.js rename to apps/server/src/routes/eventDataRouter.js index 1f53016df..cffdb2f97 100644 --- a/apps/server/src/routes/eventRouter.js +++ b/apps/server/src/routes/eventDataRouter.js @@ -2,8 +2,8 @@ import express from 'express'; export const router = express.Router(); // import event controller -import { getEvent, postEvent } from '../controllers/eventController.js'; -import { eventSanitizer } from '../controllers/eventController.validate.js'; +import { getEvent, postEvent } from '../controllers/eventDataController.js'; +import { eventSanitizer } from '../controllers/eventDataController.validate.js'; // create route between controller and 'GET /event' endpoint router.get('/', getEvent); diff --git a/apps/server/src/services/PlaybackService.js b/apps/server/src/services/PlaybackService.js index 761aac230..a28eefa11 100644 --- a/apps/server/src/services/PlaybackService.js +++ b/apps/server/src/services/PlaybackService.js @@ -3,7 +3,8 @@ */ import { socketProvider } from '../classes/socket/SocketController.js'; import { eventLoader, EventLoader } from '../classes/event-loader/EventLoader.js'; -import { eventTimer, TimerService } from './TimerService.ts'; +import { eventTimer, TimerService } from './TimerService.js'; +import { eventStore } from '../stores/EventStore.js'; /** * Service manages playback status of app @@ -26,7 +27,7 @@ export class PlaybackService { eventTimer.load(event); success = true; } - socketProvider.broadcastState(); + eventStore.broadcast(); return success; } @@ -123,7 +124,6 @@ export class PlaybackService { const newState = eventTimer.playback; socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`); } - socketProvider.broadcastState(); } /** @@ -135,7 +135,6 @@ export class PlaybackService { const newState = eventTimer.playback; socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`); } - socketProvider.broadcastState(); } /** @@ -148,7 +147,6 @@ export class PlaybackService { const newState = eventTimer.playback; socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`); } - socketProvider.broadcastState(); } /** @@ -158,7 +156,6 @@ export class PlaybackService { if (eventLoader.selectedEventId) { this.loadById(eventLoader.selectedEventId); } - socketProvider.broadcastState(); } /** @@ -186,7 +183,6 @@ export class PlaybackService { const newState = eventTimer.playback; socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`); - socketProvider.broadcastState(); } } @@ -200,6 +196,5 @@ export class PlaybackService { eventTimer.delay(delayInMs); socketProvider.info('PLAYBACK', `Added ${delayTime} min delay`); } - socketProvider.broadcastState(); } } diff --git a/apps/server/src/services/RundownService.js b/apps/server/src/services/RundownService.ts similarity index 86% rename from apps/server/src/services/RundownService.js rename to apps/server/src/services/RundownService.ts index e9fbd7185..73fad810f 100644 --- a/apps/server/src/services/RundownService.js +++ b/apps/server/src/services/RundownService.ts @@ -1,21 +1,16 @@ +import { OntimeBaseEvent, OntimeBlock, OntimeDelay, OntimeEvent } from 'ontime-types'; import { generateId } from 'ontime-utils'; -import { DataProvider } from '../classes/data-provider/DataProvider.ts'; -import { - block as blockDef, - delay as delayDef, - event as eventDef, -} from '../models/eventsDefinition.js'; +import { DataProvider } from '../classes/data-provider/DataProvider.js'; +import { block as blockDef, delay as delayDef, event as eventDef } from '../models/eventsDefinition.js'; import { MAX_EVENTS } from '../settings.js'; import { EventLoader, eventLoader } from '../classes/event-loader/EventLoader.js'; -import { eventTimer } from './TimerService.ts'; -import { socketProvider } from '../classes/socket/SocketController.js'; +import { eventTimer } from './TimerService.js'; +import { eventStore } from '../stores/EventStore.js'; /** - * - * @param affectedIds - * @returns boolean + * Checks if a list of IDs is in the current selection */ -const affectedLoaded = (affectedIds) => { +const affectedLoaded = (affectedIds: string[]) => { const now = eventLoader.selectedEventId; const nowPublic = eventLoader.selectedPublicEventId; const next = eventLoader.nextEventId; @@ -28,6 +23,9 @@ const affectedLoaded = (affectedIds) => { ); }; +/** + * Checks if timer replaces the loaded next + */ const isNewNext = () => { const timedEvents = EventLoader.getTimedEvents(); const now = eventLoader.selectedEventId; @@ -66,10 +64,9 @@ const isNewNext = () => { }; /** - * updates timer object - * @param {array} [affectedIds] + * Updates timer object */ -export function updateTimer(affectedIds) { +export function updateTimer(affectedIds?: string[]) { const runningEventId = eventLoader.selectedEventId; if (runningEventId === null) { @@ -121,18 +118,18 @@ export async function addEvent(eventData) { throw new Error(`ERROR: Reached limit number of ${MAX_EVENTS} events`); } - let newEvent = {}; + let newEvent: Partial = {}; const id = generateId(); switch (eventData.type) { case 'event': - newEvent = { ...eventDef, ...eventData, id }; + newEvent = { ...eventDef, ...eventData, id } as Partial; break; case 'delay': - newEvent = { ...delayDef, ...eventData, id }; + newEvent = { ...delayDef, ...eventData, id } as Partial; break; case 'block': - newEvent = { ...blockDef, ...eventData, id }; + newEvent = { ...blockDef, ...eventData, id } as Partial; break; } @@ -148,7 +145,7 @@ export async function addEvent(eventData) { throw new Error(error); } updateTimer([id]); - socketProvider.broadcastState(); + eventStore.broadcast(); return newEvent; } @@ -160,7 +157,7 @@ export async function editEvent(eventData) { } const newEvent = await DataProvider.updateEventById(eventId, eventData); updateTimer([eventId]); - socketProvider.broadcastState(); + eventStore.broadcast(); return newEvent; } @@ -172,7 +169,7 @@ export async function editEvent(eventData) { export async function deleteEvent(eventId) { await DataProvider.deleteEvent(eventId); updateTimer([eventId]); - socketProvider.broadcastState(); + eventStore.broadcast(); } /** @@ -182,7 +179,7 @@ export async function deleteEvent(eventId) { export async function deleteAllEvents() { await DataProvider.clearRundown(); updateTimer(); - socketProvider.broadcastState(); + eventStore.broadcast(); } /** @@ -263,5 +260,5 @@ export async function applyDelay(eventId) { // update rundown await DataProvider.setRundown(rundown); updateTimer(); - socketProvider.broadcastState(); + eventStore.broadcast(); } diff --git a/apps/server/src/services/TimerService.ts b/apps/server/src/services/TimerService.ts index 2c860d54a..96f1f4aff 100644 --- a/apps/server/src/services/TimerService.ts +++ b/apps/server/src/services/TimerService.ts @@ -1,6 +1,6 @@ import { TimerLifeCycle } from 'ontime-types'; -import { runtimeState } from '../stores/EventStore.js'; +import { eventStore } from '../stores/EventStore.js'; import { PlaybackService } from './PlaybackService.js'; import { updateRoll } from './rollUtils.js'; import { DAY_TO_MS } from '../utils/time.js'; @@ -9,9 +9,9 @@ import { integrationService } from './integration-service/IntegrationService.js' export class TimerService { private readonly _interval: NodeJS.Timer; - private playback: string; + playback: string; - private loadedTimerId: null; + loadedTimerId: null; private _pausedInterval: number; private _pausedAt: number | null; private _secondaryTarget: number | null; @@ -163,8 +163,8 @@ export class TimerService { * @private */ _onLoad() { - runtimeState.set('playback', this.playback); - runtimeState.set('ontime-timer', this.timer); + eventStore.set('playback', this.playback); + eventStore.set('timer', this.timer); integrationService.dispatch(TimerLifeCycle.onLoad); } @@ -198,8 +198,8 @@ export class TimerService { * @private */ _onStart() { - runtimeState.set('playback', this.playback); - runtimeState.set('ontime-timer', this.timer); + eventStore.set('playback', this.playback); + eventStore.set('timer', this.timer); integrationService.dispatch(TimerLifeCycle.onStart); } @@ -215,8 +215,8 @@ export class TimerService { } _onPause() { - runtimeState.set('playback', this.playback); - runtimeState.set('ontime-timer', this.timer); + eventStore.set('playback', this.playback); + eventStore.set('timer', this.timer); integrationService.dispatch(TimerLifeCycle.onPause); } @@ -230,8 +230,8 @@ export class TimerService { } _onStop() { - runtimeState.set('playback', this.playback); - runtimeState.set('ontime-timer', this.timer); + eventStore.set('playback', this.playback); + eventStore.set('timer', this.timer); integrationService.dispatch(TimerLifeCycle.onStop); } @@ -318,14 +318,14 @@ export class TimerService { } _onUpdate() { - runtimeState.set('playback', this.playback); - runtimeState.set('ontime-timer', this.timer); + eventStore.set('playback', this.playback); + eventStore.set('timer', this.timer); integrationService.dispatch(TimerLifeCycle.onUpdate); } _onFinish() { - runtimeState.set('playback', this.playback); - runtimeState.set('ontime-timer', this.timer); + eventStore.set('playback', this.playback); + eventStore.set('timer', this.timer); integrationService.dispatch(TimerLifeCycle.onFinish); } diff --git a/apps/server/src/services/integration-service/IntegrationService.ts b/apps/server/src/services/integration-service/IntegrationService.ts index 65c89ed9d..aad3296d8 100644 --- a/apps/server/src/services/integration-service/IntegrationService.ts +++ b/apps/server/src/services/integration-service/IntegrationService.ts @@ -1,5 +1,5 @@ import IIntegration, { TimerLifeCycleKey } from './IIntegration.js'; -import { runtimeState } from '../../stores/EventStore.js'; +import { eventStore } from '../../stores/EventStore.js'; class IntegrationService { private integrations: IIntegration[]; @@ -17,7 +17,7 @@ class IntegrationService { } dispatch(action: TimerLifeCycleKey) { - const state = runtimeState.poll(); + const state = eventStore.poll(); this.integrations.forEach((integration) => { integration.dispatch(action, state); }); diff --git a/apps/server/src/services/rollUtils.js b/apps/server/src/services/rollUtils.ts similarity index 88% rename from apps/server/src/services/rollUtils.js rename to apps/server/src/services/rollUtils.ts index b1f15816c..c3bf6ec12 100644 --- a/apps/server/src/services/rollUtils.js +++ b/apps/server/src/services/rollUtils.ts @@ -1,16 +1,12 @@ /** * Utility variable: 24 hour in milliseconds . - * @type {number} */ export const DAY_TO_MS = 86400000; /** - * @description handle events that span over midnight - * @param {number} start - When does the event start - * @param {number} end - When does the event end - * @returns {number} normalised time + * handle events that span over midnight */ -export const normaliseEndTime = (start, end) => (end < start ? end + DAY_TO_MS : end); +export const normaliseEndTime = (start: number, end: number) => (end < start ? end + DAY_TO_MS : end); /** * @description Sorts an array of objects by given property @@ -45,15 +41,15 @@ export const replacePlaceholder = (str, values) => { * @param timeNow * @returns {{}} */ -export const getRollTimers = (rundown, timeNow) => { - let nowIndex = null; // index of event now - let nowId = null; // id of event now - let publicIndex = null; // index of public event now +export const getRollTimers = (rundown, timeNow: number) => { + let nowIndex: number | null = null; // index of event now + let nowId: string | null = null; // id of event now + let publicIndex: string | null = null; // index of public event now let publicTime = -1; - let nextIndex = null; // index of next event - let publicNextIndex = null; // index of next public event - let timeToNext = null; // counter: time for next event - let publicTimeToNext = null; // counter: time for next public event + let nextIndex: number | null = null; // index of next event + let publicNextIndex: number | null = null; // index of next public event + let timeToNext: number | null = null; // counter: time for next event + let publicTimeToNext: number | null = null; // counter: time for next public event let timers = null; // Order events by startTime @@ -171,8 +167,7 @@ export const getRollTimers = (rundown, timeNow) => { * @returns {object} object with selection variables */ export const updateRoll = (currentTimers) => { - const { selectedEventId, current, _finishAt, clock, secondaryTimer, _secondaryTarget } = - currentTimers; + const { selectedEventId, current, _finishAt, clock, secondaryTimer, _secondaryTarget } = currentTimers; // timers let updatedTimer = current; diff --git a/apps/server/src/stores/EventStore.js b/apps/server/src/stores/EventStore.js index 09bee4c3f..b63be9a5c 100644 --- a/apps/server/src/stores/EventStore.js +++ b/apps/server/src/stores/EventStore.js @@ -5,7 +5,7 @@ const store = {}; /** * A runtime store that broadcasts its payload */ -export const runtimeState = { +export const eventStore = { get(key) { return store[key]; }, @@ -16,4 +16,8 @@ export const runtimeState = { poll() { return store; }, + broadcast() { + socketProvider.send(store); + socketProvider.broadcastState(); + }, }; diff --git a/apps/server/src/utils/__tests__/parser.tests.js b/apps/server/src/utils/__tests__/parser.tests.js index 4dc26943a..7d088c1e3 100644 --- a/apps/server/src/utils/__tests__/parser.tests.js +++ b/apps/server/src/utils/__tests__/parser.tests.js @@ -2,7 +2,7 @@ import { vi } from 'vitest'; import { dbModel } from '../../models/dataModel.js'; import { parseExcel, parseJson, validateEvent } from '../parser.js'; import { makeString, validateDuration } from '../parserUtils.js'; -import { parseAliases, parseUserFields, parseViews } from '../parserFunctions.js'; +import { parseAliases, parseUserFields, parseViewSettings } from '../parserFunctions.js'; describe('test json parser with valid def', () => { const testData = { @@ -829,7 +829,7 @@ describe('test views import', () => { overrideStyles: true, }, }; - const parsed = parseViews(testData); + const parsed = parseViewSettings(testData); expect(parsed).toStrictEqual(testData.views); }); @@ -841,7 +841,7 @@ describe('test views import', () => { version: 2, }, }; - const parsed = parseViews(testData, true); + const parsed = parseViewSettings(testData, true); expect(parsed).toStrictEqual(dbModel.views); }); }); diff --git a/apps/server/src/utils/parser.js b/apps/server/src/utils/parser.js index 4539e95c1..9e663c979 100644 --- a/apps/server/src/utils/parser.js +++ b/apps/server/src/utils/parser.js @@ -6,13 +6,13 @@ import { dbModel } from '../models/dataModel.js'; import { deleteFile, makeString, validateDuration } from './parserUtils.js'; import { parseAliases, - parseEvent, + parseEventData, parseHttp, parseOsc, parseRundown, parseSettings, parseUserFields, - parseViews, + parseViewSettings, } from './parserFunctions.js'; import { parseExcelDate } from './time.js'; @@ -238,7 +238,7 @@ export const parseExcel = async (excelData) => { }); return { rundown, - event: eventData, + eventData: eventData, settings: { app: 'ontime', version: 2, @@ -265,11 +265,11 @@ export const parseJson = async (jsonData, enforce = false) => { // parse Events returnData.rundown = parseRundown(jsonData); // parse Event - returnData.event = parseEvent(jsonData, enforce); + returnData.eventData = parseEventData(jsonData, enforce); // Settings handled partially returnData.settings = parseSettings(jsonData, enforce); // View settings handled partially - returnData.views = parseViews(jsonData, enforce); + returnData.viewSettings = parseViewSettings(jsonData, enforce); // Import OSC settings if any returnData.osc = parseOsc(jsonData, enforce); // Import HTTP settings if any @@ -358,7 +358,7 @@ export const fileHandler = async (file) => { const dataFromExcel = await parseExcel(excelData.data); res.data = {}; res.data.rundown = parseRundown(dataFromExcel); - res.data.event = parseEvent(dataFromExcel, true); + res.data.eventData = parseEventData(dataFromExcel, true); res.data.userFields = parseUserFields(dataFromExcel); res.message = 'success'; } else { diff --git a/apps/server/src/utils/parserFunctions.ts b/apps/server/src/utils/parserFunctions.ts index 330289788..7651d9981 100644 --- a/apps/server/src/utils/parserFunctions.ts +++ b/apps/server/src/utils/parserFunctions.ts @@ -64,26 +64,26 @@ export const parseRundown = (data) => { * @param {boolean} enforce - whether to create a definition if one is missing * @returns {object} - event object data */ -export const parseEvent = (data, enforce) => { - let newEvent = {}; - if ('event' in data) { +export const parseEventData = (data, enforce) => { + let newEventData = {}; + if ('eventData' in data) { console.log('Found event data, importing...'); - const e = data.event; + const e = data.eventData; // filter known properties and write to db - newEvent = { - ...dbModel.event, - title: e.title || dbModel.event.title, - publicUrl: e.publicUrl || dbModel.event.publicUrl, - publicInfo: e.publicInfo || dbModel.event.publicInfo, - backstageUrl: e.backstageUrl || dbModel.event.backstageUrl, - backstageInfo: e.backstageInfo || dbModel.event.backstageInfo, - endMessage: e.endMessage || dbModel.event.endMessage, + newEventData = { + ...dbModel.eventData, + title: e.title || dbModel.eventData.title, + publicUrl: e.publicUrl || dbModel.eventData.publicUrl, + publicInfo: e.publicInfo || dbModel.eventData.publicInfo, + backstageUrl: e.backstageUrl || dbModel.eventData.backstageUrl, + backstageInfo: e.backstageInfo || dbModel.eventData.backstageInfo, + endMessage: e.endMessage || dbModel.eventData.endMessage, }; } else if (enforce) { - newEvent = { ...dbModel.event }; + newEventData = { ...dbModel.eventData }; console.log(`Created event object in db`); } - return newEvent; + return newEventData; }; /** @@ -127,14 +127,14 @@ export const parseSettings = (data, enforce) => { * @param {boolean} enforce - whether to create a definition if one is missing * @returns {object} - event object data */ -export const parseViews = (data, enforce) => { +export const parseViewSettings = (data, enforce) => { let newViews = {}; - if ('views' in data) { + if ('viewSettings' in data) { console.log('Found view definition, importing...'); - const v = data.views; + const v = data.viewSettings; const viewSettings = { - overrideStyles: v.overrideStyles ?? dbModel.views.overrideStyles, + overrideStyles: v.overrideStyles ?? dbModel.viewSettings.overrideStyles, }; // write to db @@ -142,8 +142,8 @@ export const parseViews = (data, enforce) => { ...viewSettings, }; } else if (enforce) { - newViews = dbModel.views; - console.log(`Created view object in db`); + newViews = dbModel.viewSettings; + console.log(`Created viewSettings object in db`); } return newViews; }; diff --git a/apps/server/test-db/db.json b/apps/server/test-db/db.json index 30395bb73..3dad387cb 100644 --- a/apps/server/test-db/db.json +++ b/apps/server/test-db/db.json @@ -7,9 +7,23 @@ "note": "Maybe a running note for the operator?", "timeStart": 28800000, "timeEnd": 30600000, + "timeType": "start-end", + "duration": 1800000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 7, + "revision": 0, "id": "5946" }, { @@ -19,9 +33,23 @@ "note": "", "timeStart": 30600000, "timeEnd": 34200000, + "timeType": "start-end", + "duration": 3600000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 4, + "revision": 0, "id": "c2e7" }, { @@ -31,9 +59,23 @@ "note": "", "timeStart": 34200000, "timeEnd": 34800000, + "timeType": "start-end", + "duration": 600000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 4, + "revision": 0, "id": "cc0f" }, { @@ -43,9 +85,23 @@ "note": "In green, below", "timeStart": 34800000, "timeEnd": 35400000, + "timeType": "start-end", + "duration": 600000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 7, + "revision": 0, "id": "8ee5" }, { @@ -55,15 +111,29 @@ "note": "", "timeStart": 0, "timeEnd": 600000, + "timeType": "start-end", + "duration": 600000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 2, + "revision": 0, "id": "8222" }, { "duration": 900000, "type": "delay", - "revision": 1, + "revision": 0, "id": "a386" }, { @@ -73,9 +143,23 @@ "note": "* Until a block is found", "timeStart": 35400000, "timeEnd": 36600000, + "timeType": "start-end", + "duration": 1200000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 6, + "revision": 0, "id": "6dce" }, { @@ -85,9 +169,23 @@ "note": "Orange and red buttons on the right", "timeStart": 36600000, "timeEnd": 43200000, + "timeType": "start-end", + "duration": 6600000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 9, + "revision": 0, "id": "2651" }, { @@ -101,13 +199,27 @@ "note": "Blue button on the right", "timeStart": 46800000, "timeEnd": 57600000, + "timeType": "start-end", + "duration": 10800000, "isPublic": false, + "skip": false, + "colour": "", + "user0": "", + "user1": "", + "user2": "", + "user3": "", + "user4": "", + "user5": "", + "user6": "", + "user7": "", + "user8": "", + "user9": "", "type": "event", - "revision": 6, + "revision": 0, "id": "1358" } ], - "event": { + "eventData": { "title": "All about Carlos demo event", "publicUrl": "www.getontime.no", "publicInfo": "WiFi: demoproject \nPassword: ontimeproject", @@ -117,17 +229,53 @@ }, "settings": { "app": "ontime", - "version": 2, + "version": 1, "serverPort": 4001, "lock": null, "pinCode": "1234" }, + "viewSettings": { + "overrideStyles": false + }, "osc": { "port": 8888, "portOut": 9999, "targetIP": "127.0.0.1", "enabled": true }, + "http": { + "http": { + "user": null, + "pwd": null, + "messages": { + "onLoad": { + "url": "", + "enabled": false + }, + "onStart": { + "url": "", + "enabled": false + }, + "onUpdate": { + "url": "", + "enabled": false + }, + "onPause": { + "url": "", + "enabled": false + }, + "onStop": { + "url": "", + "enabled": false + }, + "onFinish": { + "url": "", + "enabled": false + } + }, + "enabled": true + } + }, "aliases": [ { "id": "0b0b3", @@ -148,4 +296,4 @@ "user8": "user8", "user9": "user9" } -} \ No newline at end of file +} diff --git a/demo-db/db.json b/demo-db/db.json index af9554cc4..52292f682 100644 --- a/demo-db/db.json +++ b/demo-db/db.json @@ -1,5 +1,5 @@ { - "events": [ + "rundown": [ { "title": "Welcome to Ontime", "subtitle": "Subtitles are useful", @@ -219,7 +219,7 @@ "id": "1358" } ], - "event": { + "eventData": { "title": "All about Carlos demo event", "publicUrl": "www.getontime.no", "publicInfo": "WiFi: demoproject \nPassword: ontimeproject", @@ -234,7 +234,7 @@ "lock": null, "pinCode": "1234" }, - "views": { + "viewSettings": { "overrideStyles": false }, "osc": { diff --git a/packages/types/src/definitions/DataModel.type.ts b/packages/types/src/definitions/DataModel.type.ts index 65360a284..c5a95f78b 100644 --- a/packages/types/src/definitions/DataModel.type.ts +++ b/packages/types/src/definitions/DataModel.type.ts @@ -1,12 +1,18 @@ +import { Alias } from './core/Alias.type.js'; +import { EventData } from './core/EventData.type.js'; +import { OntimeRundown } from './core/Rundown.type.js'; import { OSCSettings } from './core/OscSettings.type.js'; +import { Settings } from './core/Settings.type.js'; +import { UserFields } from './core/UserFields.type.js'; +import { ViewSettings } from './core/Views.type.js'; export type DatabaseModel = { - rundown: any; - event: any; - settings: any; - views: any; - aliases: any; - userFields: any; + rundown: OntimeRundown; + eventData: EventData; + settings: Settings; + viewSettings: ViewSettings; + aliases: Alias[]; + userFields: UserFields; osc: OSCSettings; http: any; }; diff --git a/packages/types/src/definitions/TimerType.type.ts b/packages/types/src/definitions/TimerType.type.ts index 3962446a8..69150eeae 100644 --- a/packages/types/src/definitions/TimerType.type.ts +++ b/packages/types/src/definitions/TimerType.type.ts @@ -1,7 +1,5 @@ -enum TimerTypeType { +export enum TimerTypeType { CountDown = 'count-down', CountUp = 'count-up', Clock = 'clock' } - -export default TimerTypeType diff --git a/packages/types/src/definitions/core/Alias.type.ts b/packages/types/src/definitions/core/Alias.type.ts new file mode 100644 index 000000000..c82d4e678 --- /dev/null +++ b/packages/types/src/definitions/core/Alias.type.ts @@ -0,0 +1,5 @@ +export type Alias = { + enabled: boolean; + alias: string; + pathAndParams: string; +} diff --git a/packages/types/src/definitions/core/EventData.type.ts b/packages/types/src/definitions/core/EventData.type.ts new file mode 100644 index 000000000..4954f7bd9 --- /dev/null +++ b/packages/types/src/definitions/core/EventData.type.ts @@ -0,0 +1,8 @@ +export type EventData = { + title: string; + publicUrl: string; + publicInfo: string; + backstageUrl: string; + backstageInfo: string; + endMessage: string; +}; diff --git a/packages/types/src/definitions/core/OntimeEvent.type.ts b/packages/types/src/definitions/core/OntimeEvent.type.ts new file mode 100644 index 000000000..ed73eb658 --- /dev/null +++ b/packages/types/src/definitions/core/OntimeEvent.type.ts @@ -0,0 +1,47 @@ +export enum SupportedEvent { + Event = 'event', + Delay = 'delay', + Block = 'block', +} + +export type OntimeBaseEvent = { + type: SupportedEvent; + id: string; + after?: string; // used when creating an event to indicate its position in rundown +}; + +export type OntimeDelay = OntimeBaseEvent & { + type: SupportedEvent.Delay; + duration: number; + revision: number; +}; + +export type OntimeBlock = OntimeBaseEvent & { + type: SupportedEvent.Block; +}; + +export type OntimeEvent = OntimeBaseEvent & { + type: SupportedEvent.Event; + title: string; + subtitle: string; + presenter: string; + note: string; + timeType?: string; + timeStart: number; + timeEnd: number; + duration: number; + isPublic: boolean; + skip: boolean; + colour: string; + user0: string; + user1: string; + user2: string; + user3: string; + user4: string; + user5: string; + user6: string; + user7: string; + user8: string; + user9: string; + revision: number; +}; diff --git a/packages/types/src/definitions/core/Rundown.type.ts b/packages/types/src/definitions/core/Rundown.type.ts new file mode 100644 index 000000000..8f018b2d2 --- /dev/null +++ b/packages/types/src/definitions/core/Rundown.type.ts @@ -0,0 +1,4 @@ +import { OntimeBlock, OntimeDelay, OntimeEvent } from './OntimeEvent.type'; + +export type OntimeRundownEntry = OntimeDelay | OntimeBlock | OntimeEvent; +export type OntimeRundown = OntimeRundownEntry[]; diff --git a/packages/types/src/definitions/core/Settings.type.ts b/packages/types/src/definitions/core/Settings.type.ts new file mode 100644 index 000000000..0986e88d9 --- /dev/null +++ b/packages/types/src/definitions/core/Settings.type.ts @@ -0,0 +1,10 @@ +import { TimeFormat } from './TimeFormat.type'; + +export type Settings = { + app: 'ontime'; + version: 2; + serverPort: 4001; + lock: null | boolean; + pinCode: null | number | string; + timeFormat: TimeFormat; +}; diff --git a/packages/types/src/definitions/core/TimeFormat.type.ts b/packages/types/src/definitions/core/TimeFormat.type.ts new file mode 100644 index 000000000..c8e0b9b17 --- /dev/null +++ b/packages/types/src/definitions/core/TimeFormat.type.ts @@ -0,0 +1 @@ +export type TimeFormat = '12' | '24'; diff --git a/packages/types/src/definitions/core/UserFields.type.ts b/packages/types/src/definitions/core/UserFields.type.ts new file mode 100644 index 000000000..02401571c --- /dev/null +++ b/packages/types/src/definitions/core/UserFields.type.ts @@ -0,0 +1,13 @@ +export type UserFields = { + user0: string; + user1: string; + user2: string; + user3: string; + user4: string; + user5: string; + user6: string; + user7: string; + user8: string; + user9: string; +} + diff --git a/packages/types/src/definitions/core/Views.type.ts b/packages/types/src/definitions/core/Views.type.ts new file mode 100644 index 000000000..2a29f41ff --- /dev/null +++ b/packages/types/src/definitions/core/Views.type.ts @@ -0,0 +1,3 @@ +export type ViewSettings = { + overrideStyles: boolean; +} diff --git a/packages/types/src/definitions/runtime/MessageControl.type.ts b/packages/types/src/definitions/runtime/MessageControl.type.ts new file mode 100644 index 000000000..0b2d6bf2c --- /dev/null +++ b/packages/types/src/definitions/runtime/MessageControl.type.ts @@ -0,0 +1,10 @@ +export type Message = { + text: string; + visible: boolean; +}; + +export type MessageControl = { + presenter: Message; + public: Message; + lower: Message; +}; diff --git a/apps/client/src/common/models/OntimeTypes.ts b/packages/types/src/definitions/runtime/Playback.type.ts similarity index 64% rename from apps/client/src/common/models/OntimeTypes.ts rename to packages/types/src/definitions/runtime/Playback.type.ts index a2607c3ae..ab86abefb 100644 --- a/apps/client/src/common/models/OntimeTypes.ts +++ b/packages/types/src/definitions/runtime/Playback.type.ts @@ -1,2 +1 @@ export type Playback = 'roll' | 'play' | 'pause' | 'stop' | 'armed'; -export type TimeFormat = '12' | '24'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 6a5ae3513..68ee07488 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,24 +1,56 @@ -import TimerTypeType from './definitions/TimerType.type.js'; +import { Alias } from './definitions/core/Alias.type.js'; import { DatabaseModel } from './definitions/DataModel.type.js'; -import { TimerLifeCycle } from './definitions/core/TimerLifecycle.type.js'; +import { EventData } from './definitions/core/EventData.type.js'; +import { Message, MessageControl } from './definitions/runtime/MessageControl.type.js'; +import { + OntimeBaseEvent, + OntimeBlock, + OntimeDelay, + OntimeEvent, + SupportedEvent, +} from './definitions/core/OntimeEvent.type.js'; +import { OntimeRundown, OntimeRundownEntry } from './definitions/core/Rundown.type.js'; import { OSCSettings, OscSubscription } from './definitions/core/OscSettings.type.js'; +import { Playback } from './definitions/runtime/Playback.type.js'; +import { Settings } from './definitions/core/Settings.type.js'; +import { TimerLifeCycle } from './definitions/core/TimerLifecycle.type.js'; +import { TimerTypeType } from './definitions/TimerType.type.js'; +import { UserFields } from './definitions/core/UserFields.type.js'; +import { ViewSettings } from './definitions/core/Views.type.js'; // DATA MODEL export type { DatabaseModel }; // ---> Rundown export type { TimerTypeType }; +export type { OntimeBaseEvent, OntimeBlock, OntimeDelay, OntimeEvent }; +export type { OntimeRundown, OntimeRundownEntry }; +export { SupportedEvent }; // ---> Event +export type { EventData }; + // ---> Settings +export type { Settings }; + // ---> Views +export type { ViewSettings }; + // ---> Aliases +export type { Alias }; + // ---> User Fields +export type { UserFields }; + // ---> OSC export type { OscSubscription, OSCSettings }; + // ---> HTTP // SERVER export { TimerLifeCycle }; +export type { Playback }; +export type { Message }; +export type { MessageControl }; // CLIENT