mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 15:09:10 +00:00
V2 fix socket (#296)
* refactor: rename timer endpoint * refactor: typescript * refactor: rename eventData and viewSettings * refactor: message manager uses event store
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
export const STATIC_PORT = 4001;
|
export const STATIC_PORT = 4001;
|
||||||
|
|
||||||
// REST stuff
|
// REST stuff
|
||||||
export const EVENT_TABLE = ['event'];
|
export const EVENTDATA_TABLE = ['eventdata'];
|
||||||
export const ALIASES = ['aliases'];
|
export const ALIASES = ['aliases'];
|
||||||
export const USERFIELDS = ['userFields'];
|
export const USERFIELDS = ['userFields'];
|
||||||
export const RUNDOWN_TABLE_KEY = 'rundown';
|
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_MESSAGECONTROL = 'feat-messagecontrol';
|
||||||
export const FEAT_PLAYBACKCONTROL = 'feat-playbackcontrol';
|
export const FEAT_PLAYBACKCONTROL = 'feat-playbackcontrol';
|
||||||
export const FEAT_RUNDOWN = 'feat-rundown';
|
export const FEAT_RUNDOWN = 'feat-rundown';
|
||||||
export const TIMER = 'ontime-timer';
|
export const TIMER = 'timer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description finds server path given the current location, it
|
* @description finds server path given the current location, it
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
export const calculateServer = () =>
|
export const calculateServer = () => (import.meta.env.DEV ? `http://localhost:${STATIC_PORT}` : window.location.origin);
|
||||||
import.meta.env.DEV ? `http://localhost:${STATIC_PORT}` : window.location.origin;
|
|
||||||
|
|
||||||
export const serverURL = calculateServer();
|
export const serverURL = calculateServer();
|
||||||
export const eventURL = `${serverURL}/event`;
|
export const eventURL = `${serverURL}/eventdata`;
|
||||||
export const rundownURL = `${serverURL}/eventlist`;
|
export const rundownURL = `${serverURL}/eventlist`;
|
||||||
export const ontimeURL = `${serverURL}/ontime`;
|
export const ontimeURL = `${serverURL}/ontime`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { EventData } from 'ontime-types';
|
||||||
import { EventDataType } from '../models/EventData.type';
|
|
||||||
|
|
||||||
import { eventURL } from './apiConstants';
|
import { eventURL } from './apiConstants';
|
||||||
|
|
||||||
@@ -8,7 +7,7 @@ import { eventURL } from './apiConstants';
|
|||||||
* @description HTTP request to fetch event data
|
* @description HTTP request to fetch event data
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function fetchEvent(): Promise<EventDataType> {
|
export async function fetchEventData(): Promise<EventData> {
|
||||||
const res = await axios.get(eventURL);
|
const res = await axios.get(eventURL);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -17,6 +16,6 @@ export async function fetchEvent(): Promise<EventDataType> {
|
|||||||
* @description HTTP request to mutate event data
|
* @description HTTP request to mutate event data
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function postEvent(data: EventDataType) {
|
export async function postEventData(data: EventData) {
|
||||||
return axios.post(eventURL, data);
|
return axios.post(eventURL, data);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
||||||
import { OntimeRundown, OntimeRundownEntry } from '../models/EventTypes';
|
|
||||||
|
|
||||||
import { rundownURL } from './apiConstants';
|
import { rundownURL } from './apiConstants';
|
||||||
|
|
||||||
@@ -37,12 +36,12 @@ export async function requestPatchEvent(data: OntimeRundownEntry) {
|
|||||||
return axios.patch(rundownURL, data);
|
return axios.patch(rundownURL, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type ReorderEntry = {
|
export type ReorderEntry = {
|
||||||
eventId: string,
|
eventId: string;
|
||||||
from: number,
|
from: number;
|
||||||
to: number,
|
to: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description HTTP request to reorder events
|
* @description HTTP request to reorder events
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { Alias, OSCSettings, Settings, UserFields, ViewSettings } from 'ontime-types';
|
||||||
|
|
||||||
import { URLAliasType } from '../models/Alias.type';
|
import { InfoType } from '../models/Info';
|
||||||
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 { ontimeURL } from './apiConstants';
|
import { ontimeURL } from './apiConstants';
|
||||||
|
|
||||||
@@ -13,7 +9,7 @@ import { ontimeURL } from './apiConstants';
|
|||||||
* @description HTTP request to retrieve application settings
|
* @description HTTP request to retrieve application settings
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function getSettings(): Promise<OntimeSettingsType> {
|
export async function getSettings(): Promise<Settings> {
|
||||||
const res = await axios.get(`${ontimeURL}/settings`);
|
const res = await axios.get(`${ontimeURL}/settings`);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -22,7 +18,7 @@ export async function getSettings(): Promise<OntimeSettingsType> {
|
|||||||
* @description HTTP request to mutate application settings
|
* @description HTTP request to mutate application settings
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function postSettings(data: OntimeSettingsType) {
|
export async function postSettings(data: Settings) {
|
||||||
return axios.post(`${ontimeURL}/settings`, data);
|
return axios.post(`${ontimeURL}/settings`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +35,7 @@ export async function getInfo(): Promise<InfoType> {
|
|||||||
* @description HTTP request to retrieve view settings
|
* @description HTTP request to retrieve view settings
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function getView(): Promise<ViewSettingsType> {
|
export async function getView(): Promise<ViewSettings> {
|
||||||
const res = await axios.get(`${ontimeURL}/views`);
|
const res = await axios.get(`${ontimeURL}/views`);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -48,7 +44,7 @@ export async function getView(): Promise<ViewSettingsType> {
|
|||||||
* @description HTTP request to mutate view settings
|
* @description HTTP request to mutate view settings
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function postView(data: ViewSettingsType) {
|
export async function postView(data: ViewSettings) {
|
||||||
return axios.post(`${ontimeURL}/views`, data);
|
return axios.post(`${ontimeURL}/views`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +52,7 @@ export async function postView(data: ViewSettingsType) {
|
|||||||
* @description HTTP request to retrieve aliases
|
* @description HTTP request to retrieve aliases
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function getAliases(): Promise<URLAliasType[]> {
|
export async function getAliases(): Promise<Alias[]> {
|
||||||
const res = await axios.get(`${ontimeURL}/aliases`);
|
const res = await axios.get(`${ontimeURL}/aliases`);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -65,7 +61,7 @@ export async function getAliases(): Promise<URLAliasType[]> {
|
|||||||
* @description HTTP request to mutate aliases
|
* @description HTTP request to mutate aliases
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function postAliases(data: URLAliasType[]) {
|
export async function postAliases(data: Alias[]) {
|
||||||
return axios.post(`${ontimeURL}/aliases`, data);
|
return axios.post(`${ontimeURL}/aliases`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +69,7 @@ export async function postAliases(data: URLAliasType[]) {
|
|||||||
* @description HTTP request to retrieve user fields
|
* @description HTTP request to retrieve user fields
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function getUserFields(): Promise<UserFieldsType> {
|
export async function getUserFields(): Promise<UserFields> {
|
||||||
const res = await axios.get(`${ontimeURL}/userfields`);
|
const res = await axios.get(`${ontimeURL}/userfields`);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -82,7 +78,7 @@ export async function getUserFields(): Promise<UserFieldsType> {
|
|||||||
* @description HTTP request to mutate user fields
|
* @description HTTP request to mutate user fields
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export async function postUserFields(data: UserFieldsType) {
|
export async function postUserFields(data: UserFields) {
|
||||||
return axios.post(`${ontimeURL}/userfields`, data);
|
return axios.post(`${ontimeURL}/userfields`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
import { FiPower } from '@react-icons/all-files/fi/FiPower';
|
import { FiPower } from '@react-icons/all-files/fi/FiPower';
|
||||||
|
|
||||||
import { LoggingContext } from '../../context/LoggingContext';
|
import { LoggingContext } from '../../context/LoggingContext';
|
||||||
import { Size } from '../../models/UtilTypes';
|
import { Size } from '../../models/Util.type';
|
||||||
|
|
||||||
interface QuitIconBtnProps {
|
interface QuitIconBtnProps {
|
||||||
clickHandler: () => void;
|
clickHandler: () => void;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Button, ButtonGroup, IconButton, Tooltip } from '@chakra-ui/react';
|
|||||||
import { IoCopy } from '@react-icons/all-files/io5/IoCopy';
|
import { IoCopy } from '@react-icons/all-files/io5/IoCopy';
|
||||||
|
|
||||||
import { tooltipDelayFast } from '../../../ontimeConfig';
|
import { tooltipDelayFast } from '../../../ontimeConfig';
|
||||||
import { Size } from '../../models/UtilTypes';
|
import { Size } from '../../models/Util.type';
|
||||||
|
|
||||||
interface CopyTagProps {
|
interface CopyTagProps {
|
||||||
label: string;
|
label: string;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useRef } from 'react';
|
|||||||
import { Input, Textarea } from '@chakra-ui/react';
|
import { Input, Textarea } from '@chakra-ui/react';
|
||||||
|
|
||||||
import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor';
|
import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor';
|
||||||
import { Size } from '../../../models/UtilTypes';
|
import { Size } from '../../../models/Util.type';
|
||||||
|
|
||||||
import useReactiveTextInput from './useReactiveTextInput';
|
import useReactiveTextInput from './useReactiveTextInput';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createContext, PropsWithChildren, useContext, useState } from 'react';
|
import { createContext, PropsWithChildren, useContext, useState } from 'react';
|
||||||
|
import { OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { useInterval } from '../../hooks/useInterval';
|
import { useInterval } from '../../hooks/useInterval';
|
||||||
import { OntimeEvent } from '../../models/EventTypes';
|
|
||||||
|
|
||||||
interface ScheduleContextState {
|
interface ScheduleContextState {
|
||||||
events: OntimeEvent[];
|
events: OntimeEvent[];
|
||||||
|
|||||||
+6
-6
@@ -1,14 +1,14 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||||
import { EVENT_TABLE } from '../api/apiConstants';
|
import { EVENTDATA_TABLE } from '../api/apiConstants';
|
||||||
import { fetchEvent } from '../api/eventApi';
|
import { fetchEventData } from '../api/eventDataApi';
|
||||||
import { eventDataPlaceholder } from '../models/EventData.type';
|
import { eventDataPlaceholder } from '../models/EventData';
|
||||||
|
|
||||||
export default function useEvent() {
|
export default function useEventData() {
|
||||||
const { data, status, isError, refetch } = useQuery({
|
const { data, status, isError, refetch } = useQuery({
|
||||||
queryKey: EVENT_TABLE,
|
queryKey: EVENTDATA_TABLE,
|
||||||
queryFn: fetchEvent,
|
queryFn: fetchEventData,
|
||||||
placeholderData: eventDataPlaceholder,
|
placeholderData: eventDataPlaceholder,
|
||||||
retry: 5,
|
retry: 5,
|
||||||
retryDelay: (attempt) => attempt * 2500,
|
retryDelay: (attempt) => attempt * 2500,
|
||||||
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||||
import { APP_INFO } from '../api/apiConstants';
|
import { APP_INFO } from '../api/apiConstants';
|
||||||
import { getInfo } from '../api/ontimeApi';
|
import { getInfo } from '../api/ontimeApi';
|
||||||
import { ontimePlaceholderInfo } from '../models/Info.types';
|
import { ontimePlaceholderInfo } from '../models/Info';
|
||||||
|
|
||||||
export default function useInfo() {
|
export default function useInfo() {
|
||||||
const { data, status, isError, refetch } = useQuery({
|
const { data, status, isError, refetch } = useQuery({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||||
import { OSC_SETTINGS } from '../api/apiConstants';
|
import { OSC_SETTINGS } from '../api/apiConstants';
|
||||||
import { getOSC } from '../api/ontimeApi';
|
import { getOSC } from '../api/ontimeApi';
|
||||||
import { oscPlaceholderSettings } from '../models/OscSettings.type';
|
import { oscPlaceholderSettings } from '../models/OscSettings';
|
||||||
|
|
||||||
export default function useOscSettings() {
|
export default function useOscSettings() {
|
||||||
const { data, status, isError, refetch } = useQuery({
|
const { data, status, isError, refetch } = useQuery({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||||
import { APP_SETTINGS } from '../api/apiConstants';
|
import { APP_SETTINGS } from '../api/apiConstants';
|
||||||
import { getSettings } from '../api/ontimeApi';
|
import { getSettings } from '../api/ontimeApi';
|
||||||
import { ontimePlaceholderSettings } from '../models/OntimeSettings.type';
|
import { ontimePlaceholderSettings } from '../models/OntimeSettings';
|
||||||
|
|
||||||
export default function useSettings() {
|
export default function useSettings() {
|
||||||
const { data, status, isError, refetch } = useQuery({
|
const { data, status, isError, refetch } = useQuery({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { queryRefetchInterval } from '../../ontimeConfig';
|
import { queryRefetchInterval } from '../../ontimeConfig';
|
||||||
import { USERFIELDS } from '../api/apiConstants';
|
import { USERFIELDS } from '../api/apiConstants';
|
||||||
import { getUserFields } from '../api/ontimeApi';
|
import { getUserFields } from '../api/ontimeApi';
|
||||||
import { userFieldsPlaceholder } from '../models/UserFields.type';
|
import { userFieldsPlaceholder } from '../models/UserFields';
|
||||||
|
|
||||||
export default function useUserFields() {
|
export default function useUserFields() {
|
||||||
const { data, status, isError, refetch } = useQuery({
|
const { data, status, isError, refetch } = useQuery({
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useCallback, useContext } from 'react';
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import axios, { AxiosError } from 'axios';
|
import axios, { AxiosError } from 'axios';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
|
import { OntimeRundown, OntimeRundownEntry, SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { RUNDOWN_TABLE, RUNDOWN_TABLE_KEY } from '../api/apiConstants';
|
import { RUNDOWN_TABLE, RUNDOWN_TABLE_KEY } from '../api/apiConstants';
|
||||||
import {
|
import {
|
||||||
@@ -15,7 +16,6 @@ import {
|
|||||||
} from '../api/eventsApi';
|
} from '../api/eventsApi';
|
||||||
import { defaultPublicAtom, startTimeIsLastEndAtom } from '../atoms/LocalEventSettings';
|
import { defaultPublicAtom, startTimeIsLastEndAtom } from '../atoms/LocalEventSettings';
|
||||||
import { LoggingContext } from '../context/LoggingContext';
|
import { LoggingContext } from '../context/LoggingContext';
|
||||||
import { OntimeRundown, OntimeRundownEntry, SupportedEvent } from '../models/EventTypes';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Set of utilities for events
|
* @description Set of utilities for events
|
||||||
@@ -88,7 +88,6 @@ export const useEventAction = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// @ts-expect-error we know that the event here is one of the defined types
|
|
||||||
await _addEventMutation.mutateAsync(newEvent);
|
await _addEventMutation.mutateAsync(newEvent);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!axios.isAxiosError(error)) {
|
if (!axios.isAxiosError(error)) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { ontimeQueryClient as queryClient } from '../queryClient';
|
import { Playback } from 'ontime-types';
|
||||||
import socket, { subscribeOnce } from '../utils/socket';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FEAT_CUESHEET,
|
FEAT_CUESHEET,
|
||||||
@@ -10,7 +9,8 @@ import {
|
|||||||
FEAT_RUNDOWN,
|
FEAT_RUNDOWN,
|
||||||
TIMER,
|
TIMER,
|
||||||
} from '../api/apiConstants';
|
} from '../api/apiConstants';
|
||||||
import { Playback } from '../models/OntimeTypes';
|
import { ontimeQueryClient as queryClient } from '../queryClient';
|
||||||
|
import socket, { subscribeOnce } from '../utils/socket';
|
||||||
|
|
||||||
function createSocketHook<T>(key: string, defaultValue: T | null = null) {
|
function createSocketHook<T>(key: string, defaultValue: T | null = null) {
|
||||||
subscribeOnce<T>(key, (data) => queryClient.setQueryData([key], data));
|
subscribeOnce<T>(key, (data) => queryClient.setQueryData([key], data));
|
||||||
@@ -37,17 +37,19 @@ const emptyRundown: IRundown = {
|
|||||||
export const useRundownEditor = createSocketHook(FEAT_RUNDOWN, emptyRundown);
|
export const useRundownEditor = createSocketHook(FEAT_RUNDOWN, emptyRundown);
|
||||||
|
|
||||||
const emptyMessageControl = {
|
const emptyMessageControl = {
|
||||||
presenter: {
|
messages: {
|
||||||
text: '',
|
presenter: {
|
||||||
visible: false,
|
text: '',
|
||||||
},
|
visible: false,
|
||||||
public: {
|
},
|
||||||
text: '',
|
public: {
|
||||||
visible: false,
|
text: '',
|
||||||
},
|
visible: false,
|
||||||
lower: {
|
},
|
||||||
text: '',
|
lower: {
|
||||||
visible: false,
|
text: '',
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onAir: false,
|
onAir: false,
|
||||||
};
|
};
|
||||||
@@ -124,7 +126,6 @@ export const emptyCuesheet = {
|
|||||||
|
|
||||||
export const useCuesheet = createSocketHook(FEAT_CUESHEET, emptyCuesheet);
|
export const useCuesheet = createSocketHook(FEAT_CUESHEET, emptyCuesheet);
|
||||||
|
|
||||||
|
|
||||||
export const setEventPlayback = {
|
export const setEventPlayback = {
|
||||||
loadEvent: (eventId: string) => socket.emit('set-loadid', eventId),
|
loadEvent: (eventId: string) => socket.emit('set-loadid', eventId),
|
||||||
startEvent: (eventId: string) => socket.emit('set-startid', eventId),
|
startEvent: (eventId: string) => socket.emit('set-startid', eventId),
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Alias } from 'ontime-types';
|
||||||
|
|
||||||
|
export const aliasPlaceholder: Alias = {
|
||||||
|
enabled: false,
|
||||||
|
alias: '',
|
||||||
|
pathAndParams: '',
|
||||||
|
};
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export type URLAliasType = {
|
|
||||||
enabled: boolean;
|
|
||||||
alias: string;
|
|
||||||
pathAndParams: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const aliasPlaceholder: URLAliasType = {
|
|
||||||
enabled: false,
|
|
||||||
alias: '',
|
|
||||||
pathAndParams: '',
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { EventData } from 'ontime-types';
|
||||||
|
|
||||||
|
export const eventDataPlaceholder: EventData = {
|
||||||
|
title: '',
|
||||||
|
publicUrl: '',
|
||||||
|
publicInfo: '',
|
||||||
|
backstageUrl: '',
|
||||||
|
backstageInfo: '',
|
||||||
|
endMessage: '',
|
||||||
|
};
|
||||||
@@ -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: '',
|
|
||||||
};
|
|
||||||
@@ -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[]
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
import { OntimeSettingsType } from './OntimeSettings.type';
|
import { Settings } from 'ontime-types';
|
||||||
|
|
||||||
type NetworkInterfaceType = {
|
type NetworkInterfaceType = {
|
||||||
name: string;
|
name: string;
|
||||||
address: string;
|
address: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type InfoType = {
|
export type InfoType = {
|
||||||
networkInterfaces: NetworkInterfaceType[];
|
networkInterfaces: NetworkInterfaceType[];
|
||||||
settings: Pick<OntimeSettingsType, 'version' | 'serverPort'>
|
settings: Pick<Settings, 'version' | 'serverPort'>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const ontimePlaceholderInfo: InfoType = {
|
export const ontimePlaceholderInfo: InfoType = {
|
||||||
networkInterfaces: [],
|
networkInterfaces: [],
|
||||||
settings: {
|
settings: {
|
||||||
version: 0,
|
version: 2,
|
||||||
serverPort: 4001,
|
serverPort: 4001,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -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',
|
||||||
|
};
|
||||||
@@ -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',
|
|
||||||
};
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export type PresenterMessageType = {
|
|
||||||
text: string;
|
|
||||||
visible: boolean;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Playback } from './OntimeTypes';
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
export type TimeManagerType = {
|
export type TimeManagerType = {
|
||||||
clock: number;
|
clock: number;
|
||||||
@@ -12,4 +12,4 @@ export type TimeManagerType = {
|
|||||||
|
|
||||||
finished: boolean;
|
finished: boolean;
|
||||||
playback: Playback;
|
playback: Playback;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { UserFields } from 'ontime-types';
|
||||||
|
|
||||||
|
export const userFieldsPlaceholder: UserFields = {
|
||||||
|
user0: '',
|
||||||
|
user1: '',
|
||||||
|
user2: '',
|
||||||
|
user3: '',
|
||||||
|
user4: '',
|
||||||
|
user5: '',
|
||||||
|
user6: '',
|
||||||
|
user7: '',
|
||||||
|
user8: '',
|
||||||
|
user9: '',
|
||||||
|
};
|
||||||
@@ -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: '',
|
|
||||||
};
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
export type ViewSettingsType = {
|
import { ViewSettings } from 'ontime-types';
|
||||||
overrideStyles: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const viewsSettingsPlaceholder: ViewSettingsType = {
|
export const viewsSettingsPlaceholder: ViewSettings = {
|
||||||
overrideStyles: false,
|
overrideStyles: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../models/EventTypes';
|
import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { formatTime } from './time';
|
import { formatTime } from './time';
|
||||||
|
|
||||||
|
|||||||
@@ -16,26 +16,26 @@ export default function MessageControl() {
|
|||||||
<InputRow
|
<InputRow
|
||||||
label='Timer screen message'
|
label='Timer screen message'
|
||||||
placeholder='Shown in stage timer'
|
placeholder='Shown in stage timer'
|
||||||
text={data?.presenter.text || ''}
|
text={data?.messages.presenter.text || ''}
|
||||||
visible={data?.presenter.visible || false}
|
visible={data?.messages.presenter.visible || false}
|
||||||
changeHandler={(newValue) => setMessage.presenterText(newValue)}
|
changeHandler={(newValue) => setMessage.presenterText(newValue)}
|
||||||
actionHandler={() => setMessage.presenterVisible(!data?.presenter.visible)}
|
actionHandler={() => setMessage.presenterVisible(!data?.messages.presenter.visible)}
|
||||||
/>
|
/>
|
||||||
<InputRow
|
<InputRow
|
||||||
label='Public / Backstage screen message'
|
label='Public / Backstage screen message'
|
||||||
placeholder='Shown in public and backstage screens'
|
placeholder='Shown in public and backstage screens'
|
||||||
text={data?.public.text || ''}
|
text={data?.messages.public.text || ''}
|
||||||
visible={data?.public.visible || false}
|
visible={data?.messages.public.visible || false}
|
||||||
changeHandler={(newValue) => setMessage.publicText(newValue)}
|
changeHandler={(newValue) => setMessage.publicText(newValue)}
|
||||||
actionHandler={() => setMessage.publicVisible(!data?.public.visible)}
|
actionHandler={() => setMessage.publicVisible(!data?.messages.public.visible)}
|
||||||
/>
|
/>
|
||||||
<InputRow
|
<InputRow
|
||||||
label='Lower third message'
|
label='Lower third message'
|
||||||
placeholder='Shown in lower third'
|
placeholder='Shown in lower third'
|
||||||
text={data?.lower.text || ''}
|
text={data?.messages.lower.text || ''}
|
||||||
visible={data?.lower.visible || false}
|
visible={data?.messages.lower.visible || false}
|
||||||
changeHandler={(newValue) => setMessage.lowerText(newValue)}
|
changeHandler={(newValue) => setMessage.lowerText(newValue)}
|
||||||
actionHandler={() => setMessage.lowerVisible(!data?.lower.visible)}
|
actionHandler={() => setMessage.lowerVisible(!data?.messages.lower.visible)}
|
||||||
/>
|
/>
|
||||||
<div className={style.onAirSection}>
|
<div className={style.onAirSection}>
|
||||||
<label className={style.label}>Toggle On Air state</label>
|
<label className={style.label}>Toggle On Air state</label>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
import PlaybackDisplay from './PlaybackDisplay';
|
import PlaybackDisplay from './PlaybackDisplay';
|
||||||
import Transport from './Transport';
|
import Transport from './Transport';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
import { usePlaybackControl } from '../../../common/hooks/useSocket';
|
import { usePlaybackControl } from '../../../common/hooks/useSocket';
|
||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
|
||||||
|
|
||||||
import PlaybackButtons from './PlaybackButtons';
|
import PlaybackButtons from './PlaybackButtons';
|
||||||
import PlaybackTimer from './PlaybackTimer';
|
import PlaybackTimer from './PlaybackTimer';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { IoPause } from '@react-icons/all-files/io5/IoPause';
|
import { IoPause } from '@react-icons/all-files/io5/IoPause';
|
||||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||||
import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
|
import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
|
||||||
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
import { setPlayback } from '../../../common/hooks/useSocket';
|
import { setPlayback } from '../../../common/hooks/useSocket';
|
||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
|
||||||
|
|
||||||
import TapButton from './TapButton';
|
import TapButton from './TapButton';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Tooltip } from '@chakra-ui/react';
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
import TimerDisplay from '../../../common/components/timer-display/TimerDisplay';
|
import TimerDisplay from '../../../common/components/timer-display/TimerDisplay';
|
||||||
import { setPlayback, useTimer } from '../../../common/hooks/useSocket';
|
import { setPlayback, useTimer } from '../../../common/hooks/useSocket';
|
||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
|
||||||
import { stringFromMillis } from '../../../common/utils/time';
|
import { stringFromMillis } from '../../../common/utils/time';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ForwardedRef, forwardRef, PropsWithChildren } from 'react';
|
import { ForwardedRef, forwardRef, PropsWithChildren } from 'react';
|
||||||
|
import { Playback } from 'ontime-types';
|
||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
|
||||||
|
|
||||||
import style from './TapButton.module.scss';
|
import style from './TapButton.module.scss';
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { IoPlaySkipBack } from '@react-icons/all-files/io5/IoPlaySkipBack';
|
|||||||
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
|
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
|
||||||
import { IoReload } from '@react-icons/all-files/io5/IoReload';
|
import { IoReload } from '@react-icons/all-files/io5/IoReload';
|
||||||
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
||||||
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
import { setPlayback } from '../../../common/hooks/useSocket';
|
import { setPlayback } from '../../../common/hooks/useSocket';
|
||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import TapButton from './TapButton';
|
import TapButton from './TapButton';
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useCallback, useContext, useEffect, useState } from 'react';
|
|||||||
import { Button, Select, Switch } from '@chakra-ui/react';
|
import { Button, Select, Switch } from '@chakra-ui/react';
|
||||||
import { IoBan } from '@react-icons/all-files/io5/IoBan';
|
import { IoBan } from '@react-icons/all-files/io5/IoBan';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { editorEventId } from '../../common/atoms/LocalEventSettings';
|
import { editorEventId } from '../../common/atoms/LocalEventSettings';
|
||||||
import CopyTag from '../../common/components/copy-tag/CopyTag';
|
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 { LoggingContext } from '../../common/context/LoggingContext';
|
||||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||||
import useRundown from '../../common/hooks-query/useRundown';
|
import useRundown from '../../common/hooks-query/useRundown';
|
||||||
import { OntimeEvent } from '../../common/models/EventTypes';
|
|
||||||
import { millisToMinutes } from '../../common/utils/dateConfig';
|
import { millisToMinutes } from '../../common/utils/dateConfig';
|
||||||
import getDelayTo from '../../common/utils/getDelayTo';
|
import getDelayTo from '../../common/utils/getDelayTo';
|
||||||
import { stringFromMillis } from '../../common/utils/time';
|
import { stringFromMillis } from '../../common/utils/time';
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { FiMinusCircle } from '@react-icons/all-files/fi/FiMinusCircle';
|
|||||||
import { FiTrash2 } from '@react-icons/all-files/fi/FiTrash2';
|
import { FiTrash2 } from '@react-icons/all-files/fi/FiTrash2';
|
||||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||||
import { IoTimerOutline } from '@react-icons/all-files/io5/IoTimerOutline';
|
import { IoTimerOutline } from '@react-icons/all-files/io5/IoTimerOutline';
|
||||||
|
import { SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { CursorContext } from '../../common/context/CursorContext';
|
import { CursorContext } from '../../common/context/CursorContext';
|
||||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||||
import { SupportedEvent } from '../../common/models/EventTypes';
|
|
||||||
|
|
||||||
import style from './RundownMenu.module.scss';
|
import style from './RundownMenu.module.scss';
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { eventSettingsAtom } from '../../common/atoms/LocalEventSettings';
|
|||||||
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
||||||
import { LoggingContext } from '../../common/context/LoggingContext';
|
import { LoggingContext } from '../../common/context/LoggingContext';
|
||||||
import useSettings from '../../common/hooks-query/useSettings';
|
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 { inputProps } from './modalHelper';
|
||||||
import SubmitContainer from './SubmitContainer';
|
import SubmitContainer from './SubmitContainer';
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useCallback, useContext, useEffect, useState } from 'react';
|
import { useCallback, useContext, useEffect, useState } from 'react';
|
||||||
import { FormLabel, Input, ModalBody, Textarea } from '@chakra-ui/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 { LoggingContext } from '../../common/context/LoggingContext';
|
||||||
import useEvent from '../../common/hooks-query/useEvent';
|
import useEventData from '../../common/hooks-query/useEventData';
|
||||||
import { eventDataPlaceholder } from '../../common/models/EventData.type';
|
import { eventDataPlaceholder } from '../../common/models/EventData';
|
||||||
|
|
||||||
import { inputProps } from './modalHelper';
|
import { inputProps } from './modalHelper';
|
||||||
import SubmitContainer from './SubmitContainer';
|
import SubmitContainer from './SubmitContainer';
|
||||||
@@ -12,7 +12,7 @@ import SubmitContainer from './SubmitContainer';
|
|||||||
import style from './Modals.module.scss';
|
import style from './Modals.module.scss';
|
||||||
|
|
||||||
export default function SettingsModal() {
|
export default function SettingsModal() {
|
||||||
const { data, status, refetch } = useEvent();
|
const { data, status, refetch } = useEventData();
|
||||||
const { emitError } = useContext(LoggingContext);
|
const { emitError } = useContext(LoggingContext);
|
||||||
const [formData, setFormData] = useState(eventDataPlaceholder);
|
const [formData, setFormData] = useState(eventDataPlaceholder);
|
||||||
const [changed, setChanged] = useState(false);
|
const [changed, setChanged] = useState(false);
|
||||||
@@ -44,7 +44,7 @@ export default function SettingsModal() {
|
|||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await postEvent(formData);
|
await postEventData(formData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
emitError(`Error saving event settings: ${error}`);
|
emitError(`Error saving event settings: ${error}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { FiInfo } from '@react-icons/all-files/fi/FiInfo';
|
|||||||
|
|
||||||
import { LoggingContext } from '../../common/context/LoggingContext';
|
import { LoggingContext } from '../../common/context/LoggingContext';
|
||||||
import useInfo from '../../common/hooks-query/useInfo';
|
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 { ontimeVars } from '../../common/models/OntimeVars';
|
||||||
|
|
||||||
import { inputProps } from './modalHelper';
|
import { inputProps } from './modalHelper';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { IoInformationCircleOutline } from '@react-icons/all-files/io5/IoInforma
|
|||||||
import { postUserFields } from '../../common/api/ontimeApi';
|
import { postUserFields } from '../../common/api/ontimeApi';
|
||||||
import { LoggingContext } from '../../common/context/LoggingContext';
|
import { LoggingContext } from '../../common/context/LoggingContext';
|
||||||
import useUserFields from '../../common/hooks-query/useUserFields';
|
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 { handleLinks, host } from '../../common/utils/linkUtils';
|
||||||
|
|
||||||
import SubmitContainer from './SubmitContainer';
|
import SubmitContainer from './SubmitContainer';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Button, FormControl, Input, ModalBody, ModalFooter, Switch } from '@cha
|
|||||||
import { postOSC } from '../../../common/api/ontimeApi';
|
import { postOSC } from '../../../common/api/ontimeApi';
|
||||||
import { LoggingContext } from '../../../common/context/LoggingContext';
|
import { LoggingContext } from '../../../common/context/LoggingContext';
|
||||||
import useOscSettings from '../../../common/hooks-query/useOscSettings';
|
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 { isIPAddress, isOnlyNumbers } from '../../../common/utils/regex';
|
||||||
|
|
||||||
import styles from '../Modal.module.scss';
|
import styles from '../Modal.module.scss';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { postOSC } from '../../../common/api/ontimeApi';
|
|||||||
import EnableBtn from '../../../common/components/buttons/EnableBtn';
|
import EnableBtn from '../../../common/components/buttons/EnableBtn';
|
||||||
import { LoggingContext } from '../../../common/context/LoggingContext';
|
import { LoggingContext } from '../../../common/context/LoggingContext';
|
||||||
import useOscSettings from '../../../common/hooks-query/useOscSettings';
|
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 { inputProps, portInputProps } from '../modalHelper';
|
||||||
import SubmitContainer from '../SubmitContainer';
|
import SubmitContainer from '../SubmitContainer';
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
|||||||
import { Button } from '@chakra-ui/react';
|
import { Button } from '@chakra-ui/react';
|
||||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import PropTypes from 'prop-types';
|
import { OntimeRundown, SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { defaultPublicAtom, showQuickEntryAtom, startTimeIsLastEndAtom } from '../../common/atoms/LocalEventSettings';
|
import { defaultPublicAtom, showQuickEntryAtom, startTimeIsLastEndAtom } from '../../common/atoms/LocalEventSettings';
|
||||||
import Empty from '../../common/components/state/Empty';
|
import Empty from '../../common/components/state/Empty';
|
||||||
import { CursorContext } from '../../common/context/CursorContext';
|
import { CursorContext } from '../../common/context/CursorContext';
|
||||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||||
import { useRundownEditor } from '../../common/hooks/useSocket';
|
import { useRundownEditor } from '../../common/hooks/useSocket';
|
||||||
import { OntimeRundown, SupportedEvent } from '../../common/models/EventTypes';
|
|
||||||
import { cloneEvent } from '../../common/utils/eventsManager';
|
import { cloneEvent } from '../../common/utils/eventsManager';
|
||||||
|
|
||||||
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
||||||
@@ -25,8 +24,7 @@ interface RundownProps {
|
|||||||
export default function Rundown(props: RundownProps) {
|
export default function Rundown(props: RundownProps) {
|
||||||
const { entries } = props;
|
const { entries } = props;
|
||||||
const { data } = useRundownEditor();
|
const { data } = useRundownEditor();
|
||||||
const { cursor, moveCursorUp, moveCursorDown, moveCursorTo, isCursorLocked } =
|
const { cursor, moveCursorUp, moveCursorDown, moveCursorTo, isCursorLocked } = useContext(CursorContext);
|
||||||
useContext(CursorContext);
|
|
||||||
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
||||||
const defaultPublic = useAtomValue(defaultPublicAtom);
|
const defaultPublic = useAtomValue(defaultPublicAtom);
|
||||||
const { addEvent, reorderEvent } = useEventAction();
|
const { addEvent, reorderEvent } = useEventAction();
|
||||||
@@ -260,7 +258,3 @@ export default function Rundown(props: RundownProps) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rundown.propTypes = {
|
|
||||||
entries: PropTypes.array,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { useCallback, useContext } from 'react';
|
import { useCallback, useContext } from 'react';
|
||||||
import { useAtom, useAtomValue } from 'jotai';
|
import { useAtom, useAtomValue } from 'jotai';
|
||||||
|
import { OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { defaultPublicAtom, editorEventId, startTimeIsLastEndAtom } from '../../common/atoms/LocalEventSettings';
|
import { defaultPublicAtom, editorEventId, startTimeIsLastEndAtom } from '../../common/atoms/LocalEventSettings';
|
||||||
import { CursorContext } from '../../common/context/CursorContext';
|
import { CursorContext } from '../../common/context/CursorContext';
|
||||||
import { LoggingContext } from '../../common/context/LoggingContext';
|
import { LoggingContext } from '../../common/context/LoggingContext';
|
||||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
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 { cloneEvent } from '../../common/utils/eventsManager';
|
||||||
import { calculateDuration } from '../../common/utils/timesManager';
|
import { calculateDuration } from '../../common/utils/timesManager';
|
||||||
|
|
||||||
@@ -14,14 +13,7 @@ import BlockBlock from './block-block/BlockBlock';
|
|||||||
import DelayBlock from './delay-block/DelayBlock';
|
import DelayBlock from './delay-block/DelayBlock';
|
||||||
import EventBlock from './event-block/EventBlock';
|
import EventBlock from './event-block/EventBlock';
|
||||||
|
|
||||||
export type EventItemActions =
|
export type EventItemActions = 'set-cursor' | 'event' | 'delay' | 'block' | 'delete' | 'clone' | 'update';
|
||||||
'set-cursor'
|
|
||||||
| 'event'
|
|
||||||
| 'delay'
|
|
||||||
| 'block'
|
|
||||||
| 'delete'
|
|
||||||
| 'clone'
|
|
||||||
| 'update'
|
|
||||||
|
|
||||||
interface RundownEntryProps {
|
interface RundownEntryProps {
|
||||||
type: SupportedEvent;
|
type: SupportedEvent;
|
||||||
@@ -38,18 +30,7 @@ interface RundownEntryProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function RundownEntry(props: RundownEntryProps) {
|
export default function RundownEntry(props: RundownEntryProps) {
|
||||||
const {
|
const { index, eventIndex, data, selected, hasCursor, next, delay, previousEnd, previousEventId, playback } = props;
|
||||||
index,
|
|
||||||
eventIndex,
|
|
||||||
data,
|
|
||||||
selected,
|
|
||||||
hasCursor,
|
|
||||||
next,
|
|
||||||
delay,
|
|
||||||
previousEnd,
|
|
||||||
previousEventId,
|
|
||||||
playback,
|
|
||||||
} = props;
|
|
||||||
const { emitError } = useContext(LoggingContext);
|
const { emitError } = useContext(LoggingContext);
|
||||||
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
||||||
const defaultPublic = useAtomValue(defaultPublicAtom);
|
const defaultPublic = useAtomValue(defaultPublicAtom);
|
||||||
@@ -61,7 +42,7 @@ export default function RundownEntry(props: RundownEntryProps) {
|
|||||||
type FieldValue = {
|
type FieldValue = {
|
||||||
field: keyof Omit<OntimeEvent, 'duration'> | 'durationOverride';
|
field: keyof Omit<OntimeEvent, 'duration'> | 'durationOverride';
|
||||||
value: unknown;
|
value: unknown;
|
||||||
}
|
};
|
||||||
const actionHandler = useCallback(
|
const actionHandler = useCallback(
|
||||||
(action: EventItemActions, payload?: number | FieldValue) => {
|
(action: EventItemActions, payload?: number | FieldValue) => {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
@@ -171,19 +152,11 @@ export default function RundownEntry(props: RundownEntryProps) {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (data.type === SupportedEvent.Block) {
|
} else if (data.type === SupportedEvent.Block) {
|
||||||
return <BlockBlock
|
// @ts-expect-error -- revise types here
|
||||||
index={index}
|
return <BlockBlock index={index} data={data} hasCursor={hasCursor} actionHandler={actionHandler} />;
|
||||||
data={data}
|
|
||||||
hasCursor={hasCursor}
|
|
||||||
actionHandler={actionHandler}
|
|
||||||
/>;
|
|
||||||
} else if (data.type === SupportedEvent.Delay) {
|
} else if (data.type === SupportedEvent.Delay) {
|
||||||
return <DelayBlock
|
// @ts-expect-error -- revise types here
|
||||||
index={index}
|
return <DelayBlock index={index} data={data} hasCursor={hasCursor} actionHandler={actionHandler} />;
|
||||||
data={data}
|
|
||||||
hasCursor={hasCursor}
|
|
||||||
actionHandler={actionHandler}
|
|
||||||
/>;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { Draggable } from 'react-beautiful-dnd';
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo';
|
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 { cx } from '../../../common/utils/styleUtils';
|
||||||
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
|
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
|
||||||
import { EventItemActions } from '../RundownEntry';
|
import { EventItemActions } from '../RundownEntry';
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import { Draggable } from 'react-beautiful-dnd';
|
|||||||
import { Button, HStack } from '@chakra-ui/react';
|
import { Button, HStack } from '@chakra-ui/react';
|
||||||
import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark';
|
import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark';
|
||||||
import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo';
|
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 DelayInput from '../../../common/components/input/delay-input/DelayInput';
|
||||||
import { useEventAction } from '../../../common/hooks/useEventAction';
|
import { useEventAction } from '../../../common/hooks/useEventAction';
|
||||||
import { millisToMinutes } from '../../../common/utils/dateConfig';
|
import { millisToMinutes } from '../../../common/utils/dateConfig';
|
||||||
|
|
||||||
import { OntimeDelay, OntimeEvent } from '../../../common/models/EventTypes';
|
|
||||||
import { cx } from '../../../common/utils/styleUtils';
|
import { cx } from '../../../common/utils/styleUtils';
|
||||||
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
|
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
|
||||||
import { EventItemActions } from '../RundownEntry';
|
import { EventItemActions } from '../RundownEntry';
|
||||||
@@ -15,10 +15,10 @@ import { EventItemActions } from '../RundownEntry';
|
|||||||
import style from './DelayBlock.module.scss';
|
import style from './DelayBlock.module.scss';
|
||||||
|
|
||||||
interface DelayBlockProps {
|
interface DelayBlockProps {
|
||||||
data: OntimeDelay,
|
data: OntimeDelay;
|
||||||
index: number;
|
index: number;
|
||||||
hasCursor: boolean;
|
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) {
|
export default function DelayBlock(props: DelayBlockProps) {
|
||||||
@@ -30,7 +30,7 @@ export default function DelayBlock(props: DelayBlockProps) {
|
|||||||
if (hasCursor) {
|
if (hasCursor) {
|
||||||
onFocusRef?.current?.focus();
|
onFocusRef?.current?.focus();
|
||||||
}
|
}
|
||||||
}, [hasCursor])
|
}, [hasCursor]);
|
||||||
|
|
||||||
const applyDelayHandler = useCallback(() => {
|
const applyDelayHandler = useCallback(() => {
|
||||||
applyDelay(data.id);
|
applyDelay(data.id);
|
||||||
@@ -48,10 +48,7 @@ export default function DelayBlock(props: DelayBlockProps) {
|
|||||||
[data.id, updateEvent],
|
[data.id, updateEvent],
|
||||||
);
|
);
|
||||||
|
|
||||||
const blockClasses = cx([
|
const blockClasses = cx([style.delay, hasCursor ? style.hasCursor : null]);
|
||||||
style.delay,
|
|
||||||
hasCursor ? style.hasCursor : null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const delayValue = data.duration != null ? millisToMinutes(data.duration) : undefined;
|
const delayValue = data.duration != null ? millisToMinutes(data.duration) : undefined;
|
||||||
|
|
||||||
@@ -62,17 +59,9 @@ export default function DelayBlock(props: DelayBlockProps) {
|
|||||||
<span className={style.drag} {...provided.dragHandleProps} ref={onFocusRef}>
|
<span className={style.drag} {...provided.dragHandleProps} ref={onFocusRef}>
|
||||||
<IoReorderTwo />
|
<IoReorderTwo />
|
||||||
</span>
|
</span>
|
||||||
<DelayInput
|
<DelayInput value={delayValue} submitHandler={delaySubmitHandler} />
|
||||||
value={delayValue}
|
|
||||||
submitHandler={delaySubmitHandler}
|
|
||||||
/>
|
|
||||||
<HStack spacing='8px' className={style.actionOverlay}>
|
<HStack spacing='8px' className={style.actionOverlay}>
|
||||||
<Button
|
<Button onClick={applyDelayHandler} size='sm' leftIcon={<IoCheckmark />} variant='ontime-subtle-white'>
|
||||||
onClick={applyDelayHandler}
|
|
||||||
size='sm'
|
|
||||||
leftIcon={<IoCheckmark />}
|
|
||||||
variant='ontime-subtle-white'
|
|
||||||
>
|
|
||||||
Apply delay
|
Apply delay
|
||||||
</Button>
|
</Button>
|
||||||
<BlockActionMenu showAdd enableDelete actionHandler={actionHandler} />
|
<BlockActionMenu showAdd enableDelete actionHandler={actionHandler} />
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import { IoReload } from '@react-icons/all-files/io5/IoReload';
|
|||||||
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
|
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
|
||||||
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
|
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
|
||||||
import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo';
|
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 { editorEventId } from '../../../common/atoms/LocalEventSettings';
|
||||||
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
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 { useEventAction } from '../../../common/hooks/useEventAction';
|
||||||
import { setEventPlayback } from '../../../common/hooks/useSocket';
|
import { setEventPlayback } from '../../../common/hooks/useSocket';
|
||||||
import { Playback } from '../../../common/models/OntimeTypes';
|
import { cx, getAccessibleColour } from '../../../common/utils/styleUtils';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
import { EventItemActions } from '../RundownEntry';
|
import { EventItemActions } from '../RundownEntry';
|
||||||
|
|
||||||
@@ -129,11 +129,7 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
return (
|
return (
|
||||||
<Draggable key={eventId} draggableId={eventId} index={index}>
|
<Draggable key={eventId} draggableId={eventId} index={index}>
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
<div
|
<div className={blockClasses} {...provided.draggableProps} ref={provided.innerRef}>
|
||||||
className={blockClasses}
|
|
||||||
{...provided.draggableProps}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className={style.binder}
|
className={style.binder}
|
||||||
style={{ ...binderColours }}
|
style={{ ...binderColours }}
|
||||||
@@ -206,22 +202,13 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
<div className={selected ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
|
<div className={selected ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
|
||||||
<EventBlockProgressBar playback={playback} />
|
<EventBlockProgressBar playback={playback} />
|
||||||
</div>
|
</div>
|
||||||
<div className={style.eventStatus} tabIndex={-1}
|
<div className={style.eventStatus} tabIndex={-1}>
|
||||||
>
|
<Tooltip label='Next event' isDisabled={!next} {...tooltipProps}>
|
||||||
<Tooltip
|
|
||||||
label='Next event'
|
|
||||||
isDisabled={!next}
|
|
||||||
{...tooltipProps}
|
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
<IoPlaySkipForward
|
<IoPlaySkipForward className={`${style.statusIcon} ${next ? style.active : ''}`} />
|
||||||
className={`${style.statusIcon} ${next ? style.active : ''}`} />
|
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip label={`${isPublic ? 'Event is public' : 'Event is private'}`} {...tooltipProps}>
|
||||||
label={`${isPublic ? 'Event is public' : 'Event is private'}`}
|
|
||||||
{...tooltipProps}
|
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
<IoPeople className={`${style.statusIcon} ${isPublic ? style.active : ''}`} />
|
<IoPeople className={`${style.statusIcon} ${isPublic ? style.active : ''}`} />
|
||||||
</span>
|
</span>
|
||||||
@@ -234,7 +221,7 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
variant='ontime-subtle-white'
|
variant='ontime-subtle-white'
|
||||||
size='sm'
|
size='sm'
|
||||||
icon={<IoOptions />}
|
icon={<IoOptions />}
|
||||||
clickHandler={() => setOpenId((prev) => prev === eventId ? null : eventId)}
|
clickHandler={() => setOpenId((prev) => (prev === eventId ? null : eventId))}
|
||||||
tooltip='Event options'
|
tooltip='Event options'
|
||||||
aria-label='Event options'
|
aria-label='Event options'
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
import { useTimer } from '../../../../common/hooks/useSocket';
|
import { useTimer } from '../../../../common/hooks/useSocket';
|
||||||
import { Playback } from '../../../../common/models/OntimeTypes';
|
|
||||||
import { clamp } from '../../../../common/utils/math';
|
import { clamp } from '../../../../common/utils/math';
|
||||||
|
|
||||||
import style from './EventBlockProgressBar.module.scss';
|
import style from './EventBlockProgressBar.module.scss';
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { useCallback, useContext, useRef } from 'react';
|
import { useCallback, useContext, useRef } from 'react';
|
||||||
import { Button, Checkbox, Tooltip } from '@chakra-ui/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 { defaultPublicAtom, startTimeIsLastEndAtom } from '../../../common/atoms/LocalEventSettings';
|
||||||
import { LoggingContext } from '../../../common/context/LoggingContext';
|
import { LoggingContext } from '../../../common/context/LoggingContext';
|
||||||
import { useEventAction } from '../../../common/hooks/useEventAction';
|
import { useEventAction } from '../../../common/hooks/useEventAction';
|
||||||
import { SupportedEvent } from '../../../common/models/EventTypes';
|
|
||||||
import { useAtomValue } from 'jotai';
|
|
||||||
|
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import style from './QuickAddBlock.module.scss';
|
import style from './QuickAddBlock.module.scss';
|
||||||
@@ -19,13 +19,7 @@ interface QuickAddBlockProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function QuickAddBlock(props: QuickAddBlockProps) {
|
export default function QuickAddBlock(props: QuickAddBlockProps) {
|
||||||
const {
|
const { showKbd, eventId, previousEventId, disableAddDelay = true, disableAddBlock } = props;
|
||||||
showKbd,
|
|
||||||
eventId,
|
|
||||||
previousEventId,
|
|
||||||
disableAddDelay = true,
|
|
||||||
disableAddBlock,
|
|
||||||
} = props;
|
|
||||||
const { addEvent } = useEventAction();
|
const { addEvent } = useEventAction();
|
||||||
const { emitError } = useContext(LoggingContext);
|
const { emitError } = useContext(LoggingContext);
|
||||||
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
const startTimeIsLastEnd = useAtomValue(startTimeIsLastEndAtom);
|
||||||
@@ -33,45 +27,47 @@ export default function QuickAddBlock(props: QuickAddBlockProps) {
|
|||||||
const doStartTime = useRef<HTMLInputElement | null>(null);
|
const doStartTime = useRef<HTMLInputElement | null>(null);
|
||||||
const doPublic = useRef<HTMLInputElement | null>(null);
|
const doPublic = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
const handleCreateEvent = useCallback((eventType: SupportedEvent) => {
|
const handleCreateEvent = useCallback(
|
||||||
switch (eventType) {
|
(eventType: SupportedEvent) => {
|
||||||
case 'event': {
|
switch (eventType) {
|
||||||
const isPublicOption = doPublic?.current?.checked;
|
case 'event': {
|
||||||
const startTimeIsLastEndOption = doStartTime?.current?.checked;
|
const isPublicOption = doPublic?.current?.checked;
|
||||||
|
const startTimeIsLastEndOption = doStartTime?.current?.checked;
|
||||||
|
|
||||||
const newEvent = { type: SupportedEvent.Event };
|
const newEvent = { type: SupportedEvent.Event };
|
||||||
const options = {
|
const options = {
|
||||||
defaultPublic: isPublicOption,
|
defaultPublic: isPublicOption,
|
||||||
startTimeIsLastEnd: startTimeIsLastEndOption,
|
startTimeIsLastEnd: startTimeIsLastEndOption,
|
||||||
lastEventId: previousEventId,
|
lastEventId: previousEventId,
|
||||||
after: eventId,
|
after: eventId,
|
||||||
};
|
};
|
||||||
addEvent(newEvent, options);
|
addEvent(newEvent, options);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case 'delay': {
|
|
||||||
const options = {
|
|
||||||
lastEventId: previousEventId,
|
|
||||||
after: eventId,
|
|
||||||
}
|
}
|
||||||
addEvent({ type: SupportedEvent.Delay }, options);
|
case 'delay': {
|
||||||
break;
|
const options = {
|
||||||
}
|
lastEventId: previousEventId,
|
||||||
case 'block': {
|
after: eventId,
|
||||||
const options= {
|
};
|
||||||
lastEventId: previousEventId,
|
addEvent({ type: SupportedEvent.Delay }, options);
|
||||||
after: eventId,
|
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}`);
|
[previousEventId, eventId, addEvent, emitError],
|
||||||
break;
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [previousEventId, eventId, addEvent, emitError]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.quickAdd}>
|
<div className={style.quickAdd}>
|
||||||
@@ -110,20 +106,10 @@ export default function QuickAddBlock(props: QuickAddBlockProps) {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.options}>
|
<div className={style.options}>
|
||||||
<Checkbox
|
<Checkbox ref={doStartTime} size='sm' variant='ontime-ondark' defaultChecked={startTimeIsLastEnd}>
|
||||||
ref={doStartTime}
|
|
||||||
size='sm'
|
|
||||||
variant='ontime-ondark'
|
|
||||||
defaultChecked={startTimeIsLastEnd}
|
|
||||||
>
|
|
||||||
Start time is last end
|
Start time is last end
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<Checkbox
|
<Checkbox ref={doPublic} size='sm' variant='ontime-ondark' defaultChecked={defaultPublic}>
|
||||||
ref={doPublic}
|
|
||||||
size='sm'
|
|
||||||
variant='ontime-ondark'
|
|
||||||
defaultChecked={defaultPublic}
|
|
||||||
>
|
|
||||||
Event is public
|
Event is public
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
||||||
import useFullscreen from '../../common/hooks/useFullscreen';
|
import useFullscreen from '../../common/hooks/useFullscreen';
|
||||||
import { useTimer } from '../../common/hooks/useSocket';
|
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 { formatDisplay, millisToSeconds } from '../../common/utils/dateConfig';
|
||||||
import { formatTime } from '../../common/utils/time';
|
import { formatTime } from '../../common/utils/time';
|
||||||
import { tooltipDelayFast } from '../../ontimeConfig';
|
import { tooltipDelayFast } from '../../ontimeConfig';
|
||||||
@@ -24,7 +24,7 @@ export default function TableHeader({ handleCSVExport, featureData }) {
|
|||||||
useContext(TableSettingsContext);
|
useContext(TableSettingsContext);
|
||||||
const { data: timer } = useTimer();
|
const { data: timer } = useTimer();
|
||||||
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
||||||
const { data: event } = useEvent();
|
const { data: event } = useEventData();
|
||||||
|
|
||||||
const selected = !featureData.numEvents
|
const selected = !featureData.numEvents
|
||||||
? 'No events'
|
? 'No events'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'react';
|
|||||||
|
|
||||||
import { useMessageControl } from '../../common/hooks/useSocket';
|
import { useMessageControl } from '../../common/hooks/useSocket';
|
||||||
import useSubscription from '../../common/hooks/useSubscription';
|
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 useRundown from '../../common/hooks-query/useRundown';
|
||||||
import useViewSettings from '../../common/hooks-query/useViewSettings';
|
import useViewSettings from '../../common/hooks-query/useViewSettings';
|
||||||
import socket from '../../common/utils/socket';
|
import socket from '../../common/utils/socket';
|
||||||
@@ -11,13 +11,13 @@ import socket from '../../common/utils/socket';
|
|||||||
const withSocket = (Component) => {
|
const withSocket = (Component) => {
|
||||||
return (props) => {
|
return (props) => {
|
||||||
const { data: eventsData } = useRundown();
|
const { data: eventsData } = useRundown();
|
||||||
const { data: genData } = useEvent();
|
const { data: genData } = useEventData();
|
||||||
const { data: viewSettings } = useViewSettings();
|
const { data: viewSettings } = useViewSettings();
|
||||||
const { data: messages } = useMessageControl();
|
const { data: messageControl } = useMessageControl();
|
||||||
|
|
||||||
const [publicSelectedId, setPublicSelectedId] = useState(null);
|
const [publicSelectedId, setPublicSelectedId] = useState(null);
|
||||||
|
|
||||||
const [timer] = useSubscription('ontime-timer', {
|
const [timer] = useSubscription('timer', {
|
||||||
clock: null,
|
clock: null,
|
||||||
current: null,
|
current: null,
|
||||||
elapsed: null ,
|
elapsed: null ,
|
||||||
@@ -123,9 +123,9 @@ const withSocket = (Component) => {
|
|||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
{...props}
|
{...props}
|
||||||
pres={messages.presenter}
|
pres={messageControl.messages.presenter}
|
||||||
publ={messages.public}
|
publ={messageControl.messages.public}
|
||||||
lower={messages.lower}
|
lower={messageControl.messages.lower}
|
||||||
title={titleManager}
|
title={titleManager}
|
||||||
publicTitle={publicTitleManager}
|
publicTitle={publicTitleManager}
|
||||||
time={TimeManagerType}
|
time={TimeManagerType}
|
||||||
@@ -136,7 +136,7 @@ const withSocket = (Component) => {
|
|||||||
viewSettings={viewSettings}
|
viewSettings={viewSettings}
|
||||||
nextId={nextId}
|
nextId={nextId}
|
||||||
general={genData}
|
general={genData}
|
||||||
onAir={messages.onAir}
|
onAir={messageControl.onAir}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { ViewSettings } from 'ontime-types';
|
||||||
|
|
||||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||||
import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings';
|
import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings';
|
||||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
||||||
import { ViewSettingsType } from '../../../common/models/ViewSettings.type';
|
import { OverridableOptions } from '../../../common/models/View.types';
|
||||||
import { OverridableOptions } from '../../../common/models/ViewTypes';
|
|
||||||
import { formatTime } from '../../../common/utils/time';
|
import { formatTime } from '../../../common/utils/time';
|
||||||
|
|
||||||
import './Clock.scss';
|
import './Clock.scss';
|
||||||
|
|
||||||
interface ClockProps {
|
interface ClockProps {
|
||||||
time: TimeManagerType;
|
time: TimeManagerType;
|
||||||
viewSettings: ViewSettingsType;
|
viewSettings: ViewSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatOptions = {
|
const formatOptions = {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from 'ontime-types';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||||
import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings';
|
import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings';
|
||||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../../../common/models/EventTypes';
|
|
||||||
import { formatDisplay, millisToSeconds } from '../../../common/utils/dateConfig';
|
import { formatDisplay, millisToSeconds } from '../../../common/utils/dateConfig';
|
||||||
import getDelayTo from '../../../common/utils/getDelayTo';
|
import getDelayTo from '../../../common/utils/getDelayTo';
|
||||||
import { formatTime } from '../../../common/utils/time';
|
import { formatTime } from '../../../common/utils/time';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import Empty from '../../../common/components/state/Empty';
|
import Empty from '../../../common/components/state/Empty';
|
||||||
import { OntimeEvent, OntimeRundownEntry, SupportedEvent } from '../../../common/models/EventTypes';
|
|
||||||
import { formatTime } from '../../../common/utils/time';
|
import { formatTime } from '../../../common/utils/time';
|
||||||
|
|
||||||
import { sanitiseTitle } from './countdown.helpers';
|
import { sanitiseTitle } from './countdown.helpers';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { OntimeEvent } from '../../../common/models/EventTypes';
|
import { OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
||||||
|
|
||||||
export enum TimerMessage {
|
export enum TimerMessage {
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { EventDataType } from 'common/models/EventData.type';
|
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { EventData, Message, ViewSettings } from 'ontime-types';
|
||||||
|
|
||||||
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
||||||
import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings';
|
import { mirrorViewersAtom } from '../../../common/atoms/ViewerSettings';
|
||||||
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { PresenterMessageType } from '../../../common/models/PresenterMessage.type';
|
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
||||||
import { ViewSettingsType } from '../../../common/models/ViewSettings.type';
|
import { OverridableOptions } from '../../../common/models/View.types';
|
||||||
import { OverridableOptions } from '../../../common/models/ViewTypes';
|
|
||||||
import { formatDisplay, millisToSeconds } from '../../../common/utils/dateConfig';
|
import { formatDisplay, millisToSeconds } from '../../../common/utils/dateConfig';
|
||||||
|
|
||||||
import './MinimalTimer.scss';
|
import './MinimalTimer.scss';
|
||||||
|
|
||||||
interface MinimalTimerProps {
|
interface MinimalTimerProps {
|
||||||
pres: PresenterMessageType;
|
pres: Message;
|
||||||
time: TimeManagerType;
|
time: TimeManagerType;
|
||||||
viewSettings: ViewSettingsType;
|
viewSettings: ViewSettings;
|
||||||
general: EventDataType;
|
general: EventData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MinimalTimer(props: MinimalTimerProps) {
|
export default function MinimalTimer(props: MinimalTimerProps) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { OSCSettings } from 'ontime-types';
|
|||||||
|
|
||||||
// Import Routes
|
// Import Routes
|
||||||
import { router as rundownRouter } from './routes/rundownRouter.js';
|
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 ontimeRouter } from './routes/ontimeRouter.js';
|
||||||
import { router as playbackRouter } from './routes/playbackRouter.js';
|
import { router as playbackRouter } from './routes/playbackRouter.js';
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ app.use(express.json({ limit: '1mb' }));
|
|||||||
|
|
||||||
// Implement route endpoints
|
// Implement route endpoints
|
||||||
app.use('/eventlist', rundownRouter);
|
app.use('/eventlist', rundownRouter);
|
||||||
app.use('/event', eventRouter);
|
app.use('/eventdata', eventDataRouter);
|
||||||
app.use('/ontime', ontimeRouter);
|
app.use('/ontime', ontimeRouter);
|
||||||
app.use('/playback', playbackRouter);
|
app.use('/playback', playbackRouter);
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ enum OntimeStartOrder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let step = OntimeStartOrder.InitDB;
|
let step = OntimeStartOrder.InitDB;
|
||||||
const checkStart = (currentState) => {
|
const checkStart = (currentState: OntimeStartOrder) => {
|
||||||
if (step !== currentState) {
|
if (step !== currentState) {
|
||||||
step = OntimeStartOrder.Error;
|
step = OntimeStartOrder.Error;
|
||||||
throw new Error('Init order error: startDb > startServer > startOsc > startIntegrations');
|
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');
|
expressServer.listen(serverPort, '0.0.0.0');
|
||||||
|
|
||||||
socketServer.initServer(expressServer);
|
socketServer.initServer(expressServer);
|
||||||
socketServer.info('SERVER', 'Socket initialised');
|
|
||||||
|
|
||||||
socketServer.info('SERVER', returnMessage);
|
socketServer.info('SERVER', returnMessage);
|
||||||
socketServer.startListener();
|
socketServer.startListener();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
* Class Event Provider is a mediator for handling the local db
|
* Class Event Provider is a mediator for handling the local db
|
||||||
* and adds logic specific to ontime data
|
* and adds logic specific to ontime data
|
||||||
*/
|
*/
|
||||||
|
import { EventData, ViewSettings } from 'ontime-types';
|
||||||
|
|
||||||
import { data, db } from '../../modules/loadDb.js';
|
import { data, db } from '../../modules/loadDb.js';
|
||||||
import { safeMerge } from './DataProvider.utils.js';
|
import { safeMerge } from './DataProvider.utils.js';
|
||||||
|
|
||||||
@@ -10,14 +12,14 @@ export class DataProvider {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setEventData(newData) {
|
static async setEventData(newData: EventData) {
|
||||||
data.event = { ...data.event, ...newData };
|
data.eventData = { ...data.eventData, ...newData };
|
||||||
await this.persist();
|
await this.persist();
|
||||||
return data.event;
|
return data.eventData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getEventData() {
|
static getEventData() {
|
||||||
return data.event;
|
return data.eventData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setRundown(newData) {
|
static async setRundown(newData) {
|
||||||
@@ -40,7 +42,6 @@ export class DataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async deleteEvent(eventId) {
|
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);
|
data.rundown = Array.from(data.rundown).filter((e) => e.id !== eventId);
|
||||||
await this.persist();
|
await this.persist();
|
||||||
}
|
}
|
||||||
@@ -128,12 +129,12 @@ export class DataProvider {
|
|||||||
return { ...data.userFields };
|
return { ...data.userFields };
|
||||||
}
|
}
|
||||||
|
|
||||||
static getViews() {
|
static getViewSettings() {
|
||||||
return { ...data.views };
|
return { ...data.viewSettings };
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setViews(newData) {
|
static async setViewSettings(newData: ViewSettings) {
|
||||||
data.views = { ...newData };
|
data.viewSettings = { ...newData };
|
||||||
await this.persist();
|
await this.persist();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +159,9 @@ export class DataProvider {
|
|||||||
|
|
||||||
static async mergeIntoData(newData) {
|
static async mergeIntoData(newData) {
|
||||||
const mergedData = safeMerge(data, newData);
|
const mergedData = safeMerge(data, newData);
|
||||||
data.event = mergedData.event;
|
data.eventData = mergedData.event;
|
||||||
data.settings = mergedData.settings;
|
data.settings = mergedData.settings;
|
||||||
|
data.viewSettings = mergedData.viewSettings;
|
||||||
data.osc = mergedData.osc;
|
data.osc = mergedData.osc;
|
||||||
data.http = mergedData.http;
|
data.http = mergedData.http;
|
||||||
data.aliases = mergedData.aliases;
|
data.aliases = mergedData.aliases;
|
||||||
|
|||||||
@@ -4,15 +4,13 @@
|
|||||||
* @param {object} newData
|
* @param {object} newData
|
||||||
*/
|
*/
|
||||||
export function safeMerge(existing, 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 {
|
return {
|
||||||
...existing,
|
...existing,
|
||||||
rundown: rundown ?? existing.rundown,
|
rundown: rundown ?? existing.rundown,
|
||||||
event: { ...existing.event, ...event },
|
event: { ...existing.event, ...event },
|
||||||
settings: { ...existing.settings, ...settings },
|
settings: { ...existing.settings, ...settings },
|
||||||
views: {
|
viewSettings: { ...existing.viewSettings, ...viewSettings },
|
||||||
overrideStyles: false,
|
|
||||||
},
|
|
||||||
aliases: aliases ?? existing.aliases,
|
aliases: aliases ?? existing.aliases,
|
||||||
userFields: {
|
userFields: {
|
||||||
...existing.userFields,
|
...existing.userFields,
|
||||||
|
|||||||
+55
-21
@@ -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 { getRollTimers } from '../../services/rollUtils.js';
|
||||||
|
import { eventStore } from '../../stores/EventStore.js';
|
||||||
|
|
||||||
let instance;
|
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
|
* Manages business logic around loading events
|
||||||
*/
|
*/
|
||||||
export class EventLoader {
|
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() {
|
constructor() {
|
||||||
if (instance) {
|
if (instance) {
|
||||||
throw new Error('There can be only one');
|
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
|
// eslint-disable-next-line @typescript-eslint/no-this-alias -- this logic is used to ensure singleton
|
||||||
instance = this;
|
instance = this;
|
||||||
this.reset();
|
this.reset(false);
|
||||||
this.loadedEvent = null;
|
this.loadedEvent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,11 +141,7 @@ export class EventLoader {
|
|||||||
*/
|
*/
|
||||||
findNext() {
|
findNext() {
|
||||||
const timedEvents = EventLoader.getPlayableEvents();
|
const timedEvents = EventLoader.getPlayableEvents();
|
||||||
if (
|
if (timedEvents === null || !timedEvents.length || this.selectedEventIndex === this.numEvents - 1) {
|
||||||
timedEvents === null ||
|
|
||||||
!timedEvents.length ||
|
|
||||||
this.selectedEventIndex === this.numEvents - 1
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,15 +163,8 @@ export class EventLoader {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { nowIndex, timers, timeToNext, nextEvent, nextPublicEvent, currentEvent, currentPublicEvent } =
|
||||||
nowIndex,
|
getRollTimers(timedEvents, timeNow);
|
||||||
timers,
|
|
||||||
timeToNext,
|
|
||||||
nextEvent,
|
|
||||||
nextPublicEvent,
|
|
||||||
currentEvent,
|
|
||||||
currentPublicEvent,
|
|
||||||
} = getRollTimers(timedEvents, timeNow);
|
|
||||||
|
|
||||||
this.loadedEvent = currentEvent;
|
this.loadedEvent = currentEvent;
|
||||||
this.selectedEventIndex = nowIndex;
|
this.selectedEventIndex = nowIndex;
|
||||||
@@ -187,7 +198,10 @@ export class EventLoader {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
/**
|
||||||
|
* Resets instance state
|
||||||
|
*/
|
||||||
|
reset(emit?: boolean) {
|
||||||
this.loadedEvent = null;
|
this.loadedEvent = null;
|
||||||
this.selectedEventIndex = null;
|
this.selectedEventIndex = null;
|
||||||
this.selectedEventId = null;
|
this.selectedEventId = null;
|
||||||
@@ -209,10 +223,17 @@ export class EventLoader {
|
|||||||
titleNow: null,
|
titleNow: null,
|
||||||
subtitleNow: null,
|
subtitleNow: null,
|
||||||
presenterNow: null,
|
presenterNow: null,
|
||||||
|
noteNow: null,
|
||||||
titleNext: null,
|
titleNext: null,
|
||||||
subtitleNext: null,
|
subtitleNext: null,
|
||||||
presenterNext: 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._loadTitlesNow(event, playableEvents);
|
||||||
this._loadTitlesNext(playableEvents);
|
this._loadTitlesNext(playableEvents);
|
||||||
|
|
||||||
|
this._loadEvent();
|
||||||
|
|
||||||
return this.getLoaded();
|
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)
|
* @description loads given title (now)
|
||||||
* @private
|
* @private
|
||||||
* @param {object} event
|
* @param {object} event
|
||||||
* @param {array} rundown
|
* @param {array} rundown
|
||||||
*/
|
*/
|
||||||
_loadTitlesNow(event, rundown) {
|
private _loadTitlesNow(event, rundown) {
|
||||||
// private title is always current
|
// private title is always current
|
||||||
// check if current is also public
|
// check if current is also public
|
||||||
if (event.isPublic) {
|
if (event.isPublic) {
|
||||||
@@ -276,8 +307,7 @@ export class EventLoader {
|
|||||||
* @description look for next titles to load
|
* @description look for next titles to load
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_loadTitlesNext(rundown) {
|
private _loadTitlesNext(rundown) {
|
||||||
// Todo: is there a scenario where this gets called without an event?
|
|
||||||
// maybe there is nothing to load
|
// maybe there is nothing to load
|
||||||
if (this.selectedEventIndex === null) return;
|
if (this.selectedEventIndex === null) return;
|
||||||
|
|
||||||
@@ -324,7 +354,7 @@ export class EventLoader {
|
|||||||
* @param type
|
* @param type
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_loadThisTitles(event, type) {
|
private _loadThisTitles(event, type) {
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -336,6 +366,7 @@ export class EventLoader {
|
|||||||
this.titlesPublic.titleNow = event.title;
|
this.titlesPublic.titleNow = event.title;
|
||||||
this.titlesPublic.subtitleNow = event.subtitle;
|
this.titlesPublic.subtitleNow = event.subtitle;
|
||||||
this.titlesPublic.presenterNow = event.presenter;
|
this.titlesPublic.presenterNow = event.presenter;
|
||||||
|
this.titlesPublic.noteNow = event.note;
|
||||||
this.selectedPublicEventId = event.id;
|
this.selectedPublicEventId = event.id;
|
||||||
|
|
||||||
// private
|
// private
|
||||||
@@ -350,6 +381,7 @@ export class EventLoader {
|
|||||||
this.titlesPublic.titleNow = event.title;
|
this.titlesPublic.titleNow = event.title;
|
||||||
this.titlesPublic.subtitleNow = event.subtitle;
|
this.titlesPublic.subtitleNow = event.subtitle;
|
||||||
this.titlesPublic.presenterNow = event.presenter;
|
this.titlesPublic.presenterNow = event.presenter;
|
||||||
|
this.titlesPublic.noteNow = event.note;
|
||||||
this.selectedPublicEventId = event.id;
|
this.selectedPublicEventId = event.id;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -367,6 +399,7 @@ export class EventLoader {
|
|||||||
this.titlesPublic.titleNext = event.title;
|
this.titlesPublic.titleNext = event.title;
|
||||||
this.titlesPublic.subtitleNext = event.subtitle;
|
this.titlesPublic.subtitleNext = event.subtitle;
|
||||||
this.titlesPublic.presenterNext = event.presenter;
|
this.titlesPublic.presenterNext = event.presenter;
|
||||||
|
this.titlesPublic.noteNext = event.note;
|
||||||
this.nextPublicEventId = event.id;
|
this.nextPublicEventId = event.id;
|
||||||
|
|
||||||
// private
|
// private
|
||||||
@@ -381,6 +414,7 @@ export class EventLoader {
|
|||||||
this.titlesPublic.titleNext = event.title;
|
this.titlesPublic.titleNext = event.title;
|
||||||
this.titlesPublic.subtitleNext = event.subtitle;
|
this.titlesPublic.subtitleNext = event.subtitle;
|
||||||
this.titlesPublic.presenterNext = event.presenter;
|
this.titlesPublic.presenterNext = event.presenter;
|
||||||
|
this.titlesPublic.noteNext = event.note;
|
||||||
this.nextPublicEventId = event.id;
|
this.nextPublicEventId = event.id;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -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();
|
|
||||||
@@ -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();
|
||||||
@@ -6,8 +6,7 @@ import { stringFromMillis } from '../../utils/time.js';
|
|||||||
import { messageManager } from '../message-manager/MessageManager.js';
|
import { messageManager } from '../message-manager/MessageManager.js';
|
||||||
import { PlaybackService } from '../../services/PlaybackService.js';
|
import { PlaybackService } from '../../services/PlaybackService.js';
|
||||||
|
|
||||||
import { ADDRESS_MESSAGE_CONTROL } from './socketConfig.js';
|
import { eventTimer, TimerService } from '../../services/TimerService.js';
|
||||||
import { eventTimer, TimerService } from '../../services/TimerService.ts';
|
|
||||||
import { EventLoader, eventLoader } from '../event-loader/EventLoader.js';
|
import { EventLoader, eventLoader } from '../event-loader/EventLoader.js';
|
||||||
|
|
||||||
class SocketController {
|
class SocketController {
|
||||||
@@ -55,9 +54,7 @@ class SocketController {
|
|||||||
// keep track of connections
|
// keep track of connections
|
||||||
this.numClients++;
|
this.numClients++;
|
||||||
this._clientNames[socket.id] = getRandomName();
|
this._clientNames[socket.id] = getRandomName();
|
||||||
const message = `${this.numClients} Clients with new connection: ${
|
const message = `${this.numClients} Clients with new connection: ${this._clientNames[socket.id]}`;
|
||||||
this._clientNames[socket.id]
|
|
||||||
}`;
|
|
||||||
this.info('CLIENT', message);
|
this.info('CLIENT', message);
|
||||||
|
|
||||||
// Todo: review in favour of features
|
// Todo: review in favour of features
|
||||||
@@ -78,9 +75,7 @@ class SocketController {
|
|||||||
*/
|
*/
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
this.numClients--;
|
this.numClients--;
|
||||||
const message = `${this.numClients} Clients with disconnection: ${
|
const message = `${this.numClients} Clients with disconnection: ${this._clientNames[socket.id]}`;
|
||||||
this._clientNames[socket.id]
|
|
||||||
}`;
|
|
||||||
delete this._clientNames[socket.id];
|
delete this._clientNames[socket.id];
|
||||||
this.info('CLIENT', message);
|
this.info('CLIENT', message);
|
||||||
});
|
});
|
||||||
@@ -215,12 +210,10 @@ class SocketController {
|
|||||||
try {
|
try {
|
||||||
const featureData = messageManager.setOnAir(data);
|
const featureData = messageManager.setOnAir(data);
|
||||||
this.info('PLAYBACK', featureData.onAir ? 'Going On Air' : 'Going Off Air');
|
this.info('PLAYBACK', featureData.onAir ? 'Going On Air' : 'Going Off Air');
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.error('RX', `Failed to parse message ${data} : ${error}`);
|
this.error('RX', `Failed to parse message ${data} : ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.send('onAir', messageManager.onAir);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Presenter message
|
// Presenter message
|
||||||
@@ -228,16 +221,14 @@ class SocketController {
|
|||||||
if (typeof data !== 'string') {
|
if (typeof data !== 'string') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const featureData = messageManager.setTimerText(data);
|
messageManager.setTimerText(data);
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('set-timer-message-visible', (data) => {
|
socket.on('set-timer-message-visible', (data) => {
|
||||||
if (typeof data !== 'boolean') {
|
if (typeof data !== 'boolean') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const featureData = messageManager.setTimerVisibility(data);
|
messageManager.setTimerVisibility(data);
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
@@ -246,16 +237,14 @@ class SocketController {
|
|||||||
if (typeof data !== 'string') {
|
if (typeof data !== 'string') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const featureData = messageManager.setPublicText(data);
|
messageManager.setPublicText(data);
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('set-public-message-visible', (data) => {
|
socket.on('set-public-message-visible', (data) => {
|
||||||
if (typeof data !== 'boolean') {
|
if (typeof data !== 'boolean') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const featureData = messageManager.setPublicVisibility(data);
|
messageManager.setPublicVisibility(data);
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
@@ -264,16 +253,14 @@ class SocketController {
|
|||||||
if (typeof data !== 'string') {
|
if (typeof data !== 'string') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const featureData = messageManager.setLowerText(data);
|
messageManager.setLowerText(data);
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('set-lower-message-visible', (data) => {
|
socket.on('set-lower-message-visible', (data) => {
|
||||||
if (typeof data !== 'boolean') {
|
if (typeof data !== 'boolean') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const featureData = messageManager.setLowerVisibility(data);
|
messageManager.setLowerVisibility(data);
|
||||||
this.socket.emit(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* MOLECULAR ENDPOINTS
|
/* MOLECULAR ENDPOINTS
|
||||||
@@ -312,8 +299,9 @@ class SocketController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 6. TIMER
|
// 6. TIMER
|
||||||
socket.on('get-ontime-timer', () => {
|
socket.on('get-timer', () => {
|
||||||
this.broadcastTimer();
|
// TODO: Not ideal workaround
|
||||||
|
socket.emit('timer', eventTimer.timer);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -373,7 +361,7 @@ class SocketController {
|
|||||||
*/
|
*/
|
||||||
broadcastFeatureMessageControl() {
|
broadcastFeatureMessageControl() {
|
||||||
const featureData = messageManager.getAll();
|
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);
|
this.send('feat-cuesheet', featureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// TODO: ouch, services should update the store
|
||||||
* Broadcast Timer feature
|
// make middleware to maintain the features OR remove the feature endpoints
|
||||||
*/
|
|
||||||
broadcastTimer() {
|
|
||||||
const featureData = eventTimer.timer;
|
|
||||||
this.send('ontime-timer', featureData);
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcastState() {
|
broadcastState() {
|
||||||
this.broadcastFeatureRundown();
|
this.broadcastFeatureRundown();
|
||||||
this.broadcastFeatureMessageControl();
|
this.broadcastFeatureMessageControl();
|
||||||
this.broadcastFeaturePlaybackControl();
|
this.broadcastFeaturePlaybackControl();
|
||||||
this.broadcastFeatureInfo();
|
this.broadcastFeatureInfo();
|
||||||
this.broadcastFeatureCuesheet();
|
this.broadcastFeatureCuesheet();
|
||||||
this.broadcastTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export const ADDRESS_MESSAGE_CONTROL = 'feat-messagecontrol';
|
|
||||||
@@ -4,7 +4,6 @@ import { OSCSettings } from 'ontime-types';
|
|||||||
import { PlaybackService } from '../services/PlaybackService.js';
|
import { PlaybackService } from '../services/PlaybackService.js';
|
||||||
import { messageManager } from '../classes/message-manager/MessageManager.js';
|
import { messageManager } from '../classes/message-manager/MessageManager.js';
|
||||||
import { socketProvider } from '../classes/socket/SocketController.js';
|
import { socketProvider } from '../classes/socket/SocketController.js';
|
||||||
import { ADDRESS_MESSAGE_CONTROL } from '../classes/socket/socketConfig.js';
|
|
||||||
|
|
||||||
let oscServer = null;
|
let oscServer = null;
|
||||||
|
|
||||||
@@ -47,13 +46,11 @@ export const initiateOSC = (config: OSCSettings) => {
|
|||||||
|
|
||||||
switch (path.toLowerCase()) {
|
switch (path.toLowerCase()) {
|
||||||
case 'onair': {
|
case 'onair': {
|
||||||
const featureData = messageManager.setOnAir(true);
|
messageManager.setOnAir(true);
|
||||||
socketProvider.send(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'offair': {
|
case 'offair': {
|
||||||
const featureData = messageManager.setOnAir(false);
|
messageManager.setOnAir(false);
|
||||||
socketProvider.send(ADDRESS_MESSAGE_CONTROL, featureData);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'play': {
|
case 'play': {
|
||||||
|
|||||||
@@ -2,18 +2,18 @@ import fs from 'fs';
|
|||||||
import { networkInterfaces } from 'os';
|
import { networkInterfaces } from 'os';
|
||||||
import { generateId } from 'ontime-utils';
|
import { generateId } from 'ontime-utils';
|
||||||
import { fileHandler } from '../utils/parser.js';
|
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 { failEmptyObjects, failIsNotArray } from '../utils/routerUtils.js';
|
||||||
import { mergeObject } from '../utils/parserUtils.js';
|
import { mergeObject } from '../utils/parserUtils.js';
|
||||||
import { PlaybackService } from '../services/PlaybackService.js';
|
import { PlaybackService } from '../services/PlaybackService.js';
|
||||||
import { runtimeState } from '../stores/EventStore.js';
|
import { eventStore } from '../stores/EventStore.js';
|
||||||
import { resolveDbPath } from '../setup.js';
|
import { resolveDbPath } from '../setup.js';
|
||||||
|
|
||||||
// Create controller for GET request to '/ontime/poll'
|
// Create controller for GET request to '/ontime/poll'
|
||||||
// Returns data for current state
|
// Returns data for current state
|
||||||
export const poll = async (req, res) => {
|
export const poll = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const s = runtimeState.poll();
|
const s = eventStore.poll();
|
||||||
res.status(200).send(s);
|
res.status(200).send(s);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).send({
|
res.status(500).send({
|
||||||
@@ -225,7 +225,7 @@ export const postSettings = async (req, res) => {
|
|||||||
* @method GET
|
* @method GET
|
||||||
*/
|
*/
|
||||||
export const getViewSettings = async (req, res) => {
|
export const getViewSettings = async (req, res) => {
|
||||||
const views = DataProvider.getViews();
|
const views = DataProvider.getViewSettings();
|
||||||
res.status(200).send(views);
|
res.status(200).send(views);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ export const postViewSettings = async (req, res) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const newData = { overrideStyles: req.body.overrideStyles };
|
const newData = { overrideStyles: req.body.overrideStyles };
|
||||||
await DataProvider.setViews(newData);
|
await DataProvider.setViewSettings(newData);
|
||||||
res.status(200).send(newData);
|
res.status(200).send(newData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(400).send(error);
|
res.status(400).send(error);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
deleteEvent,
|
deleteEvent,
|
||||||
editEvent,
|
editEvent,
|
||||||
reorderEvent,
|
reorderEvent,
|
||||||
} from '../services/RundownService.js';
|
} from '../services/RundownService.ts';
|
||||||
|
|
||||||
// Create controller for GET request to '/eventlist'
|
// Create controller for GET request to '/eventlist'
|
||||||
// Returns -
|
// Returns -
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import { startDb, startIntegrations, startOSCServer, startServer } from './app.j
|
|||||||
async function startOntime() {
|
async function startOntime() {
|
||||||
try {
|
try {
|
||||||
await startDb();
|
await startDb();
|
||||||
|
await startServer();
|
||||||
const loaded = await startServer();
|
|
||||||
console.log(loaded);
|
|
||||||
|
|
||||||
await startOSCServer();
|
await startOSCServer();
|
||||||
await startIntegrations();
|
await startIntegrations();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { DatabaseModel } from 'ontime-types';
|
|||||||
|
|
||||||
export const dbModel: DatabaseModel = {
|
export const dbModel: DatabaseModel = {
|
||||||
rundown: [],
|
rundown: [],
|
||||||
event: {
|
eventData: {
|
||||||
title: '',
|
title: '',
|
||||||
publicUrl: '',
|
publicUrl: '',
|
||||||
publicInfo: '',
|
publicInfo: '',
|
||||||
@@ -18,7 +18,7 @@ export const dbModel: DatabaseModel = {
|
|||||||
pinCode: null,
|
pinCode: null,
|
||||||
timeFormat: '24',
|
timeFormat: '24',
|
||||||
},
|
},
|
||||||
views: {
|
viewSettings: {
|
||||||
overrideStyles: false,
|
overrideStyles: false,
|
||||||
},
|
},
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import express from 'express';
|
|||||||
export const router = express.Router();
|
export const router = express.Router();
|
||||||
|
|
||||||
// import event controller
|
// import event controller
|
||||||
import { getEvent, postEvent } from '../controllers/eventController.js';
|
import { getEvent, postEvent } from '../controllers/eventDataController.js';
|
||||||
import { eventSanitizer } from '../controllers/eventController.validate.js';
|
import { eventSanitizer } from '../controllers/eventDataController.validate.js';
|
||||||
|
|
||||||
// create route between controller and 'GET /event' endpoint
|
// create route between controller and 'GET /event' endpoint
|
||||||
router.get('/', getEvent);
|
router.get('/', getEvent);
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
import { socketProvider } from '../classes/socket/SocketController.js';
|
import { socketProvider } from '../classes/socket/SocketController.js';
|
||||||
import { eventLoader, EventLoader } from '../classes/event-loader/EventLoader.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
|
* Service manages playback status of app
|
||||||
@@ -26,7 +27,7 @@ export class PlaybackService {
|
|||||||
eventTimer.load(event);
|
eventTimer.load(event);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
socketProvider.broadcastState();
|
eventStore.broadcast();
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +124,6 @@ export class PlaybackService {
|
|||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
socketProvider.broadcastState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,7 +135,6 @@ export class PlaybackService {
|
|||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
socketProvider.broadcastState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,7 +147,6 @@ export class PlaybackService {
|
|||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
socketProvider.broadcastState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,7 +156,6 @@ export class PlaybackService {
|
|||||||
if (eventLoader.selectedEventId) {
|
if (eventLoader.selectedEventId) {
|
||||||
this.loadById(eventLoader.selectedEventId);
|
this.loadById(eventLoader.selectedEventId);
|
||||||
}
|
}
|
||||||
socketProvider.broadcastState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,7 +183,6 @@ export class PlaybackService {
|
|||||||
|
|
||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
socketProvider.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
||||||
socketProvider.broadcastState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +196,5 @@ export class PlaybackService {
|
|||||||
eventTimer.delay(delayInMs);
|
eventTimer.delay(delayInMs);
|
||||||
socketProvider.info('PLAYBACK', `Added ${delayTime} min delay`);
|
socketProvider.info('PLAYBACK', `Added ${delayTime} min delay`);
|
||||||
}
|
}
|
||||||
socketProvider.broadcastState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-24
@@ -1,21 +1,16 @@
|
|||||||
|
import { OntimeBaseEvent, OntimeBlock, OntimeDelay, OntimeEvent } from 'ontime-types';
|
||||||
import { generateId } from 'ontime-utils';
|
import { generateId } from 'ontime-utils';
|
||||||
import { DataProvider } from '../classes/data-provider/DataProvider.ts';
|
import { DataProvider } from '../classes/data-provider/DataProvider.js';
|
||||||
import {
|
import { block as blockDef, delay as delayDef, event as eventDef } from '../models/eventsDefinition.js';
|
||||||
block as blockDef,
|
|
||||||
delay as delayDef,
|
|
||||||
event as eventDef,
|
|
||||||
} from '../models/eventsDefinition.js';
|
|
||||||
import { MAX_EVENTS } from '../settings.js';
|
import { MAX_EVENTS } from '../settings.js';
|
||||||
import { EventLoader, eventLoader } from '../classes/event-loader/EventLoader.js';
|
import { EventLoader, eventLoader } from '../classes/event-loader/EventLoader.js';
|
||||||
import { eventTimer } from './TimerService.ts';
|
import { eventTimer } from './TimerService.js';
|
||||||
import { socketProvider } from '../classes/socket/SocketController.js';
|
import { eventStore } from '../stores/EventStore.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Checks if a list of IDs is in the current selection
|
||||||
* @param affectedIds
|
|
||||||
* @returns boolean
|
|
||||||
*/
|
*/
|
||||||
const affectedLoaded = (affectedIds) => {
|
const affectedLoaded = (affectedIds: string[]) => {
|
||||||
const now = eventLoader.selectedEventId;
|
const now = eventLoader.selectedEventId;
|
||||||
const nowPublic = eventLoader.selectedPublicEventId;
|
const nowPublic = eventLoader.selectedPublicEventId;
|
||||||
const next = eventLoader.nextEventId;
|
const next = eventLoader.nextEventId;
|
||||||
@@ -28,6 +23,9 @@ const affectedLoaded = (affectedIds) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if timer replaces the loaded next
|
||||||
|
*/
|
||||||
const isNewNext = () => {
|
const isNewNext = () => {
|
||||||
const timedEvents = EventLoader.getTimedEvents();
|
const timedEvents = EventLoader.getTimedEvents();
|
||||||
const now = eventLoader.selectedEventId;
|
const now = eventLoader.selectedEventId;
|
||||||
@@ -66,10 +64,9 @@ const isNewNext = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* updates timer object
|
* Updates timer object
|
||||||
* @param {array} [affectedIds]
|
|
||||||
*/
|
*/
|
||||||
export function updateTimer(affectedIds) {
|
export function updateTimer(affectedIds?: string[]) {
|
||||||
const runningEventId = eventLoader.selectedEventId;
|
const runningEventId = eventLoader.selectedEventId;
|
||||||
|
|
||||||
if (runningEventId === null) {
|
if (runningEventId === null) {
|
||||||
@@ -121,18 +118,18 @@ export async function addEvent(eventData) {
|
|||||||
throw new Error(`ERROR: Reached limit number of ${MAX_EVENTS} events`);
|
throw new Error(`ERROR: Reached limit number of ${MAX_EVENTS} events`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let newEvent = {};
|
let newEvent: Partial<OntimeBaseEvent> = {};
|
||||||
const id = generateId();
|
const id = generateId();
|
||||||
|
|
||||||
switch (eventData.type) {
|
switch (eventData.type) {
|
||||||
case 'event':
|
case 'event':
|
||||||
newEvent = { ...eventDef, ...eventData, id };
|
newEvent = { ...eventDef, ...eventData, id } as Partial<OntimeEvent>;
|
||||||
break;
|
break;
|
||||||
case 'delay':
|
case 'delay':
|
||||||
newEvent = { ...delayDef, ...eventData, id };
|
newEvent = { ...delayDef, ...eventData, id } as Partial<OntimeDelay>;
|
||||||
break;
|
break;
|
||||||
case 'block':
|
case 'block':
|
||||||
newEvent = { ...blockDef, ...eventData, id };
|
newEvent = { ...blockDef, ...eventData, id } as Partial<OntimeBlock>;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +145,7 @@ export async function addEvent(eventData) {
|
|||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
updateTimer([id]);
|
updateTimer([id]);
|
||||||
socketProvider.broadcastState();
|
eventStore.broadcast();
|
||||||
return newEvent;
|
return newEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +157,7 @@ export async function editEvent(eventData) {
|
|||||||
}
|
}
|
||||||
const newEvent = await DataProvider.updateEventById(eventId, eventData);
|
const newEvent = await DataProvider.updateEventById(eventId, eventData);
|
||||||
updateTimer([eventId]);
|
updateTimer([eventId]);
|
||||||
socketProvider.broadcastState();
|
eventStore.broadcast();
|
||||||
return newEvent;
|
return newEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +169,7 @@ export async function editEvent(eventData) {
|
|||||||
export async function deleteEvent(eventId) {
|
export async function deleteEvent(eventId) {
|
||||||
await DataProvider.deleteEvent(eventId);
|
await DataProvider.deleteEvent(eventId);
|
||||||
updateTimer([eventId]);
|
updateTimer([eventId]);
|
||||||
socketProvider.broadcastState();
|
eventStore.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -182,7 +179,7 @@ export async function deleteEvent(eventId) {
|
|||||||
export async function deleteAllEvents() {
|
export async function deleteAllEvents() {
|
||||||
await DataProvider.clearRundown();
|
await DataProvider.clearRundown();
|
||||||
updateTimer();
|
updateTimer();
|
||||||
socketProvider.broadcastState();
|
eventStore.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,5 +260,5 @@ export async function applyDelay(eventId) {
|
|||||||
// update rundown
|
// update rundown
|
||||||
await DataProvider.setRundown(rundown);
|
await DataProvider.setRundown(rundown);
|
||||||
updateTimer();
|
updateTimer();
|
||||||
socketProvider.broadcastState();
|
eventStore.broadcast();
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { TimerLifeCycle } from 'ontime-types';
|
import { TimerLifeCycle } from 'ontime-types';
|
||||||
|
|
||||||
import { runtimeState } from '../stores/EventStore.js';
|
import { eventStore } from '../stores/EventStore.js';
|
||||||
import { PlaybackService } from './PlaybackService.js';
|
import { PlaybackService } from './PlaybackService.js';
|
||||||
import { updateRoll } from './rollUtils.js';
|
import { updateRoll } from './rollUtils.js';
|
||||||
import { DAY_TO_MS } from '../utils/time.js';
|
import { DAY_TO_MS } from '../utils/time.js';
|
||||||
@@ -9,9 +9,9 @@ import { integrationService } from './integration-service/IntegrationService.js'
|
|||||||
export class TimerService {
|
export class TimerService {
|
||||||
private readonly _interval: NodeJS.Timer;
|
private readonly _interval: NodeJS.Timer;
|
||||||
|
|
||||||
private playback: string;
|
playback: string;
|
||||||
|
|
||||||
private loadedTimerId: null;
|
loadedTimerId: null;
|
||||||
private _pausedInterval: number;
|
private _pausedInterval: number;
|
||||||
private _pausedAt: number | null;
|
private _pausedAt: number | null;
|
||||||
private _secondaryTarget: number | null;
|
private _secondaryTarget: number | null;
|
||||||
@@ -163,8 +163,8 @@ export class TimerService {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onLoad() {
|
_onLoad() {
|
||||||
runtimeState.set('playback', this.playback);
|
eventStore.set('playback', this.playback);
|
||||||
runtimeState.set('ontime-timer', this.timer);
|
eventStore.set('timer', this.timer);
|
||||||
integrationService.dispatch(TimerLifeCycle.onLoad);
|
integrationService.dispatch(TimerLifeCycle.onLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,8 +198,8 @@ export class TimerService {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onStart() {
|
_onStart() {
|
||||||
runtimeState.set('playback', this.playback);
|
eventStore.set('playback', this.playback);
|
||||||
runtimeState.set('ontime-timer', this.timer);
|
eventStore.set('timer', this.timer);
|
||||||
integrationService.dispatch(TimerLifeCycle.onStart);
|
integrationService.dispatch(TimerLifeCycle.onStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,8 +215,8 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onPause() {
|
_onPause() {
|
||||||
runtimeState.set('playback', this.playback);
|
eventStore.set('playback', this.playback);
|
||||||
runtimeState.set('ontime-timer', this.timer);
|
eventStore.set('timer', this.timer);
|
||||||
integrationService.dispatch(TimerLifeCycle.onPause);
|
integrationService.dispatch(TimerLifeCycle.onPause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +230,8 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onStop() {
|
_onStop() {
|
||||||
runtimeState.set('playback', this.playback);
|
eventStore.set('playback', this.playback);
|
||||||
runtimeState.set('ontime-timer', this.timer);
|
eventStore.set('timer', this.timer);
|
||||||
integrationService.dispatch(TimerLifeCycle.onStop);
|
integrationService.dispatch(TimerLifeCycle.onStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,14 +318,14 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onUpdate() {
|
_onUpdate() {
|
||||||
runtimeState.set('playback', this.playback);
|
eventStore.set('playback', this.playback);
|
||||||
runtimeState.set('ontime-timer', this.timer);
|
eventStore.set('timer', this.timer);
|
||||||
integrationService.dispatch(TimerLifeCycle.onUpdate);
|
integrationService.dispatch(TimerLifeCycle.onUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onFinish() {
|
_onFinish() {
|
||||||
runtimeState.set('playback', this.playback);
|
eventStore.set('playback', this.playback);
|
||||||
runtimeState.set('ontime-timer', this.timer);
|
eventStore.set('timer', this.timer);
|
||||||
integrationService.dispatch(TimerLifeCycle.onFinish);
|
integrationService.dispatch(TimerLifeCycle.onFinish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import IIntegration, { TimerLifeCycleKey } from './IIntegration.js';
|
import IIntegration, { TimerLifeCycleKey } from './IIntegration.js';
|
||||||
import { runtimeState } from '../../stores/EventStore.js';
|
import { eventStore } from '../../stores/EventStore.js';
|
||||||
|
|
||||||
class IntegrationService {
|
class IntegrationService {
|
||||||
private integrations: IIntegration[];
|
private integrations: IIntegration[];
|
||||||
@@ -17,7 +17,7 @@ class IntegrationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatch(action: TimerLifeCycleKey) {
|
dispatch(action: TimerLifeCycleKey) {
|
||||||
const state = runtimeState.poll();
|
const state = eventStore.poll();
|
||||||
this.integrations.forEach((integration) => {
|
this.integrations.forEach((integration) => {
|
||||||
integration.dispatch(action, state);
|
integration.dispatch(action, state);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Utility variable: 24 hour in milliseconds .
|
* Utility variable: 24 hour in milliseconds .
|
||||||
* @type {number}
|
|
||||||
*/
|
*/
|
||||||
export const DAY_TO_MS = 86400000;
|
export const DAY_TO_MS = 86400000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description handle events that span over midnight
|
* 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
|
|
||||||
*/
|
*/
|
||||||
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
|
* @description Sorts an array of objects by given property
|
||||||
@@ -45,15 +41,15 @@ export const replacePlaceholder = (str, values) => {
|
|||||||
* @param timeNow
|
* @param timeNow
|
||||||
* @returns {{}}
|
* @returns {{}}
|
||||||
*/
|
*/
|
||||||
export const getRollTimers = (rundown, timeNow) => {
|
export const getRollTimers = (rundown, timeNow: number) => {
|
||||||
let nowIndex = null; // index of event now
|
let nowIndex: number | null = null; // index of event now
|
||||||
let nowId = null; // id of event now
|
let nowId: string | null = null; // id of event now
|
||||||
let publicIndex = null; // index of public event now
|
let publicIndex: string | null = null; // index of public event now
|
||||||
let publicTime = -1;
|
let publicTime = -1;
|
||||||
let nextIndex = null; // index of next event
|
let nextIndex: number | null = null; // index of next event
|
||||||
let publicNextIndex = null; // index of next public event
|
let publicNextIndex: number | null = null; // index of next public event
|
||||||
let timeToNext = null; // counter: time for next event
|
let timeToNext: number | null = null; // counter: time for next event
|
||||||
let publicTimeToNext = null; // counter: time for next public event
|
let publicTimeToNext: number | null = null; // counter: time for next public event
|
||||||
let timers = null;
|
let timers = null;
|
||||||
|
|
||||||
// Order events by startTime
|
// Order events by startTime
|
||||||
@@ -171,8 +167,7 @@ export const getRollTimers = (rundown, timeNow) => {
|
|||||||
* @returns {object} object with selection variables
|
* @returns {object} object with selection variables
|
||||||
*/
|
*/
|
||||||
export const updateRoll = (currentTimers) => {
|
export const updateRoll = (currentTimers) => {
|
||||||
const { selectedEventId, current, _finishAt, clock, secondaryTimer, _secondaryTarget } =
|
const { selectedEventId, current, _finishAt, clock, secondaryTimer, _secondaryTarget } = currentTimers;
|
||||||
currentTimers;
|
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
let updatedTimer = current;
|
let updatedTimer = current;
|
||||||
@@ -5,7 +5,7 @@ const store = {};
|
|||||||
/**
|
/**
|
||||||
* A runtime store that broadcasts its payload
|
* A runtime store that broadcasts its payload
|
||||||
*/
|
*/
|
||||||
export const runtimeState = {
|
export const eventStore = {
|
||||||
get(key) {
|
get(key) {
|
||||||
return store[key];
|
return store[key];
|
||||||
},
|
},
|
||||||
@@ -16,4 +16,8 @@ export const runtimeState = {
|
|||||||
poll() {
|
poll() {
|
||||||
return store;
|
return store;
|
||||||
},
|
},
|
||||||
|
broadcast() {
|
||||||
|
socketProvider.send(store);
|
||||||
|
socketProvider.broadcastState();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { vi } from 'vitest';
|
|||||||
import { dbModel } from '../../models/dataModel.js';
|
import { dbModel } from '../../models/dataModel.js';
|
||||||
import { parseExcel, parseJson, validateEvent } from '../parser.js';
|
import { parseExcel, parseJson, validateEvent } from '../parser.js';
|
||||||
import { makeString, validateDuration } from '../parserUtils.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', () => {
|
describe('test json parser with valid def', () => {
|
||||||
const testData = {
|
const testData = {
|
||||||
@@ -829,7 +829,7 @@ describe('test views import', () => {
|
|||||||
overrideStyles: true,
|
overrideStyles: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const parsed = parseViews(testData);
|
const parsed = parseViewSettings(testData);
|
||||||
expect(parsed).toStrictEqual(testData.views);
|
expect(parsed).toStrictEqual(testData.views);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -841,7 +841,7 @@ describe('test views import', () => {
|
|||||||
version: 2,
|
version: 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const parsed = parseViews(testData, true);
|
const parsed = parseViewSettings(testData, true);
|
||||||
expect(parsed).toStrictEqual(dbModel.views);
|
expect(parsed).toStrictEqual(dbModel.views);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import { dbModel } from '../models/dataModel.js';
|
|||||||
import { deleteFile, makeString, validateDuration } from './parserUtils.js';
|
import { deleteFile, makeString, validateDuration } from './parserUtils.js';
|
||||||
import {
|
import {
|
||||||
parseAliases,
|
parseAliases,
|
||||||
parseEvent,
|
parseEventData,
|
||||||
parseHttp,
|
parseHttp,
|
||||||
parseOsc,
|
parseOsc,
|
||||||
parseRundown,
|
parseRundown,
|
||||||
parseSettings,
|
parseSettings,
|
||||||
parseUserFields,
|
parseUserFields,
|
||||||
parseViews,
|
parseViewSettings,
|
||||||
} from './parserFunctions.js';
|
} from './parserFunctions.js';
|
||||||
import { parseExcelDate } from './time.js';
|
import { parseExcelDate } from './time.js';
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ export const parseExcel = async (excelData) => {
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
rundown,
|
rundown,
|
||||||
event: eventData,
|
eventData: eventData,
|
||||||
settings: {
|
settings: {
|
||||||
app: 'ontime',
|
app: 'ontime',
|
||||||
version: 2,
|
version: 2,
|
||||||
@@ -265,11 +265,11 @@ export const parseJson = async (jsonData, enforce = false) => {
|
|||||||
// parse Events
|
// parse Events
|
||||||
returnData.rundown = parseRundown(jsonData);
|
returnData.rundown = parseRundown(jsonData);
|
||||||
// parse Event
|
// parse Event
|
||||||
returnData.event = parseEvent(jsonData, enforce);
|
returnData.eventData = parseEventData(jsonData, enforce);
|
||||||
// Settings handled partially
|
// Settings handled partially
|
||||||
returnData.settings = parseSettings(jsonData, enforce);
|
returnData.settings = parseSettings(jsonData, enforce);
|
||||||
// View settings handled partially
|
// View settings handled partially
|
||||||
returnData.views = parseViews(jsonData, enforce);
|
returnData.viewSettings = parseViewSettings(jsonData, enforce);
|
||||||
// Import OSC settings if any
|
// Import OSC settings if any
|
||||||
returnData.osc = parseOsc(jsonData, enforce);
|
returnData.osc = parseOsc(jsonData, enforce);
|
||||||
// Import HTTP settings if any
|
// Import HTTP settings if any
|
||||||
@@ -358,7 +358,7 @@ export const fileHandler = async (file) => {
|
|||||||
const dataFromExcel = await parseExcel(excelData.data);
|
const dataFromExcel = await parseExcel(excelData.data);
|
||||||
res.data = {};
|
res.data = {};
|
||||||
res.data.rundown = parseRundown(dataFromExcel);
|
res.data.rundown = parseRundown(dataFromExcel);
|
||||||
res.data.event = parseEvent(dataFromExcel, true);
|
res.data.eventData = parseEventData(dataFromExcel, true);
|
||||||
res.data.userFields = parseUserFields(dataFromExcel);
|
res.data.userFields = parseUserFields(dataFromExcel);
|
||||||
res.message = 'success';
|
res.message = 'success';
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -64,26 +64,26 @@ export const parseRundown = (data) => {
|
|||||||
* @param {boolean} enforce - whether to create a definition if one is missing
|
* @param {boolean} enforce - whether to create a definition if one is missing
|
||||||
* @returns {object} - event object data
|
* @returns {object} - event object data
|
||||||
*/
|
*/
|
||||||
export const parseEvent = (data, enforce) => {
|
export const parseEventData = (data, enforce) => {
|
||||||
let newEvent = {};
|
let newEventData = {};
|
||||||
if ('event' in data) {
|
if ('eventData' in data) {
|
||||||
console.log('Found event data, importing...');
|
console.log('Found event data, importing...');
|
||||||
const e = data.event;
|
const e = data.eventData;
|
||||||
// filter known properties and write to db
|
// filter known properties and write to db
|
||||||
newEvent = {
|
newEventData = {
|
||||||
...dbModel.event,
|
...dbModel.eventData,
|
||||||
title: e.title || dbModel.event.title,
|
title: e.title || dbModel.eventData.title,
|
||||||
publicUrl: e.publicUrl || dbModel.event.publicUrl,
|
publicUrl: e.publicUrl || dbModel.eventData.publicUrl,
|
||||||
publicInfo: e.publicInfo || dbModel.event.publicInfo,
|
publicInfo: e.publicInfo || dbModel.eventData.publicInfo,
|
||||||
backstageUrl: e.backstageUrl || dbModel.event.backstageUrl,
|
backstageUrl: e.backstageUrl || dbModel.eventData.backstageUrl,
|
||||||
backstageInfo: e.backstageInfo || dbModel.event.backstageInfo,
|
backstageInfo: e.backstageInfo || dbModel.eventData.backstageInfo,
|
||||||
endMessage: e.endMessage || dbModel.event.endMessage,
|
endMessage: e.endMessage || dbModel.eventData.endMessage,
|
||||||
};
|
};
|
||||||
} else if (enforce) {
|
} else if (enforce) {
|
||||||
newEvent = { ...dbModel.event };
|
newEventData = { ...dbModel.eventData };
|
||||||
console.log(`Created event object in db`);
|
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
|
* @param {boolean} enforce - whether to create a definition if one is missing
|
||||||
* @returns {object} - event object data
|
* @returns {object} - event object data
|
||||||
*/
|
*/
|
||||||
export const parseViews = (data, enforce) => {
|
export const parseViewSettings = (data, enforce) => {
|
||||||
let newViews = {};
|
let newViews = {};
|
||||||
if ('views' in data) {
|
if ('viewSettings' in data) {
|
||||||
console.log('Found view definition, importing...');
|
console.log('Found view definition, importing...');
|
||||||
const v = data.views;
|
const v = data.viewSettings;
|
||||||
|
|
||||||
const viewSettings = {
|
const viewSettings = {
|
||||||
overrideStyles: v.overrideStyles ?? dbModel.views.overrideStyles,
|
overrideStyles: v.overrideStyles ?? dbModel.viewSettings.overrideStyles,
|
||||||
};
|
};
|
||||||
|
|
||||||
// write to db
|
// write to db
|
||||||
@@ -142,8 +142,8 @@ export const parseViews = (data, enforce) => {
|
|||||||
...viewSettings,
|
...viewSettings,
|
||||||
};
|
};
|
||||||
} else if (enforce) {
|
} else if (enforce) {
|
||||||
newViews = dbModel.views;
|
newViews = dbModel.viewSettings;
|
||||||
console.log(`Created view object in db`);
|
console.log(`Created viewSettings object in db`);
|
||||||
}
|
}
|
||||||
return newViews;
|
return newViews;
|
||||||
};
|
};
|
||||||
|
|||||||
+160
-12
@@ -7,9 +7,23 @@
|
|||||||
"note": "Maybe a running note for the operator?",
|
"note": "Maybe a running note for the operator?",
|
||||||
"timeStart": 28800000,
|
"timeStart": 28800000,
|
||||||
"timeEnd": 30600000,
|
"timeEnd": 30600000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 1800000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 7,
|
"revision": 0,
|
||||||
"id": "5946"
|
"id": "5946"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -19,9 +33,23 @@
|
|||||||
"note": "",
|
"note": "",
|
||||||
"timeStart": 30600000,
|
"timeStart": 30600000,
|
||||||
"timeEnd": 34200000,
|
"timeEnd": 34200000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 3600000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 4,
|
"revision": 0,
|
||||||
"id": "c2e7"
|
"id": "c2e7"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -31,9 +59,23 @@
|
|||||||
"note": "",
|
"note": "",
|
||||||
"timeStart": 34200000,
|
"timeStart": 34200000,
|
||||||
"timeEnd": 34800000,
|
"timeEnd": 34800000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 600000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 4,
|
"revision": 0,
|
||||||
"id": "cc0f"
|
"id": "cc0f"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -43,9 +85,23 @@
|
|||||||
"note": "In green, below",
|
"note": "In green, below",
|
||||||
"timeStart": 34800000,
|
"timeStart": 34800000,
|
||||||
"timeEnd": 35400000,
|
"timeEnd": 35400000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 600000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 7,
|
"revision": 0,
|
||||||
"id": "8ee5"
|
"id": "8ee5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -55,15 +111,29 @@
|
|||||||
"note": "",
|
"note": "",
|
||||||
"timeStart": 0,
|
"timeStart": 0,
|
||||||
"timeEnd": 600000,
|
"timeEnd": 600000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 600000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 2,
|
"revision": 0,
|
||||||
"id": "8222"
|
"id": "8222"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"duration": 900000,
|
"duration": 900000,
|
||||||
"type": "delay",
|
"type": "delay",
|
||||||
"revision": 1,
|
"revision": 0,
|
||||||
"id": "a386"
|
"id": "a386"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -73,9 +143,23 @@
|
|||||||
"note": "* Until a block is found",
|
"note": "* Until a block is found",
|
||||||
"timeStart": 35400000,
|
"timeStart": 35400000,
|
||||||
"timeEnd": 36600000,
|
"timeEnd": 36600000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 1200000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 6,
|
"revision": 0,
|
||||||
"id": "6dce"
|
"id": "6dce"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -85,9 +169,23 @@
|
|||||||
"note": "Orange and red buttons on the right",
|
"note": "Orange and red buttons on the right",
|
||||||
"timeStart": 36600000,
|
"timeStart": 36600000,
|
||||||
"timeEnd": 43200000,
|
"timeEnd": 43200000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 6600000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 9,
|
"revision": 0,
|
||||||
"id": "2651"
|
"id": "2651"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -101,13 +199,27 @@
|
|||||||
"note": "Blue button on the right",
|
"note": "Blue button on the right",
|
||||||
"timeStart": 46800000,
|
"timeStart": 46800000,
|
||||||
"timeEnd": 57600000,
|
"timeEnd": 57600000,
|
||||||
|
"timeType": "start-end",
|
||||||
|
"duration": 10800000,
|
||||||
"isPublic": false,
|
"isPublic": false,
|
||||||
|
"skip": false,
|
||||||
|
"colour": "",
|
||||||
|
"user0": "",
|
||||||
|
"user1": "",
|
||||||
|
"user2": "",
|
||||||
|
"user3": "",
|
||||||
|
"user4": "",
|
||||||
|
"user5": "",
|
||||||
|
"user6": "",
|
||||||
|
"user7": "",
|
||||||
|
"user8": "",
|
||||||
|
"user9": "",
|
||||||
"type": "event",
|
"type": "event",
|
||||||
"revision": 6,
|
"revision": 0,
|
||||||
"id": "1358"
|
"id": "1358"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"event": {
|
"eventData": {
|
||||||
"title": "All about Carlos demo event",
|
"title": "All about Carlos demo event",
|
||||||
"publicUrl": "www.getontime.no",
|
"publicUrl": "www.getontime.no",
|
||||||
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
|
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
|
||||||
@@ -117,17 +229,53 @@
|
|||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"app": "ontime",
|
"app": "ontime",
|
||||||
"version": 2,
|
"version": 1,
|
||||||
"serverPort": 4001,
|
"serverPort": 4001,
|
||||||
"lock": null,
|
"lock": null,
|
||||||
"pinCode": "1234"
|
"pinCode": "1234"
|
||||||
},
|
},
|
||||||
|
"viewSettings": {
|
||||||
|
"overrideStyles": false
|
||||||
|
},
|
||||||
"osc": {
|
"osc": {
|
||||||
"port": 8888,
|
"port": 8888,
|
||||||
"portOut": 9999,
|
"portOut": 9999,
|
||||||
"targetIP": "127.0.0.1",
|
"targetIP": "127.0.0.1",
|
||||||
"enabled": true
|
"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": [
|
"aliases": [
|
||||||
{
|
{
|
||||||
"id": "0b0b3",
|
"id": "0b0b3",
|
||||||
@@ -148,4 +296,4 @@
|
|||||||
"user8": "user8",
|
"user8": "user8",
|
||||||
"user9": "user9"
|
"user9": "user9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"events": [
|
"rundown": [
|
||||||
{
|
{
|
||||||
"title": "Welcome to Ontime",
|
"title": "Welcome to Ontime",
|
||||||
"subtitle": "Subtitles are useful",
|
"subtitle": "Subtitles are useful",
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
"id": "1358"
|
"id": "1358"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"event": {
|
"eventData": {
|
||||||
"title": "All about Carlos demo event",
|
"title": "All about Carlos demo event",
|
||||||
"publicUrl": "www.getontime.no",
|
"publicUrl": "www.getontime.no",
|
||||||
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
|
"publicInfo": "WiFi: demoproject \nPassword: ontimeproject",
|
||||||
@@ -234,7 +234,7 @@
|
|||||||
"lock": null,
|
"lock": null,
|
||||||
"pinCode": "1234"
|
"pinCode": "1234"
|
||||||
},
|
},
|
||||||
"views": {
|
"viewSettings": {
|
||||||
"overrideStyles": false
|
"overrideStyles": false
|
||||||
},
|
},
|
||||||
"osc": {
|
"osc": {
|
||||||
|
|||||||
@@ -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 { 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 = {
|
export type DatabaseModel = {
|
||||||
rundown: any;
|
rundown: OntimeRundown;
|
||||||
event: any;
|
eventData: EventData;
|
||||||
settings: any;
|
settings: Settings;
|
||||||
views: any;
|
viewSettings: ViewSettings;
|
||||||
aliases: any;
|
aliases: Alias[];
|
||||||
userFields: any;
|
userFields: UserFields;
|
||||||
osc: OSCSettings;
|
osc: OSCSettings;
|
||||||
http: any;
|
http: any;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
enum TimerTypeType {
|
export enum TimerTypeType {
|
||||||
CountDown = 'count-down',
|
CountDown = 'count-down',
|
||||||
CountUp = 'count-up',
|
CountUp = 'count-up',
|
||||||
Clock = 'clock'
|
Clock = 'clock'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TimerTypeType
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export type Alias = {
|
||||||
|
enabled: boolean;
|
||||||
|
alias: string;
|
||||||
|
pathAndParams: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export type EventData = {
|
||||||
|
title: string;
|
||||||
|
publicUrl: string;
|
||||||
|
publicInfo: string;
|
||||||
|
backstageUrl: string;
|
||||||
|
backstageInfo: string;
|
||||||
|
endMessage: string;
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { OntimeBlock, OntimeDelay, OntimeEvent } from './OntimeEvent.type';
|
||||||
|
|
||||||
|
export type OntimeRundownEntry = OntimeDelay | OntimeBlock | OntimeEvent;
|
||||||
|
export type OntimeRundown = OntimeRundownEntry[];
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export type TimeFormat = '12' | '24';
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export type ViewSettings = {
|
||||||
|
overrideStyles: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export type Message = {
|
||||||
|
text: string;
|
||||||
|
visible: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MessageControl = {
|
||||||
|
presenter: Message;
|
||||||
|
public: Message;
|
||||||
|
lower: Message;
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user