mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-23 16:09:11 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c73f7e2207 | |||
| 4a0d83d970 | |||
| b89d0787d4 | |||
| 91a2d395cb | |||
| 6c9222bce3 |
@@ -6,6 +6,7 @@
|
|||||||
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
||||||
<meta name='theme-color' content='#121212' />
|
<meta name='theme-color' content='#121212' />
|
||||||
<meta name='ontime' content='ontime - event timer manager' />
|
<meta name='ontime' content='ontime - event timer manager' />
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="fullscreen 'self';">
|
||||||
<link rel='apple-touch-icon' href='/logo192.png' />
|
<link rel='apple-touch-icon' href='/logo192.png' />
|
||||||
<link
|
<link
|
||||||
rel='icon'
|
rel='icon'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime-ui",
|
"name": "ontime-ui",
|
||||||
"version": "2.0.2",
|
"version": "2.0.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/react": "^2.5.5",
|
"@chakra-ui/react": "^2.5.5",
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import React from 'react';
|
|||||||
// skipcq: JS-C1003 - sentry does not expose itself as an ES Module.
|
// skipcq: JS-C1003 - sentry does not expose itself as an ES Module.
|
||||||
import * as Sentry from '@sentry/react';
|
import * as Sentry from '@sentry/react';
|
||||||
|
|
||||||
|
import { runtime } from '@/common/stores/runtime';
|
||||||
|
import { hasConnected, reconnectAttempts, shouldReconnect } from '@/common/utils/socket';
|
||||||
|
|
||||||
import style from './ErrorBoundary.module.scss';
|
import style from './ErrorBoundary.module.scss';
|
||||||
|
|
||||||
class ErrorBoundary extends React.Component {
|
class ErrorBoundary extends React.Component {
|
||||||
@@ -25,7 +28,9 @@ class ErrorBoundary extends React.Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Sentry.withScope((scope) => {
|
Sentry.withScope((scope) => {
|
||||||
scope.setExtras(error);
|
scope.setExtras('error', error);
|
||||||
|
scope.setExtras('store', runtime.getState());
|
||||||
|
scope.setExtras('hasSocket', { hasConnected, shouldReconnect, reconnectAttempts });
|
||||||
const eventId = Sentry.captureException(error);
|
const eventId = Sentry.captureException(error);
|
||||||
this.setState({ eventId, info });
|
this.setState({ eventId, info });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,13 +8,16 @@ import { runtime } from '../stores/runtime';
|
|||||||
export let websocket: WebSocket | null = null;
|
export let websocket: WebSocket | null = null;
|
||||||
let reconnectTimeout: NodeJS.Timeout | null = null;
|
let reconnectTimeout: NodeJS.Timeout | null = null;
|
||||||
const reconnectInterval = 1000;
|
const reconnectInterval = 1000;
|
||||||
let shouldReconnect = true;
|
export let shouldReconnect = true;
|
||||||
|
export let hasConnected = false;
|
||||||
|
export let reconnectAttempts = 0;
|
||||||
export const connectSocket = () => {
|
export const connectSocket = () => {
|
||||||
websocket = new WebSocket(websocketUrl);
|
websocket = new WebSocket(websocketUrl);
|
||||||
|
|
||||||
websocket.onopen = () => {
|
websocket.onopen = () => {
|
||||||
clearTimeout(reconnectTimeout as NodeJS.Timeout);
|
clearTimeout(reconnectTimeout as NodeJS.Timeout);
|
||||||
|
hasConnected = true;
|
||||||
|
reconnectAttempts = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
websocket.onclose = () => {
|
websocket.onclose = () => {
|
||||||
@@ -23,6 +26,7 @@ export const connectSocket = () => {
|
|||||||
reconnectTimeout = setTimeout(() => {
|
reconnectTimeout = setTimeout(() => {
|
||||||
console.warn('WebSocket: attempting reconnect');
|
console.warn('WebSocket: attempting reconnect');
|
||||||
if (websocket && websocket.readyState === WebSocket.CLOSED) {
|
if (websocket && websocket.readyState === WebSocket.CLOSED) {
|
||||||
|
reconnectAttempts += 1;
|
||||||
connectSocket();
|
connectSocket();
|
||||||
}
|
}
|
||||||
}, reconnectInterval);
|
}, reconnectInterval);
|
||||||
|
|||||||
@@ -5,8 +5,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 { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
|
import { IoTime } from '@react-icons/all-files/io5/IoTime';
|
||||||
import { Playback } from 'ontime-types';
|
import { Playback } from 'ontime-types';
|
||||||
|
import { validatePlayback } from 'ontime-utils';
|
||||||
|
|
||||||
import { setPlayback } from '../../../../common/hooks/useSocket';
|
import { setPlayback } from '../../../../common/hooks/useSocket';
|
||||||
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
||||||
@@ -34,7 +35,13 @@ export default function PlaybackButtons(props: PlaybackButtonsProps) {
|
|||||||
const noEvents = numEvents === 0;
|
const noEvents = numEvents === 0;
|
||||||
|
|
||||||
const disableGo = isRolling || noEvents || (isLast && !isArmed);
|
const disableGo = isRolling || noEvents || (isLast && !isArmed);
|
||||||
const disablePrev = isRolling || noEvents || isFirst;
|
const disablePrev = noEvents || isFirst;
|
||||||
|
|
||||||
|
const playbackCan = validatePlayback(playback);
|
||||||
|
const disableStart = !playbackCan.start;
|
||||||
|
const disablePause = !playbackCan.pause;
|
||||||
|
const disableRoll = !playbackCan.roll || noEvents;
|
||||||
|
const disableStop = !playbackCan.stop;
|
||||||
|
|
||||||
const goModeText = selectedEventIndex === null || isArmed ? 'Start' : 'Next';
|
const goModeText = selectedEventIndex === null || isArmed ? 'Start' : 'Next';
|
||||||
const goModeAction = () => {
|
const goModeAction = () => {
|
||||||
@@ -51,21 +58,11 @@ export default function PlaybackButtons(props: PlaybackButtonsProps) {
|
|||||||
{goModeText}
|
{goModeText}
|
||||||
</TapButton>
|
</TapButton>
|
||||||
<div className={style.playbackContainer}>
|
<div className={style.playbackContainer}>
|
||||||
<TapButton
|
<TapButton onClick={setPlayback.start} disabled={disableStart} theme={Playback.Play} active={isPlaying}>
|
||||||
onClick={setPlayback.start}
|
|
||||||
disabled={isStopped || isRolling}
|
|
||||||
theme={Playback.Play}
|
|
||||||
active={isPlaying}
|
|
||||||
>
|
|
||||||
<IoPlay />
|
<IoPlay />
|
||||||
</TapButton>
|
</TapButton>
|
||||||
|
|
||||||
<TapButton
|
<TapButton onClick={setPlayback.pause} disabled={disablePause} theme={Playback.Pause} active={isPaused}>
|
||||||
onClick={setPlayback.pause}
|
|
||||||
disabled={isStopped || isRolling || isArmed}
|
|
||||||
theme={Playback.Pause}
|
|
||||||
active={isPaused}
|
|
||||||
>
|
|
||||||
<IoPause />
|
<IoPause />
|
||||||
</TapButton>
|
</TapButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,21 +79,16 @@ export default function PlaybackButtons(props: PlaybackButtonsProps) {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.extra}>
|
<div className={style.extra}>
|
||||||
<TapButton
|
<TapButton onClick={setPlayback.roll} disabled={disableRoll} theme={Playback.Roll} active={isRolling}>
|
||||||
onClick={setPlayback.roll}
|
<IoTime />
|
||||||
disabled={!isStopped || noEvents}
|
|
||||||
theme={Playback.Roll}
|
|
||||||
active={isRolling}
|
|
||||||
>
|
|
||||||
<IoTimeOutline />
|
|
||||||
</TapButton>
|
</TapButton>
|
||||||
<Tooltip label='Reload event' openDelay={tooltipDelayMid}>
|
<Tooltip label='Reload event' openDelay={tooltipDelayMid}>
|
||||||
<TapButton onClick={setPlayback.reload} disabled={isStopped || isRolling}>
|
<TapButton onClick={setPlayback.reload} disabled={isStopped}>
|
||||||
<IoReload className={style.invertX} />
|
<IoReload className={style.invertX} />
|
||||||
</TapButton>
|
</TapButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip label='Unload Event' openDelay={tooltipDelayMid}>
|
<Tooltip label='Unload Event' openDelay={tooltipDelayMid}>
|
||||||
<TapButton onClick={setPlayback.stop} disabled={isStopped && !isRolling} theme={Playback.Stop}>
|
<TapButton onClick={setPlayback.stop} disabled={disableStop} theme={Playback.Stop}>
|
||||||
<IoStop />
|
<IoStop />
|
||||||
</TapButton>
|
</TapButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ describe('parseField()', () => {
|
|||||||
{ field: 'title', value: 'test' },
|
{ field: 'title', value: 'test' },
|
||||||
{ field: 'presenter', value: 'test' },
|
{ field: 'presenter', value: 'test' },
|
||||||
{ field: 'subtitle', value: 'test' },
|
{ field: 'subtitle', value: 'test' },
|
||||||
{ field: 'notes', value: 'test' },
|
{ field: 'note', value: 'test' },
|
||||||
{ field: 'colour', value: 'test' },
|
{ field: 'colour', value: 'test' },
|
||||||
{ field: 'user0', value: 'test' },
|
{ field: 'user0', value: 'test' },
|
||||||
{ field: 'user1', value: 'test' },
|
{ field: 'user1', value: 'test' },
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ Sentry.init({
|
|||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
release: ONTIME_VERSION,
|
release: ONTIME_VERSION,
|
||||||
enabled: import.meta.env.PROD,
|
enabled: import.meta.env.PROD,
|
||||||
|
ignoreErrors: ['top.GLOBALS', 'Unable to preload CSS'],
|
||||||
|
denyUrls: [/extensions\//i, /^chrome:\/\//i, /^chrome-extension:\/\//i],
|
||||||
});
|
});
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ $ontime-delay-text: #E69056;
|
|||||||
$ontime-paused: #c05621;
|
$ontime-paused: #c05621;
|
||||||
$ontime-stop: #E4281E;
|
$ontime-stop: #E4281E;
|
||||||
$playback-negative: $red-500;
|
$playback-negative: $red-500;
|
||||||
$active-indicator: #899948;
|
$active-indicator: #8bb33d;
|
||||||
$text-black: $gray-1350;
|
$text-black: $gray-1350;
|
||||||
|
|
||||||
// interface panels
|
// interface panels
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "2.0.2",
|
"version": "2.0.8",
|
||||||
"author": "Carlos Valente",
|
"author": "Carlos Valente",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"repository": "https://github.com/cpvalente/ontime",
|
"repository": "https://github.com/cpvalente/ontime",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "ontime-server",
|
"name": "ontime-server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"version": "2.0.2",
|
"version": "2.0.8",
|
||||||
"exports": "./src/index.js",
|
"exports": "./src/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.0",
|
"body-parser": "^1.20.0",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { OntimeEvent, Playback } from 'ontime-types';
|
import { OntimeEvent } from 'ontime-types';
|
||||||
|
import { validatePlayback } from 'ontime-utils';
|
||||||
|
|
||||||
import { eventLoader, EventLoader } from '../classes/event-loader/EventLoader.js';
|
import { eventLoader, EventLoader } from '../classes/event-loader/EventLoader.js';
|
||||||
import { eventStore } from '../stores/EventStore.js';
|
import { eventStore } from '../stores/EventStore.js';
|
||||||
@@ -133,7 +134,7 @@ export class PlaybackService {
|
|||||||
* Starts playback on selected event
|
* Starts playback on selected event
|
||||||
*/
|
*/
|
||||||
static start() {
|
static start() {
|
||||||
if (eventTimer.playback === Playback.Armed || eventTimer.playback === Playback.Pause) {
|
if (validatePlayback(eventTimer.playback).start) {
|
||||||
eventTimer.start();
|
eventTimer.start();
|
||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
logger.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
logger.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
||||||
@@ -155,7 +156,7 @@ export class PlaybackService {
|
|||||||
* Pauses playback on selected event
|
* Pauses playback on selected event
|
||||||
*/
|
*/
|
||||||
static pause() {
|
static pause() {
|
||||||
if (eventTimer.playback === Playback.Play) {
|
if (validatePlayback(eventTimer.playback).pause) {
|
||||||
eventTimer.pause();
|
eventTimer.pause();
|
||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
logger.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
logger.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`);
|
||||||
@@ -166,7 +167,7 @@ export class PlaybackService {
|
|||||||
* Stops timer and unloads any events
|
* Stops timer and unloads any events
|
||||||
*/
|
*/
|
||||||
static stop() {
|
static stop() {
|
||||||
if (eventTimer.playback !== Playback.Stop) {
|
if (validatePlayback(eventTimer.playback).stop) {
|
||||||
eventLoader.reset();
|
eventLoader.reset();
|
||||||
eventTimer.stop();
|
eventTimer.stop();
|
||||||
const newState = eventTimer.playback;
|
const newState = eventTimer.playback;
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ import { DAY_TO_MS } from '../utils/time.js';
|
|||||||
import { integrationService } from './integration-service/IntegrationService.js';
|
import { integrationService } from './integration-service/IntegrationService.js';
|
||||||
import { getCurrent, getElapsed, getExpectedFinish } from './timerUtils.js';
|
import { getCurrent, getElapsed, getExpectedFinish } from './timerUtils.js';
|
||||||
import { clock } from './Clock.js';
|
import { clock } from './Clock.js';
|
||||||
|
import { logger } from '../classes/Logger.js';
|
||||||
|
|
||||||
|
type initialLoadingData = {
|
||||||
|
startedAt?: number | null;
|
||||||
|
expectedFinish?: number | null;
|
||||||
|
current?: number | null;
|
||||||
|
};
|
||||||
|
|
||||||
export class TimerService {
|
export class TimerService {
|
||||||
private readonly _interval: NodeJS.Timer;
|
private readonly _interval: NodeJS.Timer;
|
||||||
@@ -113,7 +120,7 @@ export class TimerService {
|
|||||||
* @param {string} timer.timerType
|
* @param {string} timer.timerType
|
||||||
* @param {boolean} timer.skip
|
* @param {boolean} timer.skip
|
||||||
*/
|
*/
|
||||||
load(timer) {
|
load(timer, initialData?: initialLoadingData) {
|
||||||
if (timer.skip) {
|
if (timer.skip) {
|
||||||
throw new Error('Refuse load of skipped event');
|
throw new Error('Refuse load of skipped event');
|
||||||
}
|
}
|
||||||
@@ -129,6 +136,10 @@ export class TimerService {
|
|||||||
this.pausedTime = 0;
|
this.pausedTime = 0;
|
||||||
this.pausedAt = 0;
|
this.pausedAt = 0;
|
||||||
|
|
||||||
|
if (typeof initialData !== 'undefined') {
|
||||||
|
this.timer = { ...this.timer, ...initialData };
|
||||||
|
}
|
||||||
|
|
||||||
this._onLoad();
|
this._onLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +157,9 @@ export class TimerService {
|
|||||||
|
|
||||||
start() {
|
start() {
|
||||||
if (!this.loadedTimerId) {
|
if (!this.loadedTimerId) {
|
||||||
|
if (this.playback === Playback.Roll) {
|
||||||
|
logger.error('PLAYBACK', 'Cannot start while waiting for event');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,12 +169,12 @@ export class TimerService {
|
|||||||
|
|
||||||
this.timer.clock = clock.timeNow();
|
this.timer.clock = clock.timeNow();
|
||||||
|
|
||||||
// add paused time
|
// add paused time if it exists
|
||||||
if (this.pausedTime) {
|
if (this.pausedTime) {
|
||||||
this.timer.addedTime += this.pausedTime;
|
this.timer.addedTime += this.pausedTime;
|
||||||
this.pausedAt = null;
|
this.pausedAt = null;
|
||||||
this.pausedTime = 0;
|
this.pausedTime = 0;
|
||||||
} else {
|
} else if (this.timer.startedAt === null) {
|
||||||
this.timer.startedAt = this.timer.clock;
|
this.timer.startedAt = this.timer.clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,10 +202,6 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
if (this.playback !== Playback.Play) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.playback = Playback.Pause;
|
this.playback = Playback.Pause;
|
||||||
this.timer.clock = clock.timeNow();
|
this.timer.clock = clock.timeNow();
|
||||||
this.pausedAt = this.timer.clock;
|
this.pausedAt = this.timer.clock;
|
||||||
@@ -309,7 +319,11 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(force = false) {
|
update(force = false) {
|
||||||
|
const previousTime = this.timer.clock;
|
||||||
this.timer.clock = clock.timeNow();
|
this.timer.clock = clock.timeNow();
|
||||||
|
if (previousTime > this.timer.clock) {
|
||||||
|
force = true;
|
||||||
|
}
|
||||||
|
|
||||||
// we call integrations if we update timers
|
// we call integrations if we update timers
|
||||||
let shouldNotify = false;
|
let shouldNotify = false;
|
||||||
@@ -370,9 +384,11 @@ export class TimerService {
|
|||||||
|
|
||||||
// when we load a timer in roll, we do the same things as before
|
// when we load a timer in roll, we do the same things as before
|
||||||
// but also pre-populate some data as to the running state
|
// but also pre-populate some data as to the running state
|
||||||
this.load(currentEvent);
|
this.load(currentEvent, {
|
||||||
this.timer.startedAt = currentEvent.timeStart;
|
startedAt: currentEvent.timeStart,
|
||||||
this.timer.expectedFinish = currentEvent.timeEnd;
|
expectedFinish: currentEvent.timeEnd,
|
||||||
|
current: currentEvent.timeEnd - this.timer.clock,
|
||||||
|
});
|
||||||
} else if (nextEvent) {
|
} else if (nextEvent) {
|
||||||
// account for day after
|
// account for day after
|
||||||
const nextStart = nextEvent.timeStart < this.timer.clock ? nextEvent.timeStart + DAY_TO_MS : nextEvent.timeStart;
|
const nextStart = nextEvent.timeStart < this.timer.clock ? nextEvent.timeStart + DAY_TO_MS : nextEvent.timeStart;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "2.0.2",
|
"version": "2.0.8",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"lighdev",
|
"lighdev",
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export { formatFromMillis } from './src/date-utils/formatFromMillis.js';
|
|||||||
export { isTimeString } from './src/date-utils/isTimeString.js';
|
export { isTimeString } from './src/date-utils/isTimeString.js';
|
||||||
export { millisToString } from './src/date-utils/millisToString.js';
|
export { millisToString } from './src/date-utils/millisToString.js';
|
||||||
export { generateId } from './src/generate-id/generateId.js';
|
export { generateId } from './src/generate-id/generateId.js';
|
||||||
|
export { validatePlayback } from './src/validate-action/validatePlayback.js';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "ontime-utils",
|
"name": "ontime-utils",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./index.ts",
|
"exports": "./index.ts",
|
||||||
"version": "2.0.2",
|
"version": "2.0.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "shared logic for ontime",
|
"description": "shared logic for ontime",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"eslint-config-prettier": "^8.6.0",
|
"eslint-config-prettier": "^8.6.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-simple-import-sort": "^8.0.0",
|
"eslint-plugin-simple-import-sort": "^8.0.0",
|
||||||
|
"ontime-types": "workspace:*",
|
||||||
"prettier": "^2.8.3",
|
"prettier": "^2.8.3",
|
||||||
"typescript": "^4.9.4",
|
"typescript": "^4.9.4",
|
||||||
"vitest": "^0.30.1"
|
"vitest": "^0.30.1"
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Playback } from 'ontime-types';
|
||||||
|
|
||||||
|
export function validatePlayback(currentPlayback: Playback) {
|
||||||
|
return {
|
||||||
|
start: currentPlayback !== Playback.Stop,
|
||||||
|
pause: currentPlayback === Playback.Play || currentPlayback === Playback.Roll,
|
||||||
|
roll: true,
|
||||||
|
stop: currentPlayback !== Playback.Stop,
|
||||||
|
};
|
||||||
|
}
|
||||||
Generated
+2
@@ -267,6 +267,7 @@ importers:
|
|||||||
eslint-plugin-simple-import-sort: ^8.0.0
|
eslint-plugin-simple-import-sort: ^8.0.0
|
||||||
luxon: ^3.3.0
|
luxon: ^3.3.0
|
||||||
nanoid: ^4.0.1
|
nanoid: ^4.0.1
|
||||||
|
ontime-types: workspace:*
|
||||||
prettier: ^2.8.3
|
prettier: ^2.8.3
|
||||||
typescript: ^4.9.4
|
typescript: ^4.9.4
|
||||||
vitest: ^0.30.1
|
vitest: ^0.30.1
|
||||||
@@ -281,6 +282,7 @@ importers:
|
|||||||
eslint-config-prettier: 8.6.0_eslint@8.31.0
|
eslint-config-prettier: 8.6.0_eslint@8.31.0
|
||||||
eslint-plugin-prettier: 4.2.1_do5yx3dogbskqc4h5x5ilvlwyy
|
eslint-plugin-prettier: 4.2.1_do5yx3dogbskqc4h5x5ilvlwyy
|
||||||
eslint-plugin-simple-import-sort: 8.0.0_eslint@8.31.0
|
eslint-plugin-simple-import-sort: 8.0.0_eslint@8.31.0
|
||||||
|
ontime-types: link:../types
|
||||||
prettier: 2.8.3
|
prettier: 2.8.3
|
||||||
typescript: 4.9.4
|
typescript: 4.9.4
|
||||||
vitest: 0.30.1
|
vitest: 0.30.1
|
||||||
|
|||||||
Reference in New Issue
Block a user