mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-22 07:29:08 +00:00
refactor: rename external message to secondary message
This commit is contained in:
committed by
Carlos Valente
parent
0aeec12ccd
commit
3cd6cd2f55
@@ -32,8 +32,8 @@ export const useTimerMessageInput = createSelector((state: RuntimeStore) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
export const useExternalMessageInput = createSelector((state: RuntimeStore) => ({
|
export const useExternalMessageInput = createSelector((state: RuntimeStore) => ({
|
||||||
text: state.message.external,
|
text: state.message.secondary,
|
||||||
visible: state.message.timer.secondarySource === 'external',
|
visible: state.message.timer.secondarySource === 'secondary',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useMessagePreview = createSelector((state: RuntimeStore) => ({
|
export const useMessagePreview = createSelector((state: RuntimeStore) => ({
|
||||||
@@ -41,7 +41,7 @@ export const useMessagePreview = createSelector((state: RuntimeStore) => ({
|
|||||||
blackout: state.message.timer.blackout,
|
blackout: state.message.timer.blackout,
|
||||||
phase: state.timer.phase,
|
phase: state.timer.phase,
|
||||||
showAuxTimer: state.message.timer.secondarySource === 'aux',
|
showAuxTimer: state.message.timer.secondarySource === 'aux',
|
||||||
showExternalMessage: state.message.timer.secondarySource === 'external' && Boolean(state.message.external),
|
showSecondaryMessage: state.message.timer.secondarySource === 'secondary' && Boolean(state.message.secondary),
|
||||||
showTimerMessage: state.message.timer.visible && Boolean(state.message.timer.text),
|
showTimerMessage: state.message.timer.visible && Boolean(state.message.timer.text),
|
||||||
timerType: state.eventNow?.timerType ?? null,
|
timerType: state.eventNow?.timerType ?? null,
|
||||||
countToEnd: state.eventNow?.countToEnd ?? false,
|
countToEnd: state.eventNow?.countToEnd ?? false,
|
||||||
@@ -50,7 +50,7 @@ export const useMessagePreview = createSelector((state: RuntimeStore) => ({
|
|||||||
export const setMessage = {
|
export const setMessage = {
|
||||||
timerText: (payload: string) => sendSocket('message', { timer: { text: payload } }),
|
timerText: (payload: string) => sendSocket('message', { timer: { text: payload } }),
|
||||||
timerVisible: (payload: boolean) => sendSocket('message', { timer: { visible: payload } }),
|
timerVisible: (payload: boolean) => sendSocket('message', { timer: { visible: payload } }),
|
||||||
externalText: (payload: string) => sendSocket('message', { external: payload }),
|
secondaryMessage: (payload: string) => sendSocket('message', { secondary: payload }),
|
||||||
timerBlink: (payload: boolean) => sendSocket('message', { timer: { blink: payload } }),
|
timerBlink: (payload: boolean) => sendSocket('message', { timer: { blink: payload } }),
|
||||||
timerBlackout: (payload: boolean) => sendSocket('message', { timer: { blackout: payload } }),
|
timerBlackout: (payload: boolean) => sendSocket('message', { timer: { blackout: payload } }),
|
||||||
timerSecondary: (payload: TimerMessage['secondarySource']) =>
|
timerSecondary: (payload: TimerMessage['secondarySource']) =>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { IoEye, IoEyeOffOutline } from 'react-icons/io5';
|
import { IoEye, IoEyeOffOutline } from 'react-icons/io5';
|
||||||
|
|
||||||
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
||||||
import { setMessage, useExternalMessageInput, useTimerMessageInput } from '../../../common/hooks/useSocket';
|
import { setMessage, useExternalMessageInput as useSecondaryMessageInput, useTimerMessageInput } from '../../../common/hooks/useSocket';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import InputRow from './InputRow';
|
import InputRow from './InputRow';
|
||||||
@@ -12,7 +12,7 @@ export default function MessageControl() {
|
|||||||
<>
|
<>
|
||||||
<TimerControlsPreview />
|
<TimerControlsPreview />
|
||||||
<TimerMessageInput />
|
<TimerMessageInput />
|
||||||
<ExternalInput />
|
<SecondaryInput />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -41,29 +41,29 @@ function TimerMessageInput() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExternalInput() {
|
function SecondaryInput() {
|
||||||
const { text, visible } = useExternalMessageInput();
|
const { text, visible } = useSecondaryMessageInput();
|
||||||
|
|
||||||
const toggleExternal = () => {
|
const toggleSecondary = () => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
setMessage.timerSecondary(null);
|
setMessage.timerSecondary(null);
|
||||||
} else {
|
} else {
|
||||||
setMessage.timerSecondary('external');
|
setMessage.timerSecondary('secondary');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputRow
|
<InputRow
|
||||||
label='External Message'
|
label='Secondary Message'
|
||||||
placeholder='Message shown as secondary text in stage timer'
|
placeholder='Message shown as secondary text in stage timer'
|
||||||
text={text}
|
text={text}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
changeHandler={(newValue) => setMessage.externalText(newValue)}
|
changeHandler={(newValue) => setMessage.secondaryMessage(newValue)}
|
||||||
>
|
>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
clickHandler={toggleExternal}
|
clickHandler={toggleSecondary}
|
||||||
tooltip={visible ? 'Make invisible' : 'Make visible'}
|
tooltip={visible ? 'Make invisible' : 'Make visible'}
|
||||||
aria-label='Toggle external message visibility'
|
aria-label='Toggle secondary message visibility'
|
||||||
openDelay={tooltipDelayMid}
|
openDelay={tooltipDelayMid}
|
||||||
icon={visible ? <IoEye size='18px' /> : <IoEyeOffOutline size='18px' />}
|
icon={visible ? <IoEye size='18px' /> : <IoEyeOffOutline size='18px' />}
|
||||||
variant={visible ? 'ontime-filled' : 'ontime-subtle'}
|
variant={visible ? 'ontime-filled' : 'ontime-subtle'}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { Corner } from '../../editors/editor-utils/EditorUtils';
|
|||||||
import style from './MessageControl.module.scss';
|
import style from './MessageControl.module.scss';
|
||||||
|
|
||||||
export default function TimerPreview() {
|
export default function TimerPreview() {
|
||||||
const { blink, blackout, countToEnd, phase, showAuxTimer, showExternalMessage, showTimerMessage, timerType } =
|
const { blink, blackout, countToEnd, phase, showAuxTimer, showSecondaryMessage, showTimerMessage, timerType } =
|
||||||
useMessagePreview();
|
useMessagePreview();
|
||||||
const { data } = useViewSettings();
|
const { data } = useViewSettings();
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ export default function TimerPreview() {
|
|||||||
|
|
||||||
// we need to check aux first since it takes priority
|
// we need to check aux first since it takes priority
|
||||||
if (showAuxTimer) return 'Aux Timer';
|
if (showAuxTimer) return 'Aux Timer';
|
||||||
if (showExternalMessage) return 'External message';
|
if (showSecondaryMessage) return 'Secondary message';
|
||||||
return null;
|
return null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Button } from '@chakra-ui/react';
|
import { Button } from '@chakra-ui/react';
|
||||||
|
import { SecondarySource } from 'ontime-types';
|
||||||
|
|
||||||
import { setMessage, useTimerViewControl } from '../../../common/hooks/useSocket';
|
import { setMessage, useTimerViewControl } from '../../../common/hooks/useSocket';
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ import style from './MessageControl.module.scss';
|
|||||||
export default function TimerControlsPreview() {
|
export default function TimerControlsPreview() {
|
||||||
const { blackout, blink, secondarySource } = useTimerViewControl();
|
const { blackout, blink, secondarySource } = useTimerViewControl();
|
||||||
|
|
||||||
const toggleSecondary = (newValue: 'aux' | 'external' | null) => {
|
const toggleSecondary = (newValue: SecondarySource) => {
|
||||||
if (secondarySource === newValue) {
|
if (secondarySource === newValue) {
|
||||||
setMessage.timerSecondary(null);
|
setMessage.timerSecondary(null);
|
||||||
} else {
|
} else {
|
||||||
@@ -31,10 +32,10 @@ export default function TimerControlsPreview() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size='sm'
|
size='sm'
|
||||||
variant={secondarySource === 'external' ? 'ontime-filled' : 'ontime-subtle'}
|
variant={secondarySource === 'secondary' ? 'ontime-filled' : 'ontime-subtle'}
|
||||||
onClick={() => toggleSecondary('external')}
|
onClick={() => toggleSecondary('secondary')}
|
||||||
>
|
>
|
||||||
Show external
|
Show secondary
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<hr className={style.divider} />
|
<hr className={style.divider} />
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default function Timer(props: TimerProps) {
|
|||||||
hideCards,
|
hideCards,
|
||||||
hideProgress,
|
hideProgress,
|
||||||
hideMessage,
|
hideMessage,
|
||||||
hideExternal,
|
hideSecondary,
|
||||||
hideTimerSeconds,
|
hideTimerSeconds,
|
||||||
removeLeadingZeros,
|
removeLeadingZeros,
|
||||||
mainSource,
|
mainSource,
|
||||||
@@ -110,7 +110,7 @@ export default function Timer(props: TimerProps) {
|
|||||||
localisedMinutes,
|
localisedMinutes,
|
||||||
hideTimerSeconds,
|
hideTimerSeconds,
|
||||||
removeLeadingZeros,
|
removeLeadingZeros,
|
||||||
hideExternal,
|
hideSecondary,
|
||||||
);
|
);
|
||||||
|
|
||||||
// gather presentation styles
|
// gather presentation styles
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ export const getTimerOptions = (timeFormat: string, customFields: CustomFields):
|
|||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'hideExternal',
|
id: 'hideSecondary',
|
||||||
title: 'Hide Auxiliary timer / External message',
|
title: 'Hide Auxiliary timer / Secondary message',
|
||||||
description: 'Prevents the screen from displaying the secondary timer field',
|
description: 'Prevents the screen from displaying the secondary timer field',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
@@ -115,7 +115,7 @@ type TimerOptions = {
|
|||||||
hideCards: boolean;
|
hideCards: boolean;
|
||||||
hideProgress: boolean;
|
hideProgress: boolean;
|
||||||
hideMessage: boolean;
|
hideMessage: boolean;
|
||||||
hideExternal: boolean;
|
hideSecondary: boolean;
|
||||||
hideTimerSeconds: boolean;
|
hideTimerSeconds: boolean;
|
||||||
removeLeadingZeros: boolean;
|
removeLeadingZeros: boolean;
|
||||||
mainSource: keyof OntimeEvent | null;
|
mainSource: keyof OntimeEvent | null;
|
||||||
@@ -135,7 +135,7 @@ function getOptionsFromParams(searchParams: URLSearchParams): TimerOptions {
|
|||||||
hideCards: isStringBoolean(searchParams.get('hideCards')),
|
hideCards: isStringBoolean(searchParams.get('hideCards')),
|
||||||
hideProgress: isStringBoolean(searchParams.get('hideProgress')),
|
hideProgress: isStringBoolean(searchParams.get('hideProgress')),
|
||||||
hideMessage: isStringBoolean(searchParams.get('hideMessage')),
|
hideMessage: isStringBoolean(searchParams.get('hideMessage')),
|
||||||
hideExternal: isStringBoolean(searchParams.get('hideExternal')),
|
hideSecondary: isStringBoolean(searchParams.get('hideSecondary')),
|
||||||
hideTimerSeconds: isStringBoolean(searchParams.get('hideTimerSeconds')),
|
hideTimerSeconds: isStringBoolean(searchParams.get('hideTimerSeconds')),
|
||||||
removeLeadingZeros: !isStringBoolean(searchParams.get('showLeadingZeros')),
|
removeLeadingZeros: !isStringBoolean(searchParams.get('showLeadingZeros')),
|
||||||
|
|
||||||
|
|||||||
@@ -111,9 +111,9 @@ export function getSecondaryDisplay(
|
|||||||
localisedMinutes: string,
|
localisedMinutes: string,
|
||||||
removeSeconds: boolean,
|
removeSeconds: boolean,
|
||||||
removeLeadingZero: boolean,
|
removeLeadingZero: boolean,
|
||||||
hideExternal: boolean,
|
hideSecondary: boolean,
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (hideExternal) {
|
if (hideSecondary) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (message.timer.secondarySource === 'aux') {
|
if (message.timer.secondarySource === 'aux') {
|
||||||
@@ -122,8 +122,8 @@ export function getSecondaryDisplay(
|
|||||||
removeLeadingZero,
|
removeLeadingZero,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (message.timer.secondarySource === 'external' && message.external) {
|
if (message.timer.secondarySource === 'secondary' && message.secondary) {
|
||||||
return message.external;
|
return message.secondary;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,10 +158,10 @@ describe('parseOutput', () => {
|
|||||||
parseOutput({
|
parseOutput({
|
||||||
type: 'ontime',
|
type: 'ontime',
|
||||||
action: 'message-secondary',
|
action: 'message-secondary',
|
||||||
secondarySource: 'external',
|
secondarySource: 'secondary',
|
||||||
}),
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
secondarySource: 'external',
|
secondarySource: 'secondary',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -254,6 +254,6 @@ function indeterminateBooleanString(value: string): boolean | undefined {
|
|||||||
*/
|
*/
|
||||||
function chooseSecondarySource(value: string): SecondarySource {
|
function chooseSecondarySource(value: string): SecondarySource {
|
||||||
if (value === 'aux') return 'aux';
|
if (value === 'aux') return 'aux';
|
||||||
if (value === 'external') return 'external';
|
if (value === 'secondary') return 'secondary';
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { LogOrigin, OntimeAction } from 'ontime-types';
|
|||||||
|
|
||||||
import { logger } from '../../../classes/Logger.js';
|
import { logger } from '../../../classes/Logger.js';
|
||||||
import { auxTimerService } from '../../../services/aux-timer-service/AuxTimerService.js';
|
import { auxTimerService } from '../../../services/aux-timer-service/AuxTimerService.js';
|
||||||
import * as messageService from '../../../services/message-service/MessageService.js';
|
import * as messageService from '../../../services/message-service/message.service.js';
|
||||||
|
|
||||||
export function toOntimeAction(action: OntimeAction) {
|
export function toOntimeAction(action: OntimeAction) {
|
||||||
const actionType = action.action;
|
const actionType = action.action;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import { DeepPartial } from 'ts-essentials';
|
|||||||
|
|
||||||
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
|
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
|
||||||
import { auxTimerService } from '../services/aux-timer-service/AuxTimerService.js';
|
import { auxTimerService } from '../services/aux-timer-service/AuxTimerService.js';
|
||||||
import * as messageService from '../services/message-service/MessageService.js';
|
import * as messageService from '../services/message-service/message.service.js';
|
||||||
import { validateMessage, validateTimerMessage } from '../services/message-service/messageUtils.js';
|
import { validateMessage, validateTimerMessage } from '../services/message-service/message.utils.js';
|
||||||
import { runtimeService } from '../services/runtime-service/RuntimeService.js';
|
import { runtimeService } from '../services/runtime-service/RuntimeService.js';
|
||||||
import { eventStore } from '../stores/EventStore.js';
|
import { eventStore } from '../stores/EventStore.js';
|
||||||
import * as assert from '../utils/assert.js';
|
import * as assert from '../utils/assert.js';
|
||||||
@@ -101,7 +101,7 @@ const actionHandlers: Record<ApiAction, ActionHandler> = {
|
|||||||
|
|
||||||
const patch: DeepPartial<MessageState> = {
|
const patch: DeepPartial<MessageState> = {
|
||||||
timer: 'timer' in payload ? validateTimerMessage(payload.timer) : undefined,
|
timer: 'timer' in payload ? validateTimerMessage(payload.timer) : undefined,
|
||||||
external: 'external' in payload ? validateMessage(payload.external) : undefined,
|
secondary: 'secondary' in payload ? validateMessage(payload.secondary) : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const newMessage = messageService.patch(patch);
|
const newMessage = messageService.patch(patch);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { populateStyles } from './setup/loadStyles.js';
|
|||||||
import { eventStore } from './stores/EventStore.js';
|
import { eventStore } from './stores/EventStore.js';
|
||||||
import { runtimeService } from './services/runtime-service/RuntimeService.js';
|
import { runtimeService } from './services/runtime-service/RuntimeService.js';
|
||||||
import { restoreService } from './services/RestoreService.js';
|
import { restoreService } from './services/RestoreService.js';
|
||||||
import * as messageService from './services/message-service/MessageService.js';
|
import * as messageService from './services/message-service/message.service.js';
|
||||||
import { populateDemo } from './setup/loadDemo.js';
|
import { populateDemo } from './setup/loadDemo.js';
|
||||||
import { getState } from './stores/runtimeState.js';
|
import { getState } from './stores/runtimeState.js';
|
||||||
import { initRundown } from './api-data/rundown/rundown.service.js';
|
import { initRundown } from './api-data/rundown/rundown.service.js';
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
import { RuntimeStore } from 'ontime-types';
|
import { RuntimeStore } from 'ontime-types';
|
||||||
|
|
||||||
import * as messageService from '../MessageService.js';
|
import * as messageService from '../message.service.js';
|
||||||
|
|
||||||
describe('MessageService', () => {
|
describe('MessageService', () => {
|
||||||
let store: Partial<RuntimeStore>;
|
let store: Partial<RuntimeStore>;
|
||||||
@@ -17,12 +17,12 @@ describe('MessageService', () => {
|
|||||||
it('should patch the message state', () => {
|
it('should patch the message state', () => {
|
||||||
const newState = messageService.patch({
|
const newState = messageService.patch({
|
||||||
timer: { text: 'new text', visible: true },
|
timer: { text: 'new text', visible: true },
|
||||||
external: 'external',
|
secondary: 'secondary',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(newState).toMatchObject({
|
expect(newState).toMatchObject({
|
||||||
timer: { text: 'new text', visible: true, blackout: false, blink: false, secondarySource: null },
|
timer: { text: 'new text', visible: true, blackout: false, blink: false, secondarySource: null },
|
||||||
external: 'external',
|
secondary: 'secondary',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ describe('MessageService', () => {
|
|||||||
|
|
||||||
expect(newState).toMatchObject({
|
expect(newState).toMatchObject({
|
||||||
timer: { text: 'initial text', visible: true, blackout: false, blink: false, secondarySource: null },
|
timer: { text: 'initial text', visible: true, blackout: false, blink: false, secondarySource: null },
|
||||||
external: '',
|
secondary: '',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { validateMessage, validateTimerMessage } from '../messageUtils.js';
|
import { validateMessage, validateTimerMessage } from '../message.utils.js';
|
||||||
|
|
||||||
describe('validateMessage()', () => {
|
describe('validateMessage()', () => {
|
||||||
it('returns a valid Message object', () => {
|
it('returns a valid Message object', () => {
|
||||||
+1
-1
@@ -43,7 +43,7 @@ export function patch(patch: DeepPartial<MessageState>): MessageState {
|
|||||||
const newState = { ...getState() };
|
const newState = { ...getState() };
|
||||||
|
|
||||||
if ('timer' in patch) newState.timer = { ...newState.timer, ...patch.timer };
|
if ('timer' in patch) newState.timer = { ...newState.timer, ...patch.timer };
|
||||||
if ('external' in patch && patch.external !== undefined) newState.external = patch.external;
|
if ('secondary' in patch && patch.secondary !== undefined) newState.secondary = patch.secondary;
|
||||||
|
|
||||||
throttledSet('message', newState);
|
throttledSet('message', newState);
|
||||||
return newState;
|
return newState;
|
||||||
+1
-1
@@ -33,7 +33,7 @@ export function validateTimerMessage(message: unknown): Partial<TimerMessage> {
|
|||||||
* Asserts that the secondary value is one of the permitted values
|
* Asserts that the secondary value is one of the permitted values
|
||||||
*/
|
*/
|
||||||
function assertSecondary(source: unknown): source is TimerMessage['secondarySource'] {
|
function assertSecondary(source: unknown): source is TimerMessage['secondarySource'] {
|
||||||
return source === 'aux' || source === 'external' || source === null;
|
return source === 'aux' || source === 'secondary' || source === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export type SecondarySource = 'aux' | 'external' | null;
|
export type SecondarySource = 'aux' | 'secondary' | null;
|
||||||
|
|
||||||
export type TimerMessage = {
|
export type TimerMessage = {
|
||||||
text: string;
|
text: string;
|
||||||
@@ -10,5 +10,5 @@ export type TimerMessage = {
|
|||||||
|
|
||||||
export type MessageState = {
|
export type MessageState = {
|
||||||
timer: TimerMessage;
|
timer: TimerMessage;
|
||||||
external: string;
|
secondary: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const runtimeStorePlaceholder: Readonly<RuntimeStore> = {
|
|||||||
blackout: false,
|
blackout: false,
|
||||||
secondarySource: null,
|
secondarySource: null,
|
||||||
},
|
},
|
||||||
external: '',
|
secondary: '',
|
||||||
},
|
},
|
||||||
runtime: {
|
runtime: {
|
||||||
selectedEventIndex: null, // changes if rundown changes or we load a new event
|
selectedEventIndex: null, // changes if rundown changes or we load a new event
|
||||||
|
|||||||
Reference in New Issue
Block a user