mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-09 16:19:47 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6397d33eaa | |||
| 9288566a7f | |||
| 7fd9f83fb0 | |||
| e621f1386e | |||
| b51e7cbd2d | |||
| 7cd92ce5f7 | |||
| f6a02abf36 | |||
| e4b0df42cf | |||
| ded8bddb2d | |||
| 8d3ce46c56 | |||
| 578cb2b244 | |||
| c79ee193c9 | |||
| 5810ae0d54 | |||
| bfbf8574e3 | |||
| 490e429f44 | |||
| 2e950965e0 | |||
| cc34db775a |
@@ -1,42 +0,0 @@
|
|||||||
name: Ontime Resolver build
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_cli:
|
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Use Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
registry-url: 'https://registry.npmjs.org'
|
|
||||||
|
|
||||||
- name: Setup pnpm
|
|
||||||
uses: pnpm/action-setup@v3
|
|
||||||
with:
|
|
||||||
version: 10
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Build project packages
|
|
||||||
run: pnpm turbo @getontime/resolver#build
|
|
||||||
|
|
||||||
- name: Publish to NPM
|
|
||||||
run: pnpm publish --access public --no-git-checks
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
NPM_CONFIG_PROVENANCE: true
|
|
||||||
working-directory: ./apps/resolver
|
|
||||||
@@ -8,4 +8,3 @@ playwright-report
|
|||||||
**/*.toml
|
**/*.toml
|
||||||
**/*.yml
|
**/*.yml
|
||||||
**/*.json
|
**/*.json
|
||||||
!tsconfig.common.json
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@getontime/cli",
|
"name": "@getontime/cli",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.3",
|
||||||
"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",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime-ui",
|
"name": "ontime-ui",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import IdentifyOverlay from './common/components/identify-overlay/IdentifyOverla
|
|||||||
import { AppContextProvider } from './common/context/AppContext';
|
import { AppContextProvider } from './common/context/AppContext';
|
||||||
import { ontimeQueryClient } from './common/queryClient';
|
import { ontimeQueryClient } from './common/queryClient';
|
||||||
import { connectSocket } from './common/utils/socket';
|
import { connectSocket } from './common/utils/socket';
|
||||||
import KeepAwake from './features/keep-awake/KeepAwake';
|
|
||||||
import { TranslationProvider } from './translation/TranslationProvider';
|
import { TranslationProvider } from './translation/TranslationProvider';
|
||||||
import AppRouter from './AppRouter';
|
import AppRouter from './AppRouter';
|
||||||
import { baseURI } from './externals';
|
import { baseURI } from './externals';
|
||||||
@@ -25,7 +24,6 @@ function App() {
|
|||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<TranslationProvider>
|
<TranslationProvider>
|
||||||
<IdentifyOverlay />
|
<IdentifyOverlay />
|
||||||
<KeepAwake />
|
|
||||||
<AppRouter />
|
<AppRouter />
|
||||||
</TranslationProvider>
|
</TranslationProvider>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { IoClose, IoContract, IoExpand, IoEye, IoLockClosedOutline, IoSwapVertical } from 'react-icons/io5';
|
import { IoClose, IoContract, IoExpand, IoLockClosedOutline, IoSwapVertical } from 'react-icons/io5';
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router';
|
||||||
import { Dialog } from '@base-ui-components/react/dialog';
|
import { Dialog } from '@base-ui-components/react/dialog';
|
||||||
import { useDisclosure, useFullscreen } from '@mantine/hooks';
|
import { useDisclosure, useFullscreen } from '@mantine/hooks';
|
||||||
|
|
||||||
import { isLocalhost } from '../../../externals';
|
import { isLocalhost } from '../../../externals';
|
||||||
import { useKeepAwakeOptions } from '../../../features/keep-awake/KeepAwake';
|
|
||||||
import { navigatorConstants } from '../../../viewerConfig';
|
import { navigatorConstants } from '../../../viewerConfig';
|
||||||
import { useClientStore } from '../../stores/clientStore';
|
import { useClientStore } from '../../stores/clientStore';
|
||||||
import { useViewOptionsStore } from '../../stores/viewOptions';
|
import { useViewOptionsStore } from '../../stores/viewOptions';
|
||||||
@@ -32,7 +31,6 @@ function NavigationMenu({ isOpen, onClose }: NavigationMenuProps) {
|
|||||||
const [isRenameOpen, handlers] = useDisclosure(false);
|
const [isRenameOpen, handlers] = useDisclosure(false);
|
||||||
const { fullscreen, toggle } = useFullscreen();
|
const { fullscreen, toggle } = useFullscreen();
|
||||||
const { mirror, toggleMirror } = useViewOptionsStore();
|
const { mirror, toggleMirror } = useViewOptionsStore();
|
||||||
const { keepAwake, toggleKeepAwake } = useKeepAwakeOptions();
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -64,13 +62,6 @@ function NavigationMenu({ isOpen, onClose }: NavigationMenuProps) {
|
|||||||
<IoSwapVertical />
|
<IoSwapVertical />
|
||||||
{mirror && <span className={style.note}>Active</span>}
|
{mirror && <span className={style.note}>Active</span>}
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
{window.isSecureContext && (
|
|
||||||
<NavigationMenuItem active={keepAwake} onClick={toggleKeepAwake}>
|
|
||||||
Keep Awake
|
|
||||||
<IoEye />
|
|
||||||
{keepAwake && <span className={style.note}>Active</span>}
|
|
||||||
</NavigationMenuItem>
|
|
||||||
)}
|
|
||||||
<NavigationMenuItem onClick={handlers.open}>Rename Client</NavigationMenuItem>
|
<NavigationMenuItem onClick={handlers.open}>Rename Client</NavigationMenuItem>
|
||||||
|
|
||||||
<hr className={style.separator} />
|
<hr className={style.separator} />
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
||||||
width: 40rem;
|
width: 40rem;
|
||||||
max-width: 100vw;
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -164,6 +164,24 @@ export const useProgressData = createSelector((state: RuntimeStore) => ({
|
|||||||
timeDanger: state.eventNow?.timeDanger ?? null,
|
timeDanger: state.eventNow?.timeDanger ?? null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const useRundownOverview = createSelector((state: RuntimeStore) => ({
|
||||||
|
plannedStart: state.rundown.plannedStart,
|
||||||
|
actualStart: state.rundown.actualStart,
|
||||||
|
plannedEnd: state.rundown.plannedEnd,
|
||||||
|
expectedEnd: state.offset.expectedRundownEnd,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const useRuntimePlaybackOverview = createSelector((state: RuntimeStore) => ({
|
||||||
|
playback: state.timer.playback,
|
||||||
|
clock: state.clock,
|
||||||
|
|
||||||
|
numEvents: state.rundown.numEvents,
|
||||||
|
selectedEventIndex: state.rundown.selectedEventIndex,
|
||||||
|
offset: state.offset.mode === OffsetMode.Absolute ? state.offset.absolute : state.offset.relative,
|
||||||
|
|
||||||
|
groupExpectedEnd: state.offset.expectedGroupEnd,
|
||||||
|
}));
|
||||||
|
|
||||||
export const useTimelineStatus = createSelector((state: RuntimeStore) => ({
|
export const useTimelineStatus = createSelector((state: RuntimeStore) => ({
|
||||||
clock: state.clock,
|
clock: state.clock,
|
||||||
offset: state.offset.absolute,
|
offset: state.offset.absolute,
|
||||||
@@ -172,7 +190,7 @@ export const useTimelineStatus = createSelector((state: RuntimeStore) => ({
|
|||||||
export const useExpectedStartData = createSelector((state: RuntimeStore) => ({
|
export const useExpectedStartData = createSelector((state: RuntimeStore) => ({
|
||||||
offset: state.offset.mode === OffsetMode.Absolute ? state.offset.absolute : state.offset.relative,
|
offset: state.offset.mode === OffsetMode.Absolute ? state.offset.absolute : state.offset.relative,
|
||||||
mode: state.offset.mode,
|
mode: state.offset.mode,
|
||||||
currentDay: state.rundown.currentDay ?? 0,
|
currentDay: state.eventNow?.dayOffset ?? 0,
|
||||||
actualStart: state.rundown.actualStart,
|
actualStart: state.rundown.actualStart,
|
||||||
plannedStart: state.rundown.plannedStart,
|
plannedStart: state.rundown.plannedStart,
|
||||||
clock: state.clock,
|
clock: state.clock,
|
||||||
@@ -209,45 +227,6 @@ export const usePlayback = () => {
|
|||||||
return useRuntimeStore(featureSelector);
|
return useRuntimeStore(featureSelector);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ======================= Overview data subscriptions ======================= */
|
|
||||||
|
|
||||||
export const useRundownOverview = createSelector((state: RuntimeStore) => ({
|
|
||||||
plannedStart: state.rundown.plannedStart,
|
|
||||||
actualStart: state.rundown.actualStart,
|
|
||||||
plannedEnd: state.rundown.plannedEnd,
|
|
||||||
expectedEnd: state.offset.expectedRundownEnd,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const useProgressOverview = createSelector((state: RuntimeStore) => ({
|
|
||||||
numEvents: state.rundown.numEvents,
|
|
||||||
selectedEventIndex: state.rundown.selectedEventIndex,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const useOffsetOverview = createSelector((state: RuntimeStore) => ({
|
|
||||||
offset: state.offset.mode === OffsetMode.Absolute ? state.offset.absolute : state.offset.relative,
|
|
||||||
playback: state.timer.playback,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const useGroupTimerOverView = createSelector((state: RuntimeStore) => ({
|
|
||||||
clock: state.clock,
|
|
||||||
mode: state.offset.mode,
|
|
||||||
groupExpectedEnd: state.offset.expectedGroupEnd,
|
|
||||||
// we can force these numbers to 0 fo this use case to avoid null checks
|
|
||||||
actualGroupStart: state.rundown.actualGroupStart ?? 0,
|
|
||||||
currentDay: state.eventNow?.dayOffset ?? 0,
|
|
||||||
playback: state.timer.playback,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const useFlagTimerOverView = createSelector((state: RuntimeStore) => ({
|
|
||||||
clock: state.clock,
|
|
||||||
mode: state.offset.mode,
|
|
||||||
// we can force these numbers to 0 fo this use case to avoid null checks
|
|
||||||
actualStart: state.rundown.actualStart ?? 0,
|
|
||||||
plannedStart: state.rundown.plannedStart ?? 0,
|
|
||||||
currentDay: state.eventNow?.dayOffset ?? 0,
|
|
||||||
playback: state.timer.playback,
|
|
||||||
}));
|
|
||||||
|
|
||||||
/* ======================= View specific subscriptions ======================= */
|
/* ======================= View specific subscriptions ======================= */
|
||||||
|
|
||||||
export const useTimerSocket = createSelector((state: RuntimeStore) => ({
|
export const useTimerSocket = createSelector((state: RuntimeStore) => ({
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export type Size = 'xs' | 'sm' | 'md' | 'lg';
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
type Target = 'cuesheet' | 'timer' | 'clock' | 'countdown' | 'backstage' | 'studio';
|
||||||
|
|
||||||
|
interface SelectionState {
|
||||||
|
[key: string]: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ColumnPermissions {
|
||||||
|
read: string[];
|
||||||
|
write: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CuesheetLinksState {
|
||||||
|
target: Target | null;
|
||||||
|
readSelected: SelectionState;
|
||||||
|
writeSelected: SelectionState;
|
||||||
|
setTarget: (target: Target | null) => void;
|
||||||
|
setField: (field: 'read' | 'write', key: string, value: boolean) => void;
|
||||||
|
toggleField: (field: 'read' | 'write', key: string) => void;
|
||||||
|
selectAll: (field: 'read' | 'write', keys: string[]) => void;
|
||||||
|
clearAll: (field: 'read' | 'write', keys: string[]) => void;
|
||||||
|
// Returns arrays of column keys that have read/write permissions if target is 'cuesheet'
|
||||||
|
getSelections: () => ColumnPermissions | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCuesheetLinksStore = create<CuesheetLinksState>((set, get) => ({
|
||||||
|
target: null,
|
||||||
|
readSelected: {},
|
||||||
|
writeSelected: {},
|
||||||
|
setTarget: (target) => set({ target }),
|
||||||
|
setField: (field, key, value) =>
|
||||||
|
set((state) => ({
|
||||||
|
...(field === 'read'
|
||||||
|
? { readSelected: { ...state.readSelected, [key]: value } }
|
||||||
|
: { writeSelected: { ...state.writeSelected, [key]: value } }),
|
||||||
|
})),
|
||||||
|
toggleField: (field, key) =>
|
||||||
|
set((state) => ({
|
||||||
|
...(field === 'read'
|
||||||
|
? { readSelected: { ...state.readSelected, [key]: !state.readSelected[key] } }
|
||||||
|
: { writeSelected: { ...state.writeSelected, [key]: !state.writeSelected[key] } }),
|
||||||
|
})),
|
||||||
|
selectAll: (field, keys) =>
|
||||||
|
set((_state) => ({
|
||||||
|
...(field === 'read'
|
||||||
|
? {
|
||||||
|
readSelected: keys.reduce((acc, key) => {
|
||||||
|
acc[key] = true;
|
||||||
|
return acc;
|
||||||
|
}, {} as SelectionState),
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
writeSelected: keys.reduce((acc, key) => {
|
||||||
|
acc[key] = true;
|
||||||
|
return acc;
|
||||||
|
}, {} as SelectionState),
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
clearAll: (field, keys) =>
|
||||||
|
set((_state) => ({
|
||||||
|
...(field === 'read'
|
||||||
|
? {
|
||||||
|
readSelected: keys.reduce((acc, key) => {
|
||||||
|
acc[key] = false;
|
||||||
|
return acc;
|
||||||
|
}, {} as SelectionState),
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
writeSelected: keys.reduce((acc, key) => {
|
||||||
|
acc[key] = false;
|
||||||
|
return acc;
|
||||||
|
}, {} as SelectionState),
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
getSelections: () => {
|
||||||
|
const state = get();
|
||||||
|
if (state.target !== 'cuesheet') return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
read: Object.entries(state.readSelected)
|
||||||
|
.filter(([_, selected]) => selected)
|
||||||
|
.map(([key]) => key),
|
||||||
|
write: Object.entries(state.writeSelected)
|
||||||
|
.filter(([_, selected]) => selected)
|
||||||
|
.map(([key]) => key),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}));
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { MaybeString } from 'ontime-types';
|
||||||
|
|
||||||
|
export default function safeParseNumber(value: MaybeString, defaultValue: number = 0): number {
|
||||||
|
if (!value) return defaultValue;
|
||||||
|
const number = Number(value);
|
||||||
|
if (isNaN(number)) return defaultValue;
|
||||||
|
return number;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
ApiActionTag,
|
ApiAction,
|
||||||
Log,
|
Log,
|
||||||
MessageTag,
|
MessageTag,
|
||||||
RefetchKey,
|
RefetchKey,
|
||||||
@@ -199,7 +199,7 @@ export const connectSocket = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function sendSocket<T extends MessageTag | ApiActionTag>(
|
export function sendSocket<T extends MessageTag | ApiAction>(
|
||||||
tag: T,
|
tag: T,
|
||||||
payload: T extends MessageTag ? Pick<WsPacketToServer & { tag: T }, 'payload'>['payload'] : unknown,
|
payload: T extends MessageTag ? Pick<WsPacketToServer & { tag: T }, 'payload'>['payload'] : unknown,
|
||||||
): void {
|
): void {
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ export function validateProjectFile(file: File) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Limit file size of a project file to around 1MB
|
// Limit file size of a project file to around 1MB
|
||||||
if (file.size > 2_000_000) {
|
if (file.size > 1_000_000) {
|
||||||
throw new Error('File size limit (2MB) exceeded');
|
throw new Error('File size limit (1MB) exceeded');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ export function validateLogo(file: File) {
|
|||||||
throw new Error('File is empty');
|
throw new Error('File is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit file size of a project file to around 1.5MB
|
// Limit file size of a project file to around 1MB
|
||||||
if (file.size > 1_500_000) {
|
if (file.size > 1_000_000) {
|
||||||
throw new Error('File size limit (1.5MB) exceeded');
|
throw new Error('File size limit (1MB) exceeded');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/* eslint-disable react/display-name */
|
||||||
|
import { ComponentType, useEffect } from 'react';
|
||||||
|
import { useLocation, useNavigate } from 'react-router';
|
||||||
|
|
||||||
|
import useUrlPresets from '../common/hooks-query/useUrlPresets';
|
||||||
|
import { getRouteFromPreset } from '../common/utils/urlPresets';
|
||||||
|
|
||||||
|
const withPreset = <P extends object>(Component: ComponentType<P>) => {
|
||||||
|
return (props: Partial<P>) => {
|
||||||
|
const { data } = useUrlPresets();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
// navigate if is alias route
|
||||||
|
useEffect(() => {
|
||||||
|
if (!data) return;
|
||||||
|
const destination = getRouteFromPreset(location, data);
|
||||||
|
|
||||||
|
// navigate to this destination if its not null
|
||||||
|
if (destination) {
|
||||||
|
navigate(destination);
|
||||||
|
}
|
||||||
|
}, [data, navigate, location]);
|
||||||
|
|
||||||
|
return <Component {...(props as P)} />;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withPreset;
|
||||||
@@ -107,9 +107,6 @@ export default function AutomationsList(props: AutomationsListProps) {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Panel.InlineElements>
|
</Panel.InlineElements>
|
||||||
</tr>
|
</tr>
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{deleteError && (
|
{deleteError && (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={5}>
|
<td colSpan={5}>
|
||||||
@@ -117,6 +114,9 @@ export default function AutomationsList(props: AutomationsListProps) {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</Panel.Table>
|
</Panel.Table>
|
||||||
</Panel.Card>
|
</Panel.Card>
|
||||||
|
|||||||
+2
-6
@@ -2,7 +2,6 @@ import { useState } from 'react';
|
|||||||
import { CustomFields, Rundown } from 'ontime-types';
|
import { CustomFields, Rundown } from 'ontime-types';
|
||||||
|
|
||||||
import Button from '../../../../../common/components/buttons/Button';
|
import Button from '../../../../../common/components/buttons/Button';
|
||||||
import useRundown from '../../../../../common/hooks-query/useRundown';
|
|
||||||
import * as Panel from '../../../panel-utils/PanelUtils';
|
import * as Panel from '../../../panel-utils/PanelUtils';
|
||||||
|
|
||||||
import PreviewSpreadsheet from './preview/PreviewRundown';
|
import PreviewSpreadsheet from './preview/PreviewRundown';
|
||||||
@@ -18,7 +17,7 @@ interface ImportReviewProps {
|
|||||||
|
|
||||||
export default function ImportReview(props: ImportReviewProps) {
|
export default function ImportReview(props: ImportReviewProps) {
|
||||||
const { rundown, customFields, onFinished, onCancel } = props;
|
const { rundown, customFields, onFinished, onCancel } = props;
|
||||||
const { data: currentRundown } = useRundown();
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { importRundown } = useGoogleSheet();
|
const { importRundown } = useGoogleSheet();
|
||||||
const resetPreview = useSheetStore((state) => state.resetPreview);
|
const resetPreview = useSheetStore((state) => state.resetPreview);
|
||||||
@@ -30,12 +29,9 @@ export default function ImportReview(props: ImportReviewProps) {
|
|||||||
|
|
||||||
const applyImport = async () => {
|
const applyImport = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// we need to import on-top of the currently loaded rundown
|
|
||||||
// so the id needs to match
|
|
||||||
await importRundown(
|
await importRundown(
|
||||||
{
|
{
|
||||||
[currentRundown.id]: { ...rundown, id: currentRundown.id, title: currentRundown.title },
|
[rundown.id]: rundown,
|
||||||
},
|
},
|
||||||
customFields,
|
customFields,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ export default function ProjectData() {
|
|||||||
reset,
|
reset,
|
||||||
formState: { isSubmitting, isValid, isDirty, errors },
|
formState: { isSubmitting, isValid, isDirty, errors },
|
||||||
setError,
|
setError,
|
||||||
clearErrors,
|
|
||||||
watch,
|
watch,
|
||||||
control,
|
control,
|
||||||
setValue,
|
setValue,
|
||||||
@@ -54,7 +53,6 @@ export default function ProjectData() {
|
|||||||
|
|
||||||
const handleUploadProjectLogo = async (event: ChangeEvent<HTMLInputElement>) => {
|
const handleUploadProjectLogo = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = event.target.files?.[0];
|
const file = event.target.files?.[0];
|
||||||
clearErrors('logo');
|
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
@@ -95,7 +93,6 @@ export default function ProjectData() {
|
|||||||
|
|
||||||
const onSubmit = async (formData: ProjectData) => {
|
const onSubmit = async (formData: ProjectData) => {
|
||||||
try {
|
try {
|
||||||
clearErrors();
|
|
||||||
await updateProjectData(formData);
|
await updateProjectData(formData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = maybeAxiosError(error);
|
const message = maybeAxiosError(error);
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
import { use, useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
import { useSearchParams } from 'react-router';
|
|
||||||
|
|
||||||
import { PresetContext } from '../../common/context/PresetContext';
|
|
||||||
|
|
||||||
/** @url https://developer.mozilla.org/en-US/docs/Web/API/WakeLock */
|
|
||||||
export default function KeepAwake() {
|
|
||||||
const { keepAwake } = useKeepAwakeOptions();
|
|
||||||
const [wakeLockSentinel, setWakeLockSentinel] = useState<WakeLockSentinel | null>(null);
|
|
||||||
|
|
||||||
const removeLock = () => {
|
|
||||||
if (wakeLockSentinel) wakeLockSentinel.release().finally(() => setWakeLockSentinel(null));
|
|
||||||
};
|
|
||||||
|
|
||||||
const acquireLock = () => {
|
|
||||||
if (!wakeLockSentinel || wakeLockSentinel.released) {
|
|
||||||
setWakeLockSentinel(null);
|
|
||||||
navigator.wakeLock
|
|
||||||
.request('screen')
|
|
||||||
.then((sentinel) => {
|
|
||||||
setWakeLockSentinel(sentinel);
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const controller = new AbortController();
|
|
||||||
if (keepAwake) {
|
|
||||||
acquireLock();
|
|
||||||
document.addEventListener(
|
|
||||||
'visibilitychange',
|
|
||||||
() => {
|
|
||||||
if (wakeLockSentinel !== null && document.visibilityState === 'visible') {
|
|
||||||
acquireLock();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ signal: controller.signal },
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
removeLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
controller.abort();
|
|
||||||
removeLock();
|
|
||||||
};
|
|
||||||
}, [keepAwake]);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const keepAwakeKey = 'keep-awake';
|
|
||||||
|
|
||||||
function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URLSearchParams) {
|
|
||||||
// Helper to get value from either source, prioritizing defaultValues
|
|
||||||
return defaultValues?.has(keepAwakeKey) || searchParams.has(keepAwakeKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook exposes the keep awake options
|
|
||||||
*/
|
|
||||||
export function useKeepAwakeOptions() {
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
const maybePreset = use(PresetContext);
|
|
||||||
|
|
||||||
const keepAwake = useMemo(() => {
|
|
||||||
const defaultValues = maybePreset ? new URLSearchParams(maybePreset.search) : undefined;
|
|
||||||
return getOptionsFromParams(searchParams, defaultValues);
|
|
||||||
}, [maybePreset, searchParams]);
|
|
||||||
|
|
||||||
const toggleKeepAwake = useCallback(() => {
|
|
||||||
setSearchParams((searchParams) => {
|
|
||||||
if (keepAwake) {
|
|
||||||
searchParams.delete(keepAwakeKey);
|
|
||||||
} else {
|
|
||||||
searchParams.set(keepAwakeKey, '1');
|
|
||||||
}
|
|
||||||
return searchParams;
|
|
||||||
});
|
|
||||||
}, [keepAwake]);
|
|
||||||
|
|
||||||
return { keepAwake, toggleKeepAwake };
|
|
||||||
}
|
|
||||||
@@ -47,10 +47,9 @@
|
|||||||
|
|
||||||
.daySpan {
|
.daySpan {
|
||||||
&::after {
|
&::after {
|
||||||
content: "+"attr(data-day-offset);
|
content: '*';
|
||||||
vertical-align: super;
|
vertical-align: super;
|
||||||
font-size: 0.6em;
|
font-size: 0.75em;
|
||||||
letter-spacing: 0;
|
|
||||||
color: $info-blue;
|
color: $info-blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,10 +67,3 @@
|
|||||||
font-size: calc(1rem - 2px);
|
font-size: calc(1rem - 2px);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dueTime {
|
|
||||||
text-transform: capitalize;
|
|
||||||
font-size: 1rem;
|
|
||||||
letter-spacing: 0;
|
|
||||||
color: $playback-over;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,26 +8,23 @@ import {
|
|||||||
TbFolderPin,
|
TbFolderPin,
|
||||||
TbFolderStar,
|
TbFolderStar,
|
||||||
} from 'react-icons/tb';
|
} from 'react-icons/tb';
|
||||||
import { OffsetMode, OntimeEvent, OntimeGroup, TimerPhase, TimerType } from 'ontime-types';
|
import { OntimeEvent, OntimeGroup, TimerPhase, TimerType } from 'ontime-types';
|
||||||
import { dayInMs, isPlaybackActive, millisToString } from 'ontime-utils';
|
import { isPlaybackActive, millisToString } from 'ontime-utils';
|
||||||
|
|
||||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||||
import {
|
import {
|
||||||
useClock,
|
useClock,
|
||||||
useCurrentGroupId,
|
useCurrentGroupId,
|
||||||
useFlagTimerOverView,
|
|
||||||
useGroupTimerOverView,
|
|
||||||
useNextFlag,
|
useNextFlag,
|
||||||
useOffsetOverview,
|
|
||||||
useProgressOverview,
|
|
||||||
useRundownOverview,
|
useRundownOverview,
|
||||||
|
useRuntimePlaybackOverview,
|
||||||
useTimer,
|
useTimer,
|
||||||
} from '../../../common/hooks/useSocket';
|
} from '../../../common/hooks/useSocket';
|
||||||
import { useEntry } from '../../../common/hooks-query/useRundown';
|
import { useEntry } from '../../../common/hooks-query/useRundown';
|
||||||
import { getOffsetState, getOffsetText } from '../../../common/utils/offset';
|
import { getOffsetState, getOffsetText } from '../../../common/utils/offset';
|
||||||
import { cx, enDash, timerPlaceholder } from '../../../common/utils/styleUtils';
|
import { cx, enDash, timerPlaceholder } from '../../../common/utils/styleUtils';
|
||||||
import { formatTime } from '../../../common/utils/time';
|
import { formatTime } from '../../../common/utils/time';
|
||||||
import { calculateEndAndDaySpan, formatDueTime, formattedTime } from '../overview.utils';
|
import { calculateEndAndDaySpan, formattedTime } from '../overview.utils';
|
||||||
|
|
||||||
import { OverUnder, TimeColumn } from './TimeLayout';
|
import { OverUnder, TimeColumn } from './TimeLayout';
|
||||||
|
|
||||||
@@ -61,8 +58,8 @@ export function StartTimes() {
|
|||||||
<Tooltip text='Planned end time' render={<TbCalendarPin className={style.icon} />} />
|
<Tooltip text='Planned end time' render={<TbCalendarPin className={style.icon} />} />
|
||||||
{maybePlannedDaySpan > 0 ? (
|
{maybePlannedDaySpan > 0 ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
text={`Rundown spans over ${maybePlannedDaySpan + 1} days`}
|
text={`Event spans over ${maybePlannedDaySpan + 1} days`}
|
||||||
render={<span className={cx([style.time, style.daySpan])} data-day-offset={maybePlannedDaySpan} />}
|
render={<span className={cx([style.time, style.daySpan])} />}
|
||||||
>
|
>
|
||||||
{plannedEndText}
|
{plannedEndText}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -74,8 +71,8 @@ export function StartTimes() {
|
|||||||
<Tooltip text='Expected end time' render={<TbCalendarStar className={style.icon} />} />
|
<Tooltip text='Expected end time' render={<TbCalendarStar className={style.icon} />} />
|
||||||
{maybeExpectedEnd !== null && maybeExpectedDaySpan > 0 ? (
|
{maybeExpectedEnd !== null && maybeExpectedDaySpan > 0 ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
text={`Rundown spans over ${maybeExpectedDaySpan + 1} days`}
|
text={`Event spans over ${maybeExpectedDaySpan + 1} days`}
|
||||||
render={<span className={cx([style.time, style.daySpan])} data-day-offset={maybeExpectedDaySpan} />}
|
render={<span className={cx([style.time, style.daySpan])} />}
|
||||||
>
|
>
|
||||||
{formattedTime(maybeExpectedEnd)}
|
{formattedTime(maybeExpectedEnd)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -99,110 +96,61 @@ export function MetadataTimes() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: there a some things here we still need to think about, mainly what to do whit the planed group duration in relation to the events
|
||||||
function GroupTimes() {
|
function GroupTimes() {
|
||||||
const { clock, mode, groupExpectedEnd, actualGroupStart, currentDay, playback } = useGroupTimerOverView();
|
const { clock, groupExpectedEnd } = useRuntimePlaybackOverview();
|
||||||
const { currentGroupId } = useCurrentGroupId();
|
const { currentGroupId } = useCurrentGroupId();
|
||||||
const group = useEntry(currentGroupId) as OntimeGroup | null;
|
const group = useEntry(currentGroupId) as OntimeGroup | null;
|
||||||
|
|
||||||
const active = isPlaybackActive(playback);
|
// the group end time dose not encode any day offsets
|
||||||
|
const plannedGroupEnd = group && group.timeStart !== null ? group.timeStart + group.duration - clock : null;
|
||||||
// the group end time dose not encode any day offsets so it is calculated with group start time and duration
|
const plannedTimeUntilGroupEnd = formattedTime(plannedGroupEnd, 3, TimerType.CountDown);
|
||||||
const plannedGroupEnd = (() => {
|
|
||||||
if (!active) return null;
|
|
||||||
if (!group || group.timeStart === null) return null;
|
|
||||||
const normalizedClock = clock + currentDay * dayInMs;
|
|
||||||
|
|
||||||
return mode === OffsetMode.Absolute
|
|
||||||
? group.timeStart + group.duration - normalizedClock
|
|
||||||
: actualGroupStart + group.duration - normalizedClock;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const plannedTimeUntilGroupEnd = formatDueTime(plannedGroupEnd, 3, TimerType.CountDown);
|
|
||||||
|
|
||||||
const expectedGroupEnd = groupExpectedEnd !== null ? groupExpectedEnd - clock : null;
|
const expectedGroupEnd = groupExpectedEnd !== null ? groupExpectedEnd - clock : null;
|
||||||
const expectedTimeUntilGroupEnd = formatDueTime(expectedGroupEnd, 3, TimerType.CountDown);
|
const expectedTimeUntilGroupEnd = formattedTime(expectedGroupEnd, 3, TimerType.CountDown);
|
||||||
|
|
||||||
|
const groupTitle = group?.title ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.metadataRow}>
|
<div className={style.metadataRow}>
|
||||||
<span className={group?.title ? style.labelTitle : style.label}>{`${group?.title || 'Group'} `}</span>
|
<span className={groupTitle ? style.labelTitle : style.label}>{`${groupTitle ? groupTitle : 'Group'} `}</span>
|
||||||
<div className={style.labelledElement}>
|
<div className={style.labelledElement}>
|
||||||
<Tooltip text='Time to planned group end' render={<TbFolderPin className={style.icon} />} />
|
<Tooltip text='Time to planned group end' render={<TbFolderPin className={style.icon} />} />
|
||||||
<span
|
<span className={cx([style.time, !group && style.muted])}>{plannedTimeUntilGroupEnd}</span>
|
||||||
className={cx([
|
|
||||||
style.time,
|
|
||||||
(!group || !active) && style.muted,
|
|
||||||
plannedTimeUntilGroupEnd === 'due' && style.dueTime,
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{plannedTimeUntilGroupEnd}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={style.labelledElement}>
|
<div className={style.labelledElement}>
|
||||||
<Tooltip text='Time to expected group end' render={<TbFolderStar className={style.icon} />} />
|
<Tooltip text='Time to expected group end' render={<TbFolderStar className={style.icon} />} />
|
||||||
<span
|
<span className={cx([style.time, groupExpectedEnd === null && style.muted])}>{expectedTimeUntilGroupEnd}</span>
|
||||||
className={cx([
|
|
||||||
style.time,
|
|
||||||
!groupExpectedEnd && style.muted,
|
|
||||||
expectedTimeUntilGroupEnd === 'due' && style.dueTime,
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{expectedTimeUntilGroupEnd}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FlagTimes() {
|
function FlagTimes() {
|
||||||
const { clock, mode, actualStart, plannedStart, playback, currentDay } = useFlagTimerOverView();
|
const { clock } = useClock();
|
||||||
const { id, expectedStart } = useNextFlag();
|
const { id, expectedStart } = useNextFlag();
|
||||||
const entry = useEntry(id) as OntimeEvent | null;
|
const entry = useEntry(id) as OntimeEvent | null;
|
||||||
|
|
||||||
const active = isPlaybackActive(playback);
|
const plannedFlagStart = entry ? entry.timeStart - clock : null;
|
||||||
|
const plannedTimeUntilDisplay = formattedTime(plannedFlagStart, 3, TimerType.CountDown);
|
||||||
const plannedFlagStart = (() => {
|
|
||||||
if (!active) return null;
|
|
||||||
if (!entry) return null;
|
|
||||||
const normalizedTimeStart = entry.timeStart + entry.dayOffset * dayInMs;
|
|
||||||
const normalizedClock = clock + currentDay * dayInMs;
|
|
||||||
return mode === OffsetMode.Absolute
|
|
||||||
? normalizedTimeStart - normalizedClock
|
|
||||||
: normalizedTimeStart + actualStart - plannedStart - normalizedClock;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const plannedTimeUntilDisplay = formatDueTime(plannedFlagStart, 3, TimerType.CountDown);
|
|
||||||
|
|
||||||
const expectedTimeUntil = expectedStart !== null ? expectedStart - clock : null;
|
const expectedTimeUntil = expectedStart !== null ? expectedStart - clock : null;
|
||||||
const expectedTimeUntilDisplay = formatDueTime(expectedTimeUntil, 3, TimerType.CountDown);
|
const expectedTimeUntilDisplay = formattedTime(expectedTimeUntil, 3, TimerType.CountDown);
|
||||||
|
|
||||||
const title = entry?.title ?? null;
|
const title = entry?.title ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.metadataRow}>
|
<div className={style.metadataRow}>
|
||||||
<span className={title ? style.labelTitle : style.label}>{`${title || 'Flag'} `}</span>
|
<span className={title ? style.labelTitle : style.label}>{`${title ? title : 'Flag'} `}</span>
|
||||||
<div className={style.labelledElement}>
|
<div className={style.labelledElement}>
|
||||||
<Tooltip text='Time to next flag planned start' render={<TbFlagPin className={style.icon} />} />
|
<Tooltip text='Time to next flag planned start' render={<TbFlagPin className={style.icon} />} />
|
||||||
<span
|
<span data-testid='flag-plannedStart' className={cx([style.time, !entry && style.muted])}>
|
||||||
data-testid='flag-plannedStart'
|
|
||||||
className={cx([
|
|
||||||
style.time,
|
|
||||||
(!entry || !active) && style.muted,
|
|
||||||
plannedTimeUntilDisplay === 'due' && style.dueTime,
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{plannedTimeUntilDisplay}
|
{plannedTimeUntilDisplay}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.labelledElement}>
|
<div className={style.labelledElement}>
|
||||||
<Tooltip text='Time to next flag expected start' render={<TbFlagStar className={style.icon} />} />
|
<Tooltip text='Time to next flag expected start' render={<TbFlagStar className={style.icon} />} />
|
||||||
<span
|
<span data-testid='flag-expectedStart' className={cx([style.time, expectedTimeUntil === null && style.muted])}>
|
||||||
data-testid='flag-expectedStart'
|
|
||||||
className={cx([
|
|
||||||
style.time,
|
|
||||||
expectedTimeUntil === null && style.muted,
|
|
||||||
expectedTimeUntilDisplay === 'due' && style.dueTime,
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{expectedTimeUntilDisplay}
|
{expectedTimeUntilDisplay}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -211,7 +159,7 @@ function FlagTimes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ProgressOverview() {
|
export function ProgressOverview() {
|
||||||
const { numEvents, selectedEventIndex } = useProgressOverview();
|
const { numEvents, selectedEventIndex } = useRuntimePlaybackOverview();
|
||||||
|
|
||||||
const current = selectedEventIndex !== null ? selectedEventIndex + 1 : enDash;
|
const current = selectedEventIndex !== null ? selectedEventIndex + 1 : enDash;
|
||||||
const progressText = numEvents ? `${current} of ${numEvents || enDash}` : enDash;
|
const progressText = numEvents ? `${current} of ${numEvents || enDash}` : enDash;
|
||||||
@@ -220,7 +168,7 @@ export function ProgressOverview() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function OffsetOverview() {
|
export function OffsetOverview() {
|
||||||
const { offset, playback } = useOffsetOverview();
|
const { offset, playback } = useRuntimePlaybackOverview();
|
||||||
|
|
||||||
const isPlaying = isPlaybackActive(playback);
|
const isPlaying = isPlaybackActive(playback);
|
||||||
const offsetState = getOffsetState(isPlaying ? offset : null);
|
const offsetState = getOffsetState(isPlaying ? offset : null);
|
||||||
|
|||||||
@@ -3,23 +3,6 @@ import { dayInMs, millisToString } from 'ontime-utils';
|
|||||||
|
|
||||||
import { timerPlaceholder, timerPlaceholderMin } from '../../common/utils/styleUtils';
|
import { timerPlaceholder, timerPlaceholderMin } from '../../common/utils/styleUtils';
|
||||||
|
|
||||||
/**
|
|
||||||
* Composition to stop negative timers from being formatted
|
|
||||||
* They should show a due string instead
|
|
||||||
*
|
|
||||||
* This is used for cases when a negative timer is unwanted
|
|
||||||
* eg: count down to a milestone
|
|
||||||
*/
|
|
||||||
export function formatDueTime(
|
|
||||||
time: MaybeNumber,
|
|
||||||
segments: number = 3,
|
|
||||||
direction?: TimerType.CountDown | TimerType.CountUp,
|
|
||||||
dueString = 'due',
|
|
||||||
): string {
|
|
||||||
if (time !== null && time <= 0) return dueString;
|
|
||||||
return formattedTime(time, segments, direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the logic for formatting time in overview
|
* Encapsulates the logic for formatting time in overview
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ interface EventUntilProps {
|
|||||||
isLinkedToLoaded: boolean;
|
isLinkedToLoaded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EventUntil({ timeStart, delay, dayOffset, totalGap, isLinkedToLoaded }: EventUntilProps) {
|
function EventUntil(props: EventUntilProps) {
|
||||||
|
const { timeStart, delay, dayOffset, totalGap, isLinkedToLoaded } = props;
|
||||||
|
|
||||||
const timeUntil = useTimeUntilExpectedStart({ timeStart, delay, dayOffset }, { totalGap, isLinkedToLoaded });
|
const timeUntil = useTimeUntilExpectedStart({ timeStart, delay, dayOffset }, { totalGap, isLinkedToLoaded });
|
||||||
const isDue = timeUntil < MILLIS_PER_SECOND;
|
const isDue = timeUntil < MILLIS_PER_SECOND;
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ $header-font-size: clamp(24px, 2.5vw, 48px);
|
|||||||
|
|
||||||
// General styling
|
// General styling
|
||||||
$accent-color: $red-500; // --accent-color-override
|
$accent-color: $red-500; // --accent-color-override
|
||||||
|
$delay-color: $ontime-delay-text;
|
||||||
$viewer-label-color: rgba(white, 25%);
|
$viewer-label-color: rgba(white, 25%);
|
||||||
|
|
||||||
// Main Properties of a viewer
|
// Main Properties of a viewer
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ import {
|
|||||||
makeProjectDataOptions,
|
makeProjectDataOptions,
|
||||||
} from '../../common/components/view-params-editor/viewParams.utils';
|
} from '../../common/components/view-params-editor/viewParams.utils';
|
||||||
import { PresetContext } from '../../common/context/PresetContext';
|
import { PresetContext } from '../../common/context/PresetContext';
|
||||||
import { getScheduleOptions } from '../common/schedule/schedule.options';
|
import { scheduleOptions } from '../common/schedule/schedule.options';
|
||||||
|
|
||||||
export const getBackstageOptions = (
|
export const getBackstageOptions = (
|
||||||
timeFormat: string,
|
timeFormat: string,
|
||||||
customFields: CustomFields,
|
customFields: CustomFields,
|
||||||
projectData: ProjectData,
|
projectData: ProjectData,
|
||||||
): ViewOption[] => {
|
): ViewOption[] => {
|
||||||
const customFieldOptions = makeOptionsFromCustomFields(customFields, []);
|
|
||||||
const secondaryOptions = makeOptionsFromCustomFields(customFields, [
|
const secondaryOptions = makeOptionsFromCustomFields(customFields, [
|
||||||
{ value: 'none', label: 'None' },
|
{ value: 'none', label: 'None' },
|
||||||
{ value: 'note', label: 'Note' },
|
{ value: 'note', label: 'Note' },
|
||||||
@@ -40,7 +39,7 @@ export const getBackstageOptions = (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
getScheduleOptions(customFieldOptions),
|
scheduleOptions,
|
||||||
{
|
{
|
||||||
title: OptionTitle.ElementVisibility,
|
title: OptionTitle.ElementVisibility,
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
import { createContext, PropsWithChildren, RefObject, use, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
import {
|
||||||
import { EntryId, isOntimeEvent, OntimeEntry, OntimeEvent } from 'ontime-types';
|
createContext,
|
||||||
|
PropsWithChildren,
|
||||||
|
RefObject,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import { isOntimeEvent, OntimeEntry, OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { usePartialRundown } from '../../../common/hooks-query/useRundown';
|
import { usePartialRundown } from '../../../common/hooks-query/useRundown';
|
||||||
|
|
||||||
@@ -16,18 +25,13 @@ interface ScheduleContextState {
|
|||||||
const ScheduleContext = createContext<ScheduleContextState | undefined>(undefined);
|
const ScheduleContext = createContext<ScheduleContextState | undefined>(undefined);
|
||||||
|
|
||||||
interface ScheduleProviderProps {
|
interface ScheduleProviderProps {
|
||||||
selectedEventId: EntryId | null;
|
selectedEventId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildren<ScheduleProviderProps>) => {
|
export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildren<ScheduleProviderProps>) => {
|
||||||
const { cycleInterval, stopCycle, filter } = useScheduleOptions();
|
const { cycleInterval, stopCycle } = useScheduleOptions();
|
||||||
const { data: events } = usePartialRundown((entry: OntimeEntry) => {
|
const { data: events } = usePartialRundown((event: OntimeEntry) => {
|
||||||
if (filter) {
|
return isOntimeEvent(event);
|
||||||
// custom keys are prepended with custom-
|
|
||||||
const customKey = filter.startsWith('custom-') ? filter.slice('custom-'.length) : filter;
|
|
||||||
return isOntimeEvent(entry) && Boolean(entry.custom[customKey]);
|
|
||||||
}
|
|
||||||
return isOntimeEvent(entry);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [firstIndex, setFirstIndex] = useState(-1);
|
const [firstIndex, setFirstIndex] = useState(-1);
|
||||||
@@ -131,7 +135,7 @@ export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildre
|
|||||||
selectedEventIndex = 0;
|
selectedEventIndex = 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScheduleContext
|
<ScheduleContext.Provider
|
||||||
value={{
|
value={{
|
||||||
events: viewEvents as OntimeEvent[],
|
events: viewEvents as OntimeEvent[],
|
||||||
selectedEventId,
|
selectedEventId,
|
||||||
@@ -141,12 +145,12 @@ export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildre
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ScheduleContext>
|
</ScheduleContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSchedule = () => {
|
export const useSchedule = () => {
|
||||||
const context = use(ScheduleContext);
|
const context = useContext(ScheduleContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useSchedule() can only be used inside a ScheduleContext');
|
throw new Error('useSchedule() can only be used inside a ScheduleContext');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ interface ScheduleItemProps {
|
|||||||
delay: number;
|
delay: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }: ScheduleItemProps) {
|
export default function ScheduleItem(props: ScheduleItemProps) {
|
||||||
|
const { timeStart, timeEnd, title, colour, skip, delay } = props;
|
||||||
const { showExpected } = useScheduleOptions();
|
const { showExpected } = useScheduleOptions();
|
||||||
|
|
||||||
if (showExpected) {
|
if (showExpected) {
|
||||||
@@ -66,7 +67,9 @@ export default function ScheduleItem({ timeStart, timeEnd, title, colour, skip,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DelayedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }: ScheduleItemProps) {
|
function DelayedScheduleItem(props: ScheduleItemProps) {
|
||||||
|
const { timeStart, timeEnd, title, colour, skip, delay } = props;
|
||||||
|
|
||||||
const start = formatTime(timeStart, formatOptions);
|
const start = formatTime(timeStart, formatOptions);
|
||||||
const end = formatTime(timeEnd, formatOptions);
|
const end = formatTime(timeEnd, formatOptions);
|
||||||
const delayedStart = formatTime(timeStart + delay, formatOptions);
|
const delayedStart = formatTime(timeStart + delay, formatOptions);
|
||||||
@@ -92,7 +95,9 @@ function DelayedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExpectedScheduleItem({ timeStart, timeEnd, title, colour, skip, delay }: ScheduleItemProps) {
|
function ExpectedScheduleItem(props: ScheduleItemProps) {
|
||||||
|
const { timeStart, timeEnd, title, colour, skip, delay } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className={cx(['entry', skip && 'entry--skip'])}>
|
<li className={cx(['entry', skip && 'entry--skip'])}>
|
||||||
<div className='entry-times'>
|
<div className='entry-times'>
|
||||||
@@ -111,11 +116,12 @@ interface ExpectedTimeProps {
|
|||||||
delay: number;
|
delay: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExpectedTime({ time, delay }: ExpectedTimeProps) {
|
function ExpectedTime(props: ExpectedTimeProps) {
|
||||||
|
const { time, delay } = props;
|
||||||
const { offset } = useRuntimeOffset();
|
const { offset } = useRuntimeOffset();
|
||||||
|
|
||||||
const expectedOffset = offset - delay;
|
const expectedOffset = offset - delay;
|
||||||
const expectedTime = formatTime(time + offset, formatOptions);
|
const expectedTime = formatTime(time - offset, formatOptions);
|
||||||
const expectedState = getOffsetState(expectedOffset);
|
const expectedState = getOffsetState(expectedOffset);
|
||||||
|
|
||||||
return <SuperscriptTime className={`entry-times--${expectedState}`} time={expectedTime} />;
|
return <SuperscriptTime className={`entry-times--${expectedState}`} time={expectedTime} />;
|
||||||
|
|||||||
@@ -1,23 +1,14 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useSearchParams } from 'react-router';
|
import { useSearchParams } from 'react-router';
|
||||||
|
|
||||||
import { SelectOption } from '../../../common/components/select/Select';
|
|
||||||
import { OptionTitle } from '../../../common/components/view-params-editor/constants';
|
import { OptionTitle } from '../../../common/components/view-params-editor/constants';
|
||||||
import type { ViewOption } from '../../../common/components/view-params-editor/viewParams.types';
|
import { ViewOption } from '../../../common/components/view-params-editor/viewParams.types';
|
||||||
import { isStringBoolean } from '../../../features/viewers/common/viewUtils';
|
import { isStringBoolean } from '../../../features/viewers/common/viewUtils';
|
||||||
|
|
||||||
export const getScheduleOptions = (customFieldOptions: SelectOption[]): ViewOption => ({
|
export const scheduleOptions: ViewOption = {
|
||||||
title: OptionTitle.Schedule,
|
title: OptionTitle.Schedule,
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
options: [
|
options: [
|
||||||
{
|
|
||||||
id: 'filter',
|
|
||||||
title: 'Filter',
|
|
||||||
description: 'Hide events without data in the selected custom field',
|
|
||||||
type: 'option',
|
|
||||||
values: customFieldOptions,
|
|
||||||
defaultValue: 'None',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'stopCycle',
|
id: 'stopCycle',
|
||||||
title: 'Stop cycling through event pages',
|
title: 'Stop cycling through event pages',
|
||||||
@@ -40,10 +31,9 @@ export const getScheduleOptions = (customFieldOptions: SelectOption[]): ViewOpti
|
|||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
|
||||||
type ScheduleOptions = {
|
type ScheduleOptions = {
|
||||||
filter: string | null;
|
|
||||||
cycleInterval: number;
|
cycleInterval: number;
|
||||||
stopCycle: boolean;
|
stopCycle: boolean;
|
||||||
showExpected: boolean;
|
showExpected: boolean;
|
||||||
@@ -51,7 +41,6 @@ type ScheduleOptions = {
|
|||||||
|
|
||||||
function getScheduleOptionsFromParams(searchParams: URLSearchParams): ScheduleOptions {
|
function getScheduleOptionsFromParams(searchParams: URLSearchParams): ScheduleOptions {
|
||||||
return {
|
return {
|
||||||
filter: searchParams.get('filter'),
|
|
||||||
cycleInterval: Number(searchParams.get('cycleInterval')) || 10,
|
cycleInterval: Number(searchParams.get('cycleInterval')) || 10,
|
||||||
stopCycle: isStringBoolean(searchParams.get('stopCycle')),
|
stopCycle: isStringBoolean(searchParams.get('stopCycle')),
|
||||||
showExpected: isStringBoolean(searchParams.get('showExpected')),
|
showExpected: isStringBoolean(searchParams.get('showExpected')),
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ $item-height: 3.5rem;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sub__schedule--delayed {
|
.sub__schedule--delayed {
|
||||||
color: $ontime-delay-text;
|
color: $delay-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub__schedule--strike {
|
.sub__schedule--strike {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { IoAdd } from 'react-icons/io5';
|
import { IoAdd } from 'react-icons/io5';
|
||||||
import { EntryId, isOntimeEvent, isPlayableEvent, OntimeEvent, OntimeView } from 'ontime-types';
|
import { isOntimeEvent, isPlayableEvent, OntimeEvent, OntimeView } from 'ontime-types';
|
||||||
|
|
||||||
import Button from '../../common/components/buttons/Button';
|
import Button from '../../common/components/buttons/Button';
|
||||||
import Empty from '../../common/components/state/Empty';
|
import Empty from '../../common/components/state/Empty';
|
||||||
@@ -16,7 +16,7 @@ import { useTranslation } from '../../translation/TranslationProvider';
|
|||||||
import Loader from '../common/loader/Loader';
|
import Loader from '../common/loader/Loader';
|
||||||
|
|
||||||
import { getCountdownOptions, useCountdownOptions } from './countdown.options';
|
import { getCountdownOptions, useCountdownOptions } from './countdown.options';
|
||||||
import { getOrderedSubscriptions } from './countdown.utils';
|
import { CountdownSubscription, getOrderedSubscriptions } from './countdown.utils';
|
||||||
import CountdownSelect from './CountdownSelect';
|
import CountdownSelect from './CountdownSelect';
|
||||||
import CountdownSubscriptions from './CountdownSubscriptions';
|
import CountdownSubscriptions from './CountdownSubscriptions';
|
||||||
import SingleEventCountdown from './SingleEventCountdown';
|
import SingleEventCountdown from './SingleEventCountdown';
|
||||||
@@ -59,6 +59,8 @@ function Countdown({ customFields, rundownData, projectData, isMirrored, setting
|
|||||||
[defaultFormat, customFields, subscriptions],
|
[defaultFormat, customFields, subscriptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(subscriptions)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`countdown ${isMirrored ? 'mirror' : ''}`} data-testid='countdown-view'>
|
<div className={`countdown ${isMirrored ? 'mirror' : ''}`} data-testid='countdown-view'>
|
||||||
<ViewParamsEditor target={OntimeView.Countdown} viewOptions={countdownOptions} />
|
<ViewParamsEditor target={OntimeView.Countdown} viewOptions={countdownOptions} />
|
||||||
@@ -87,7 +89,7 @@ function Countdown({ customFields, rundownData, projectData, isMirrored, setting
|
|||||||
|
|
||||||
interface CountdownContentsProps {
|
interface CountdownContentsProps {
|
||||||
playableEvents: ExtendedEntry<OntimeEvent>[];
|
playableEvents: ExtendedEntry<OntimeEvent>[];
|
||||||
subscriptions: EntryId[];
|
subscriptions: CountdownSubscription;
|
||||||
goToEditMode: () => void;
|
goToEditMode: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { IoArrowBack, IoClose, IoSaveOutline } from 'react-icons/io5';
|
import { IoArrowBack, IoClose, IoSaveOutline, IoAlbumsOutline } from 'react-icons/io5';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { EntryId, OntimeEvent } from 'ontime-types';
|
import { EntryId, OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
@@ -7,18 +7,19 @@ import Button from '../../common/components/buttons/Button';
|
|||||||
import { cx } from '../../common/utils/styleUtils';
|
import { cx } from '../../common/utils/styleUtils';
|
||||||
import ClockTime from '../../features/viewers/common/clock-time/ClockTime';
|
import ClockTime from '../../features/viewers/common/clock-time/ClockTime';
|
||||||
|
|
||||||
import { makeSubscriptionsUrl } from './countdown.utils';
|
import { CountdownSubscription, makeSubscriptionsUrl } from './countdown.utils';
|
||||||
|
|
||||||
import './Countdown.scss';
|
import './Countdown.scss';
|
||||||
|
|
||||||
interface CountdownSelectProps {
|
interface CountdownSelectProps {
|
||||||
events: OntimeEvent[];
|
events: OntimeEvent[];
|
||||||
subscriptions: EntryId[];
|
subscriptions: CountdownSubscription;
|
||||||
disableEdit: () => void;
|
disableEdit: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CountdownSelect({ events, subscriptions, disableEdit }: CountdownSelectProps) {
|
export default function CountdownSelect({ events, subscriptions, disableEdit }: CountdownSelectProps) {
|
||||||
const [selected, setSelected] = useState<EntryId[]>(subscriptions);
|
const maybeAllSubscriptions: EntryId[] = subscriptions === 'all' ? events.map((event) => event.id) : subscriptions;
|
||||||
|
const [selected, setSelected] = useState<EntryId[]>(maybeAllSubscriptions);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +48,18 @@ export default function CountdownSelect({ events, subscriptions, disableEdit }:
|
|||||||
navigate(url.search.toString());
|
navigate(url.search.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a URL with all
|
||||||
|
* and navigates to it
|
||||||
|
*/
|
||||||
|
const applyAll = () => {
|
||||||
|
// we remove events that no longer exist to avoid stale subscriptions
|
||||||
|
const url = makeSubscriptionsUrl(window.location.href, 'all');
|
||||||
|
disableEdit();
|
||||||
|
setSelected([]);
|
||||||
|
navigate(url.search.toString());
|
||||||
|
};
|
||||||
|
|
||||||
// make a copy of the selected array for quick lookup
|
// make a copy of the selected array for quick lookup
|
||||||
const selectedIds = new Set(selected);
|
const selectedIds = new Set(selected);
|
||||||
|
|
||||||
@@ -86,6 +99,10 @@ export default function CountdownSelect({ events, subscriptions, disableEdit }:
|
|||||||
<Button variant='subtle' size='xlarge' onClick={disableEdit}>
|
<Button variant='subtle' size='xlarge' onClick={disableEdit}>
|
||||||
<IoArrowBack /> Go back
|
<IoArrowBack /> Go back
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button variant='subtle' size='xlarge' onClick={applyAll}>
|
||||||
|
{/* TODO: icon ??? */}
|
||||||
|
<IoAlbumsOutline /> Use All
|
||||||
|
</Button>
|
||||||
<Button variant='subtle' size='xlarge' onClick={() => setSelected([])} disabled={selected.length === 0}>
|
<Button variant='subtle' size='xlarge' onClick={() => setSelected([])} disabled={selected.length === 0}>
|
||||||
<IoClose /> Clear
|
<IoClose /> Clear
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import { ViewOption } from '../../common/components/view-params-editor/viewParam
|
|||||||
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
|
import { makeOptionsFromCustomFields } from '../../common/components/view-params-editor/viewParams.utils';
|
||||||
import { PresetContext } from '../../common/context/PresetContext';
|
import { PresetContext } from '../../common/context/PresetContext';
|
||||||
import { isStringBoolean } from '../../features/viewers/common/viewUtils';
|
import { isStringBoolean } from '../../features/viewers/common/viewUtils';
|
||||||
|
import { CountdownSubscription } from './countdown.utils';
|
||||||
|
|
||||||
export const getCountdownOptions = (
|
export const getCountdownOptions = (
|
||||||
timeFormat: string,
|
timeFormat: string,
|
||||||
customFields: CustomFields,
|
customFields: CustomFields,
|
||||||
persistedSubscriptions: EntryId[],
|
persistedSubscriptions: CountdownSubscription,
|
||||||
): ViewOption[] => {
|
): ViewOption[] => {
|
||||||
const secondaryOptions = makeOptionsFromCustomFields(customFields, [
|
const secondaryOptions = makeOptionsFromCustomFields(customFields, [
|
||||||
{ value: 'none', label: 'None' },
|
{ value: 'none', label: 'None' },
|
||||||
@@ -55,7 +56,7 @@ export const getCountdownOptions = (
|
|||||||
id: 'sub',
|
id: 'sub',
|
||||||
title: 'Event subscription',
|
title: 'Event subscription',
|
||||||
description: 'The events to follow',
|
description: 'The events to follow',
|
||||||
values: persistedSubscriptions,
|
values: persistedSubscriptions === 'all' ? ['all'] : persistedSubscriptions,
|
||||||
type: 'persist',
|
type: 'persist',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -64,7 +65,7 @@ export const getCountdownOptions = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
type CountdownOptions = {
|
type CountdownOptions = {
|
||||||
subscriptions: EntryId[];
|
subscriptions: CountdownSubscription;
|
||||||
secondarySource: keyof OntimeEvent | null;
|
secondarySource: keyof OntimeEvent | null;
|
||||||
showExpected: boolean;
|
showExpected: boolean;
|
||||||
};
|
};
|
||||||
@@ -85,8 +86,10 @@ function getOptionsFromParams(searchParams: URLSearchParams, defaultValues?: URL
|
|||||||
return searchParams.getAll(key) as EntryId[];
|
return searchParams.getAll(key) as EntryId[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const subscriptions = getArrayValues('sub');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscriptions: getArrayValues('sub'),
|
subscriptions: subscriptions.at(0) === 'all' ? 'all' : subscriptions,
|
||||||
secondarySource: getValue('secondary-src') as keyof OntimeEvent | null,
|
secondarySource: getValue('secondary-src') as keyof OntimeEvent | null,
|
||||||
showExpected: isStringBoolean(getValue('showExpected')),
|
showExpected: isStringBoolean(getValue('showExpected')),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export function sanitiseTitle(title: string | null) {
|
|||||||
return title ?? '{no title}';
|
return title ?? '{no title}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CountdownSubscription = EntryId[] | 'all';
|
||||||
|
|
||||||
export const preferredFormat12 = 'h:mm a';
|
export const preferredFormat12 = 'h:mm a';
|
||||||
export const preferredFormat24 = 'HH:mm';
|
export const preferredFormat24 = 'HH:mm';
|
||||||
|
|
||||||
@@ -120,7 +122,7 @@ export function useSubscriptionDisplayData(
|
|||||||
/**
|
/**
|
||||||
* Adds a set of subscriptions to the URL parameters
|
* Adds a set of subscriptions to the URL parameters
|
||||||
*/
|
*/
|
||||||
export function makeSubscriptionsUrl(urlRef: string, subscriptions: EntryId[]) {
|
export function makeSubscriptionsUrl(urlRef: string, subscriptions: CountdownSubscription) {
|
||||||
const url = new URL(urlRef);
|
const url = new URL(urlRef);
|
||||||
const newParams = new URLSearchParams();
|
const newParams = new URLSearchParams();
|
||||||
|
|
||||||
@@ -131,10 +133,14 @@ export function makeSubscriptionsUrl(urlRef: string, subscriptions: EntryId[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subscriptions === 'all') {
|
||||||
|
newParams.append('sub', 'all');
|
||||||
|
} else {
|
||||||
// add new subscriptions
|
// add new subscriptions
|
||||||
subscriptions.forEach((id) => {
|
subscriptions.forEach((id) => {
|
||||||
newParams.append('sub', id);
|
newParams.append('sub', id);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
url.search = newParams.toString();
|
url.search = newParams.toString();
|
||||||
|
|
||||||
@@ -146,38 +152,14 @@ export function makeSubscriptionsUrl(urlRef: string, subscriptions: EntryId[]) {
|
|||||||
* Since the original array is already ordered, we simply filter out the events
|
* Since the original array is already ordered, we simply filter out the events
|
||||||
* which are not in the subscriptions list.
|
* which are not in the subscriptions list.
|
||||||
*/
|
*/
|
||||||
export function getOrderedSubscriptions<T extends OntimeEntry>(subscriptions: EntryId[], playableEvents: T[]): T[] {
|
export function getOrderedSubscriptions<T extends OntimeEntry>(
|
||||||
|
subscriptions: CountdownSubscription,
|
||||||
|
playableEvents: T[],
|
||||||
|
): T[] {
|
||||||
|
if (subscriptions === 'all') return playableEvents;
|
||||||
return playableEvents.filter((event) => subscriptions.includes(event.id));
|
return playableEvents.filter((event) => subscriptions.includes(event.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks through the rundown whether the current event is linked to the loaded event
|
|
||||||
*/
|
|
||||||
export function isLinkedToLoadedEvent(events: OntimeEvent[], loadedId: EntryId | null, currentId: EntryId): boolean {
|
|
||||||
// if nothing is loaded, we return true to simplify the logic
|
|
||||||
if (!loadedId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadedIndex = events.findIndex((event) => event.id === loadedId);
|
|
||||||
if (loadedIndex === -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = loadedIndex; i < events.length; i++) {
|
|
||||||
const event = events[i];
|
|
||||||
if (event.id === currentId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.linkStart === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOutsideRange(a: number, b: number): boolean {
|
export function isOutsideRange(a: number, b: number): boolean {
|
||||||
return Math.abs(a - b) > MILLIS_PER_MINUTE;
|
return Math.abs(a - b) > MILLIS_PER_MINUTE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { useVisibleRowsStore } from './visibleRowsStore';
|
||||||
|
|
||||||
|
let observer: IntersectionObserver | null = null;
|
||||||
|
|
||||||
|
function getObserver(): IntersectionObserver {
|
||||||
|
if (!observer) {
|
||||||
|
const options: IntersectionObserverInit = {
|
||||||
|
root: null,
|
||||||
|
rootMargin: '400px 0px', // prevent unmounting rows too early
|
||||||
|
threshold: 0.25,
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnIntersect: IntersectionObserverCallback = (entries) => {
|
||||||
|
const visibleRows = useVisibleRowsStore.getState();
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
const targetId = entry.target.id;
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
visibleRows.addVisibleRow(targetId);
|
||||||
|
} else {
|
||||||
|
visibleRows.removeVisibleRow(targetId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
observer = new IntersectionObserver(handleOnIntersect, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a row element in the observer
|
||||||
|
*/
|
||||||
|
export function observeRow(element: HTMLElement) {
|
||||||
|
getObserver().observe(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unregister a row element in the observer
|
||||||
|
*/
|
||||||
|
export function unobserveRow(element: HTMLElement) {
|
||||||
|
getObserver().unobserve(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cleanup observer, should be called when the table component unmounts
|
||||||
|
*/
|
||||||
|
export function cleanup() {
|
||||||
|
observer?.disconnect();
|
||||||
|
observer = null;
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
interface VisibleRowsStore {
|
||||||
|
visibleRows: Set<string>;
|
||||||
|
addVisibleRow: (id: string) => void;
|
||||||
|
removeVisibleRow: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useVisibleRowsStore = create<VisibleRowsStore>((set) => ({
|
||||||
|
visibleRows: new Set(),
|
||||||
|
addVisibleRow: (id) => set((state) => ({ visibleRows: new Set(state.visibleRows).add(id) })),
|
||||||
|
removeVisibleRow: (id) =>
|
||||||
|
set((state) => {
|
||||||
|
const newSet = new Set(state.visibleRows);
|
||||||
|
newSet.delete(id);
|
||||||
|
return { visibleRows: newSet };
|
||||||
|
}),
|
||||||
|
}));
|
||||||
@@ -105,7 +105,7 @@ $timeline-color: color-mix(in srgb, transparent 60%, var(--background-color-over
|
|||||||
}
|
}
|
||||||
|
|
||||||
.delay {
|
.delay {
|
||||||
color: $ontime-delay-text;
|
color: $delay-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeOverview {
|
.timeOverview {
|
||||||
@@ -117,7 +117,7 @@ $timeline-color: color-mix(in srgb, transparent 60%, var(--background-color-over
|
|||||||
.cross {
|
.cross {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-decoration-color: $ontime-delay-text;
|
text-decoration-color: $delay-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.separeLeft {
|
.separeLeft {
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export function getUpcomingEvents(events: PlayableEvent[], selectedId: MaybeStri
|
|||||||
* Utility function calculates time to start
|
* Utility function calculates time to start
|
||||||
*/
|
*/
|
||||||
export function getTimeToStart(now: number, start: number, delay: number, offset: number): number {
|
export function getTimeToStart(now: number, start: number, delay: number, offset: number): number {
|
||||||
return start + delay - now + offset;
|
return start + delay - now - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TimelineLayout {
|
interface TimelineLayout {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.common.json",
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "ESNext",
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"dom.iterable",
|
"dom.iterable",
|
||||||
@@ -14,7 +13,21 @@
|
|||||||
],
|
],
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
"allowUnusedLabels": false,
|
"allowUnusedLabels": false,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime-electron",
|
"name": "ontime-electron",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.3",
|
||||||
"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",
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
*.tgz
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Ontime Resolver
|
|
||||||
|
|
||||||
Congratulations! You got this far into Ontime's rabbit hole and want to manage your installation.
|
|
||||||
|
|
||||||
The Resolver is an attempt to expose our ontime's api so it is easier to integrate with
|
|
||||||
|
|
||||||
## Links
|
|
||||||
- [Ontime's repository](https://github.com/cpvalente/ontime)
|
|
||||||
- [Ontime's documentation](https://docs.getontime.no/)
|
|
||||||
- [Ontime's website](https://getontime.no/)
|
|
||||||
|
|
||||||
## Sponsoring
|
|
||||||
You can help the development of this project or say thank you with a one time donation. \
|
|
||||||
See the [terms of donations](https://github.com/cpvalente/ontime/blob/master/SPONSOR.md)
|
|
||||||
|
|
||||||
[](https://github.com/sponsors/cpvalente)
|
|
||||||
[](https://www.buymeacoffee.com/cpvalente)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@getontime/resolver",
|
|
||||||
"version": "4.0.0-beta.4",
|
|
||||||
"type": "module",
|
|
||||||
"repository": "https://github.com/cpvalente/ontime",
|
|
||||||
"types": "./dist/main.d.ts",
|
|
||||||
"main": "./dist/main.js",
|
|
||||||
"description": "shared typings for ontime",
|
|
||||||
"scripts": {
|
|
||||||
"lint": "eslint . --quiet",
|
|
||||||
"prebuild": "pnpm rimraf ./dist",
|
|
||||||
"build": "tsup && pnpm rimraf ./dist/index.js",
|
|
||||||
"postbuild": "pnpm rimraf ./dist/index.d.ts"
|
|
||||||
},
|
|
||||||
"keywords": ["ontime", "resolver", "parser"],
|
|
||||||
"author": "",
|
|
||||||
"license": "AGPL-3.0-only",
|
|
||||||
"devDependencies": {
|
|
||||||
"@sprout2000/esbuild-copy-plugin": "^1.1.19",
|
|
||||||
"@typescript-eslint/parser": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"tsup": "^8.5.0",
|
|
||||||
"rimraf": "catalog:",
|
|
||||||
"typescript": "catalog:",
|
|
||||||
"ontime-types": "workspace:^4.0.0"
|
|
||||||
},
|
|
||||||
"files": ["dist"]
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// api
|
|
||||||
export { MessageTag, RefetchKey } from 'ontime-types';
|
|
||||||
export type { ApiAction, ApiActionTag, ApiResponse } from 'ontime-types';
|
|
||||||
export type { WsPacketToClient, WsPacketToServer } from 'ontime-types';
|
|
||||||
|
|
||||||
// stores
|
|
||||||
export type { RuntimeStore, TimerState, MessageState, RundownState, Offset } from 'ontime-types';
|
|
||||||
export { TimerPhase, Playback, runtimeStorePlaceholder, OffsetMode } from 'ontime-types';
|
|
||||||
|
|
||||||
// aux timer
|
|
||||||
export type { SimpleTimerState } from 'ontime-types';
|
|
||||||
export { SimplePlayback, SimpleDirection } from 'ontime-types';
|
|
||||||
|
|
||||||
// entries
|
|
||||||
export type { OntimeEvent, OntimeGroup, EntryCustomFields, CustomFields, Rundown } from 'ontime-types';
|
|
||||||
export { SupportedEntry, isOntimeEvent, isOntimeGroup, isOntimeDelay, isOntimeMilestone } from 'ontime-types';
|
|
||||||
|
|
||||||
// functions
|
|
||||||
export { isWsPacketToClient } from './websocket.js';
|
|
||||||
export type { SocketSender } from './websocket.js';
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { ApiAction, ApiActionTag, MessageTag, WsPacketToClient, WsPacketToServer } from 'ontime-types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper type for sending correct websocket messages to ontime
|
|
||||||
*/
|
|
||||||
export type SocketSender = <T extends MessageTag | ApiActionTag>(
|
|
||||||
tag: T,
|
|
||||||
payload: T extends MessageTag
|
|
||||||
? Pick<WsPacketToServer & { tag: T }, 'payload'>['payload']
|
|
||||||
: Pick<ApiAction & { tag: T }, 'payload'>['payload'],
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a soft type guard for WS packets
|
|
||||||
*/
|
|
||||||
export function isWsPacketToClient(data: unknown): data is WsPacketToClient {
|
|
||||||
return typeof data === 'object' && data !== null && 'tag' in data && 'payload' in data;
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.common.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "esnext",
|
|
||||||
"module": "preserve",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"allowUnusedLabels": false,
|
|
||||||
"removeComments": true,
|
|
||||||
"preserveConstEnums": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"declaration": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"sourceMap": true,
|
|
||||||
"baseUrl": "src",
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src",
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { defineConfig } from 'tsup';
|
|
||||||
import copyPlugin from '@sprout2000/esbuild-copy-plugin';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
clean: false, //we can't use clean as i dose so after the copy plugin runs
|
|
||||||
entry: ['src/main.ts'],
|
|
||||||
outDir: 'dist',
|
|
||||||
bundle: true,
|
|
||||||
|
|
||||||
dts: { resolve: true },
|
|
||||||
format: 'esm',
|
|
||||||
target: 'esnext',
|
|
||||||
platform: 'node',
|
|
||||||
esbuildPlugins: [
|
|
||||||
copyPlugin.copyPlugin({
|
|
||||||
src: './node_modules/ontime-types/dist',
|
|
||||||
dest: './dist',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "ontime-server",
|
"name": "ontime-server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.3",
|
||||||
"exports": "./src/index.js",
|
"exports": "./src/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@googleapis/sheets": "^5.0.5",
|
"@googleapis/sheets": "^5.0.5",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"ontime-utils": "workspace:*",
|
"ontime-utils": "workspace:*",
|
||||||
"osc-min": "2.1.2",
|
"osc-min": "2.1.2",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
|
"steno": "^4.0.2",
|
||||||
"ws": "^8.18.0",
|
"ws": "^8.18.0",
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
"prettier": "catalog:",
|
"prettier": "catalog:",
|
||||||
"server-timing": "^3.3.3",
|
"server-timing": "^3.3.3",
|
||||||
"shx": "^0.3.4",
|
"shx": "^0.3.4",
|
||||||
"ts-essentials": "catalog:",
|
"ts-essentials": "^10.0.3",
|
||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"vitest": "catalog:"
|
"vitest": "catalog:"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { TriggerDTO, TimerLifeCycle, AutomationDTO, Automation, ProjectRundowns } from 'ontime-types';
|
import { TriggerDTO, TimerLifeCycle, AutomationDTO, Automation, EntryId } from 'ontime-types';
|
||||||
|
|
||||||
import { makeOntimeEvent } from '../../rundown/__mocks__/rundown.mocks.js';
|
import { makeRundown } from '../../rundown/__mocks__/rundown.mocks.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addTrigger,
|
addTrigger,
|
||||||
@@ -203,29 +203,10 @@ describe('deleteAutomation()', () => {
|
|||||||
const automations = getAutomations();
|
const automations = getAutomations();
|
||||||
expect(Object.keys(automations).length).toEqual(1);
|
expect(Object.keys(automations).length).toEqual(1);
|
||||||
|
|
||||||
const projectRundowns: ProjectRundowns = {
|
const rundown = makeRundown({});
|
||||||
'rundown-1': {
|
const timedEventOrder: EntryId[] = [];
|
||||||
id: 'rundown-1',
|
|
||||||
title: 'Rundown 1',
|
await deleteAutomation(rundown, timedEventOrder, Object.keys(automations)[0]);
|
||||||
order: ['1'],
|
|
||||||
flatOrder: ['1'],
|
|
||||||
entries: {
|
|
||||||
'1': makeOntimeEvent({
|
|
||||||
id: '1',
|
|
||||||
triggers: [
|
|
||||||
{
|
|
||||||
id: 'trigger-1',
|
|
||||||
title: 'Trigger 1',
|
|
||||||
trigger: TimerLifeCycle.onClock,
|
|
||||||
automationId: 'test-automation',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
revision: 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
await deleteAutomation(projectRundowns, Object.keys(automations)[0]);
|
|
||||||
const removed = getAutomations();
|
const removed = getAutomations();
|
||||||
expect(Object.keys(removed).length).toEqual(0);
|
expect(Object.keys(removed).length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { ProjectRundowns, TimerLifeCycle } from 'ontime-types';
|
import { TimerLifeCycle } from 'ontime-types';
|
||||||
|
import { makeOntimeEvent, makeRundown } from '../../rundown/__mocks__/rundown.mocks.js';
|
||||||
import { makeOntimeEvent } from '../../rundown/__mocks__/rundown.mocks.js';
|
|
||||||
|
|
||||||
import { isAutomationUsed, parseTemplateNested, stringToOSCArgs } from '../automation.utils.js';
|
import { isAutomationUsed, parseTemplateNested, stringToOSCArgs } from '../automation.utils.js';
|
||||||
|
|
||||||
describe('parseTemplateNested()', () => {
|
describe('parseTemplateNested()', () => {
|
||||||
@@ -252,12 +250,7 @@ describe('test stringToOSCArgs()', () => {
|
|||||||
|
|
||||||
describe('isAutomationUsed()', () => {
|
describe('isAutomationUsed()', () => {
|
||||||
it('returns the first event which uses an automation', () => {
|
it('returns the first event which uses an automation', () => {
|
||||||
const projectRundowns: ProjectRundowns = {
|
const rundown = makeRundown({
|
||||||
'rundown-1': {
|
|
||||||
id: 'rundown-1',
|
|
||||||
title: 'Rundown 1',
|
|
||||||
order: ['1'],
|
|
||||||
flatOrder: ['1'],
|
|
||||||
entries: {
|
entries: {
|
||||||
'1': makeOntimeEvent({
|
'1': makeOntimeEvent({
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -271,71 +264,17 @@ describe('isAutomationUsed()', () => {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
revision: 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const automationId = 'test-automation';
|
|
||||||
|
|
||||||
const result = isAutomationUsed(projectRundowns, automationId);
|
|
||||||
expect(result).toStrictEqual(['Rundown 1', '1']);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('finds usages in any rundown', () => {
|
const timedEventOrder = ['1'];
|
||||||
const projectRundowns: ProjectRundowns = {
|
const automationId = 'test-automation';
|
||||||
'rundown-1': {
|
|
||||||
id: 'rundown-1',
|
|
||||||
title: 'Rundown 1',
|
|
||||||
order: ['1'],
|
|
||||||
flatOrder: ['1'],
|
|
||||||
entries: {
|
|
||||||
'1': makeOntimeEvent({
|
|
||||||
id: '1',
|
|
||||||
triggers: [
|
|
||||||
{
|
|
||||||
id: 'trigger-1',
|
|
||||||
title: 'Trigger 1',
|
|
||||||
trigger: TimerLifeCycle.onClock,
|
|
||||||
automationId: 'test-automation',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
revision: 1,
|
|
||||||
},
|
|
||||||
'rundown-2': {
|
|
||||||
id: 'rundown-2',
|
|
||||||
title: 'Rundown 2',
|
|
||||||
order: ['1'],
|
|
||||||
flatOrder: ['1'],
|
|
||||||
entries: {
|
|
||||||
'1': makeOntimeEvent({
|
|
||||||
id: '1',
|
|
||||||
triggers: [
|
|
||||||
{
|
|
||||||
id: 'trigger-1',
|
|
||||||
title: 'Trigger 1',
|
|
||||||
trigger: TimerLifeCycle.onClock,
|
|
||||||
automationId: 'in-the-second-rundown',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
revision: 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const automationId = 'in-the-second-rundown';
|
|
||||||
|
|
||||||
const result = isAutomationUsed(projectRundowns, automationId);
|
const result = isAutomationUsed(rundown, timedEventOrder, automationId);
|
||||||
expect(result).toStrictEqual(['Rundown 2', '1']);
|
expect(result).toBe('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns returns undefined if there are no matches', () => {
|
it('returns returns undefined if there are no matches', () => {
|
||||||
const projectRundowns: ProjectRundowns = {
|
const rundown = makeRundown({
|
||||||
'rundown-1': {
|
|
||||||
id: 'rundown-1',
|
|
||||||
title: 'Rundown 1',
|
|
||||||
order: ['1'],
|
|
||||||
flatOrder: ['1'],
|
|
||||||
entries: {
|
entries: {
|
||||||
'1': makeOntimeEvent({
|
'1': makeOntimeEvent({
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -349,12 +288,12 @@ describe('isAutomationUsed()', () => {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
revision: 1,
|
});
|
||||||
},
|
|
||||||
};
|
const timedEventOrder = ['1'];
|
||||||
const automationId = 'does-not-exist';
|
const automationId = 'does-not-exist';
|
||||||
|
|
||||||
const result = isAutomationUsed(projectRundowns, automationId);
|
const result = isAutomationUsed(rundown, timedEventOrder, automationId);
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { Automation, AutomationSettings, ErrorResponse, Trigger } from 'ontime-t
|
|||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
|
|
||||||
import { oscServer } from '../../adapters/OscAdapter.js';
|
import { oscServer } from '../../adapters/OscAdapter.js';
|
||||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
|
||||||
|
import { getCurrentRundown, getRundownMetadata } from '../rundown/rundown.dao.js';
|
||||||
|
|
||||||
import * as automationDao from './automation.dao.js';
|
import * as automationDao from './automation.dao.js';
|
||||||
import * as automationService from './automation.service.js';
|
import * as automationService from './automation.service.js';
|
||||||
@@ -107,8 +108,10 @@ export async function editAutomation(req: Request, res: Response<Automation | Er
|
|||||||
|
|
||||||
export async function deleteAutomation(req: Request, res: Response<void | ErrorResponse>) {
|
export async function deleteAutomation(req: Request, res: Response<void | ErrorResponse>) {
|
||||||
try {
|
try {
|
||||||
const projectRundowns = getDataProvider().getProjectRundowns();
|
const rundown = getCurrentRundown();
|
||||||
await automationDao.deleteAutomation(projectRundowns, req.params.id);
|
const { timedEventOrder } = getRundownMetadata();
|
||||||
|
|
||||||
|
await automationDao.deleteAutomation(rundown, timedEventOrder, req.params.id);
|
||||||
res.status(204).send();
|
res.status(204).send();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = getErrorMessage(error);
|
const message = getErrorMessage(error);
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import type {
|
|||||||
Automation,
|
Automation,
|
||||||
AutomationDTO,
|
AutomationDTO,
|
||||||
AutomationSettings,
|
AutomationSettings,
|
||||||
|
EntryId,
|
||||||
NormalisedAutomation,
|
NormalisedAutomation,
|
||||||
ProjectRundowns,
|
Rundown,
|
||||||
Trigger,
|
Trigger,
|
||||||
TriggerDTO,
|
TriggerDTO,
|
||||||
} from 'ontime-types';
|
} from 'ontime-types';
|
||||||
@@ -135,15 +136,15 @@ export async function editAutomation(id: string, newAutomation: AutomationDTO):
|
|||||||
/**
|
/**
|
||||||
* Deletes a automation given its ID
|
* Deletes a automation given its ID
|
||||||
*/
|
*/
|
||||||
export async function deleteAutomation(projectRundowns: ProjectRundowns, automationId: string): Promise<void> {
|
export async function deleteAutomation(rundown: Rundown, timedEventOrder: EntryId[], id: string): Promise<void> {
|
||||||
const automations = getAutomations();
|
const automations = getAutomations();
|
||||||
// ignore request if automation does not exist
|
// ignore request if automation does not exist
|
||||||
if (!Object.hasOwn(automations, automationId)) {
|
if (!Object.hasOwn(automations, id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent deleting a automation that is in use in triggers
|
// prevent deleting a automation that is in use in triggers
|
||||||
const triggers = getAutomationTriggers().filter((trigger) => trigger.automationId === automationId);
|
const triggers = getAutomationTriggers().filter((trigger) => trigger.automationId === id);
|
||||||
if (triggers.length) {
|
if (triggers.length) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unable to delete automation used in trigger ${triggers[0].title}${triggers.length > 1 ? ` and ${triggers.length - 1} more` : ''}`,
|
`Unable to delete automation used in trigger ${triggers[0].title}${triggers.length > 1 ? ` and ${triggers.length - 1} more` : ''}`,
|
||||||
@@ -151,12 +152,12 @@ export async function deleteAutomation(projectRundowns: ProjectRundowns, automat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prevent deleting a automation that is in use in events
|
// prevent deleting a automation that is in use in events
|
||||||
const isInUse = isAutomationUsed(projectRundowns, automationId);
|
const isInUse = isAutomationUsed(rundown, timedEventOrder, id);
|
||||||
if (isInUse) {
|
if (isInUse) {
|
||||||
throw new Error(`Unable to delete automation used in rundown: ${isInUse[0]}, in event with ID: ${isInUse[1]}`);
|
throw new Error(`Unable to delete automation used in event with ID ${isInUse}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete automations[automationId];
|
delete automations[id];
|
||||||
await saveChanges({ automations });
|
await saveChanges({ automations });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
import {
|
import { EntryId, FilterRule, isOntimeEvent, MaybeNumber, OntimeAction, ontimeActionKeyValues, Rundown } from 'ontime-types';
|
||||||
EntryId,
|
|
||||||
FilterRule,
|
|
||||||
isOntimeEvent,
|
|
||||||
MaybeNumber,
|
|
||||||
OntimeAction,
|
|
||||||
ontimeActionKeyValues,
|
|
||||||
ProjectRundowns,
|
|
||||||
RundownEntries,
|
|
||||||
} from 'ontime-types';
|
|
||||||
import { millisToString, removeLeadingZero, splitWhitespace, getPropertyFromPath } from 'ontime-utils';
|
import { millisToString, removeLeadingZero, splitWhitespace, getPropertyFromPath } from 'ontime-utils';
|
||||||
import type { OscArgOrArrayInput, OscArgInput } from 'osc-min';
|
import type { OscArgOrArrayInput, OscArgInput } from 'osc-min';
|
||||||
|
|
||||||
@@ -207,40 +198,22 @@ export function isBooleanEquals(a: boolean, b: string): boolean {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks is an automation is used in a rundown
|
* Checks is an automation is used in a rundown
|
||||||
*/
|
* TODO(v4): this currently only checks the current rundown, we will need to check all rundowns in the future
|
||||||
function isAutomationUsedInRundown(
|
|
||||||
entries: RundownEntries,
|
|
||||||
flatOrder: EntryId[],
|
|
||||||
automationId: string,
|
|
||||||
): EntryId | undefined {
|
|
||||||
for (let i = 0; i < flatOrder.length; i++) {
|
|
||||||
const eventId = flatOrder[i];
|
|
||||||
const entry = entries[eventId];
|
|
||||||
|
|
||||||
// only ontime events can contain triggers
|
|
||||||
if (isOntimeEvent(entry) && entry.triggers) {
|
|
||||||
for (const trigger of entry.triggers) {
|
|
||||||
if (trigger.automationId === automationId) {
|
|
||||||
return entry.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an automation is used in any of the project rundowns
|
|
||||||
*/
|
*/
|
||||||
export function isAutomationUsed(
|
export function isAutomationUsed(
|
||||||
projectRundowns: ProjectRundowns,
|
rundown: Rundown,
|
||||||
|
timedEventOrder: EntryId[],
|
||||||
automationId: string,
|
automationId: string,
|
||||||
): [string, EntryId] | undefined {
|
): EntryId | undefined {
|
||||||
for (const rundownId in projectRundowns) {
|
for (let i = 0; i < timedEventOrder.length; i++) {
|
||||||
const rundown = projectRundowns[rundownId];
|
const eventId = timedEventOrder[i];
|
||||||
const usedInEvent = isAutomationUsedInRundown(rundown.entries, rundown.flatOrder, automationId);
|
const event = rundown.entries[eventId];
|
||||||
|
if (isOntimeEvent(event) && event.triggers) {
|
||||||
if (usedInEvent) {
|
for (const trigger of event.triggers) {
|
||||||
return [rundown.title, usedInEvent];
|
if (trigger.automationId === automationId) {
|
||||||
|
return eventId;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export async function patchPartialProjectFile(req: Request, res: Response<Databa
|
|||||||
};
|
};
|
||||||
|
|
||||||
const newData = await projectService.patchCurrentProject(patchDb);
|
const newData = await projectService.patchCurrentProject(patchDb);
|
||||||
|
|
||||||
res.status(200).send(newData);
|
res.status(200).send(newData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = getErrorMessage(error);
|
const message = getErrorMessage(error);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
ApiActionTag,
|
ApiAction,
|
||||||
MessageState,
|
MessageState,
|
||||||
OffsetMode,
|
OffsetMode,
|
||||||
OntimeEvent,
|
OntimeEvent,
|
||||||
@@ -30,7 +30,7 @@ let lastRequest: Date | null = null;
|
|||||||
|
|
||||||
export function dispatchFromAdapter(tag: string, payload: unknown, _source?: 'osc' | 'ws' | 'http') {
|
export function dispatchFromAdapter(tag: string, payload: unknown, _source?: 'osc' | 'ws' | 'http') {
|
||||||
const action = tag.toLowerCase();
|
const action = tag.toLowerCase();
|
||||||
const handler = actionHandlers[action as ApiActionTag];
|
const handler = actionHandlers[action as ApiAction];
|
||||||
lastRequest = new Date();
|
lastRequest = new Date();
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
@@ -46,7 +46,7 @@ export function getLastRequest() {
|
|||||||
|
|
||||||
type ActionHandler = (payload: unknown) => { payload: unknown };
|
type ActionHandler = (payload: unknown) => { payload: unknown };
|
||||||
|
|
||||||
const actionHandlers: Record<ApiActionTag, ActionHandler> = {
|
const actionHandlers: Record<ApiAction, ActionHandler> = {
|
||||||
/* General */
|
/* General */
|
||||||
version: () => ({ payload: ONTIME_VERSION }),
|
version: () => ({ payload: ONTIME_VERSION }),
|
||||||
poll: () => ({
|
poll: () => ({
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { dayInMs, MILLIS_PER_HOUR, millisToString } from 'ontime-utils';
|
import { dayInMs, millisToString } from 'ontime-utils';
|
||||||
import { EndAction, Playback, TimeStrategy, TimerPhase, TimerType } from 'ontime-types';
|
import { EndAction, Playback, TimeStrategy, TimerPhase, TimerType } from 'ontime-types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
findDayOffset,
|
|
||||||
getCurrent,
|
getCurrent,
|
||||||
getExpectedFinish,
|
getExpectedFinish,
|
||||||
getRuntimeOffset,
|
getRuntimeOffset,
|
||||||
@@ -727,7 +726,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
eventNow: {
|
eventNow: {
|
||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 100,
|
timeStart: 100,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 150,
|
startedAt: 150,
|
||||||
@@ -740,10 +738,7 @@ describe('getRuntimeOffset()', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 150,
|
actualStart: 150,
|
||||||
plannedStart: 100,
|
plannedStart: 100,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
clock: 150,
|
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute } = getRuntimeOffset(state);
|
const { absolute } = getRuntimeOffset(state);
|
||||||
@@ -755,7 +750,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
eventNow: {
|
eventNow: {
|
||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 100,
|
timeStart: 100,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 150, // we started 50ms delayed
|
startedAt: 150, // we started 50ms delayed
|
||||||
@@ -768,9 +762,7 @@ describe('getRuntimeOffset()', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 150,
|
actualStart: 150,
|
||||||
plannedStart: 100,
|
plannedStart: 100,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute } = getRuntimeOffset(state);
|
const { absolute } = getRuntimeOffset(state);
|
||||||
@@ -783,7 +775,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 100,
|
timeStart: 100,
|
||||||
timeEnd: 140,
|
timeEnd: 140,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 100, // we started ontime
|
startedAt: 100, // we started ontime
|
||||||
@@ -796,9 +787,7 @@ describe('getRuntimeOffset()', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 100,
|
actualStart: 100,
|
||||||
plannedStart: 100,
|
plannedStart: 100,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute } = getRuntimeOffset(state);
|
const { absolute } = getRuntimeOffset(state);
|
||||||
@@ -811,7 +800,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 100,
|
timeStart: 100,
|
||||||
timeEnd: 150,
|
timeEnd: 150,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
clock: 150,
|
clock: 150,
|
||||||
timer: {
|
timer: {
|
||||||
@@ -825,9 +813,7 @@ describe('getRuntimeOffset()', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 100,
|
actualStart: 100,
|
||||||
plannedStart: 100,
|
plannedStart: 100,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute } = getRuntimeOffset(state);
|
const { absolute } = getRuntimeOffset(state);
|
||||||
@@ -844,7 +830,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
duration: 3600000,
|
duration: 3600000,
|
||||||
timeStrategy: 'lock-duration',
|
timeStrategy: 'lock-duration',
|
||||||
linkStart: false,
|
linkStart: false,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
rundown: {
|
rundown: {
|
||||||
selectedEventIndex: 0,
|
selectedEventIndex: 0,
|
||||||
@@ -852,7 +837,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
plannedStart: 77400000,
|
plannedStart: 77400000,
|
||||||
plannedEnd: 84600000,
|
plannedEnd: 84600000,
|
||||||
actualStart: null,
|
actualStart: null,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
absolute: -77400000,
|
absolute: -77400000,
|
||||||
@@ -868,7 +852,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
startedAt: null,
|
startedAt: null,
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
@@ -891,7 +874,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
endAction: EndAction.None,
|
endAction: EndAction.None,
|
||||||
timerType: TimerType.CountDown,
|
timerType: TimerType.CountDown,
|
||||||
countToEnd: true,
|
countToEnd: true,
|
||||||
dayOffset: 0,
|
|
||||||
skip: false,
|
skip: false,
|
||||||
note: '',
|
note: '',
|
||||||
colour: '',
|
colour: '',
|
||||||
@@ -908,7 +890,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
plannedStart: 77400000, // 21:30:00
|
plannedStart: 77400000, // 21:30:00
|
||||||
plannedEnd: 81000000, // 22:30:00
|
plannedEnd: 81000000, // 22:30:00
|
||||||
actualStart: 78000000, // 21:40:00
|
actualStart: 78000000, // 21:40:00
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
absolute: 0,
|
absolute: 0,
|
||||||
@@ -924,7 +905,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
startedAt: 78000000,
|
startedAt: 78000000,
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
@@ -942,7 +922,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
timeStart: 77400000, // 21:30:00
|
timeStart: 77400000, // 21:30:00
|
||||||
timeEnd: 81000000, // 22:30:00
|
timeEnd: 81000000, // 22:30:00
|
||||||
duration: 3600000, // 01:00:00
|
duration: 3600000, // 01:00:00
|
||||||
dayOffset: 0,
|
|
||||||
timeStrategy: TimeStrategy.LockEnd,
|
timeStrategy: TimeStrategy.LockEnd,
|
||||||
linkStart: false,
|
linkStart: false,
|
||||||
endAction: EndAction.None,
|
endAction: EndAction.None,
|
||||||
@@ -964,7 +943,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
plannedStart: 77400000, // 21:30:00
|
plannedStart: 77400000, // 21:30:00
|
||||||
plannedEnd: 81000000, // 22:30:00
|
plannedEnd: 81000000, // 22:30:00
|
||||||
actualStart: 78000000, // 21:40:00
|
actualStart: 78000000, // 21:40:00
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
absolute: 0,
|
absolute: 0,
|
||||||
@@ -980,7 +958,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
startedAt: 78000000,
|
startedAt: 78000000,
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
@@ -1001,7 +978,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
endAction: EndAction.None,
|
endAction: EndAction.None,
|
||||||
timerType: TimerType.CountDown,
|
timerType: TimerType.CountDown,
|
||||||
countToEnd: true,
|
countToEnd: true,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
rundown: {
|
rundown: {
|
||||||
selectedEventIndex: 0,
|
selectedEventIndex: 0,
|
||||||
@@ -1009,7 +985,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
plannedStart: 77400000, // 21:30:00
|
plannedStart: 77400000, // 21:30:00
|
||||||
plannedEnd: 81000000, // 22:30:00
|
plannedEnd: 81000000, // 22:30:00
|
||||||
actualStart: 82000000, // 22:46:40 <--- started now
|
actualStart: 82000000, // 22:46:40 <--- started now
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
absolute: 0,
|
absolute: 0,
|
||||||
@@ -1025,7 +1000,6 @@ describe('getRuntimeOffset()', () => {
|
|||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
startedAt: 82000000, // <--- started now
|
startedAt: 82000000, // <--- started now
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
@@ -1043,7 +1017,6 @@ describe('getRuntimeOffset() relative', () => {
|
|||||||
eventNow: {
|
eventNow: {
|
||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 150,
|
timeStart: 150,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 150,
|
startedAt: 150,
|
||||||
@@ -1056,9 +1029,7 @@ describe('getRuntimeOffset() relative', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 150,
|
actualStart: 150,
|
||||||
plannedStart: 150,
|
plannedStart: 150,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute, relative } = getRuntimeOffset(state);
|
const { absolute, relative } = getRuntimeOffset(state);
|
||||||
@@ -1070,7 +1041,6 @@ describe('getRuntimeOffset() relative', () => {
|
|||||||
eventNow: {
|
eventNow: {
|
||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 100,
|
timeStart: 100,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 150,
|
startedAt: 150,
|
||||||
@@ -1083,9 +1053,7 @@ describe('getRuntimeOffset() relative', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 150,
|
actualStart: 150,
|
||||||
plannedStart: 100,
|
plannedStart: 100,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute, relative } = getRuntimeOffset(state);
|
const { absolute, relative } = getRuntimeOffset(state);
|
||||||
@@ -1097,7 +1065,6 @@ describe('getRuntimeOffset() relative', () => {
|
|||||||
eventNow: {
|
eventNow: {
|
||||||
id: '1',
|
id: '1',
|
||||||
timeStart: 150,
|
timeStart: 150,
|
||||||
dayOffset: 0,
|
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 100,
|
startedAt: 100,
|
||||||
@@ -1110,9 +1077,7 @@ describe('getRuntimeOffset() relative', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 100,
|
actualStart: 100,
|
||||||
plannedStart: 150,
|
plannedStart: 150,
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
_startDayOffset: 0,
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const { absolute, relative } = getRuntimeOffset(state);
|
const { absolute, relative } = getRuntimeOffset(state);
|
||||||
@@ -1293,21 +1258,3 @@ describe('getTimerPhase()', () => {
|
|||||||
expect(phase).toBe(TimerPhase.Pending);
|
expect(phase).toBe(TimerPhase.Pending);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('findDay()', () => {
|
|
||||||
test('finds dayOffset', () => {
|
|
||||||
//both have 1 hour offset but the clock are on different days
|
|
||||||
expect(findDayOffset(0, 23 * MILLIS_PER_HOUR)).toBe(-1); // -> 23
|
|
||||||
expect(findDayOffset(0, 13 * MILLIS_PER_HOUR)).toBe(-1); // -> 13
|
|
||||||
expect(findDayOffset(0, 12 * MILLIS_PER_HOUR)).toBe(-1); // -> 12
|
|
||||||
expect(findDayOffset(0, 11 * MILLIS_PER_HOUR)).toBe(0); // -> 11
|
|
||||||
expect(findDayOffset(1 * MILLIS_PER_HOUR, 0)).toBe(0); // -> -1
|
|
||||||
|
|
||||||
//both have 1 hour offset but the clock are on different days
|
|
||||||
expect(findDayOffset(23 * MILLIS_PER_HOUR, 0)).toBe(1); // -> -23
|
|
||||||
expect(findDayOffset(13 * MILLIS_PER_HOUR, 0)).toBe(1); // -> -13
|
|
||||||
expect(findDayOffset(12 * MILLIS_PER_HOUR, 0)).toBe(0); // -> -12
|
|
||||||
expect(findDayOffset(11 * MILLIS_PER_HOUR, 0)).toBe(0); // -> -11
|
|
||||||
expect(findDayOffset(22 * MILLIS_PER_HOUR, 23 * MILLIS_PER_HOUR)).toBe(0); // -> 1
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -323,14 +323,11 @@ export async function patchCurrentProject(data: Partial<DatabaseModel>) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The user may have multiple rundowns
|
* The user may have multiple rundowns
|
||||||
* so attempt to get the one that was used last
|
* We currently ignore all other rundowns
|
||||||
* otherwise just pick the first
|
|
||||||
*/
|
*/
|
||||||
const last = await getLastLoaded();
|
const firstRundown = getFirstRundown(result);
|
||||||
const rundownToLoad =
|
|
||||||
last?.rundownId && last.rundownId in result ? result[last.rundownId] : getFirstRundown(result);
|
|
||||||
|
|
||||||
await initRundown(rundownToLoad, customFields, true);
|
await initRundown(firstRundown, customFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedData = await getDataProvider().getData();
|
const updatedData = await getDataProvider().getData();
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ describe('isRestorePoint()', () => {
|
|||||||
addedTime: 2,
|
addedTime: 2,
|
||||||
pausedAt: 3,
|
pausedAt: 3,
|
||||||
firstStart: 1,
|
firstStart: 1,
|
||||||
startEpoch: 1,
|
|
||||||
};
|
};
|
||||||
expect(isRestorePoint(restorePoint)).toBe(true);
|
expect(isRestorePoint(restorePoint)).toBe(true);
|
||||||
|
|
||||||
@@ -23,7 +22,6 @@ describe('isRestorePoint()', () => {
|
|||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
firstStart: 1,
|
firstStart: 1,
|
||||||
startEpoch: 1,
|
|
||||||
};
|
};
|
||||||
expect(isRestorePoint(restorePoint)).toBe(true);
|
expect(isRestorePoint(restorePoint)).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -37,7 +35,6 @@ describe('isRestorePoint()', () => {
|
|||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
groupStartAt: 10,
|
groupStartAt: 10,
|
||||||
startEpoch: 1,
|
|
||||||
};
|
};
|
||||||
expect(isRestorePoint(restorePoint)).toBe(false);
|
expect(isRestorePoint(restorePoint)).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -59,7 +56,6 @@ describe('isRestorePoint()', () => {
|
|||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
groupStartAt: 10,
|
groupStartAt: 10,
|
||||||
startEpoch: 1,
|
|
||||||
};
|
};
|
||||||
expect(isRestorePoint(restorePoint)).toBe(false);
|
expect(isRestorePoint(restorePoint)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ describe('restoreService', () => {
|
|||||||
addedTime: 5678,
|
addedTime: 5678,
|
||||||
pausedAt: 9087,
|
pausedAt: 9087,
|
||||||
firstStart: 1234,
|
firstStart: 1234,
|
||||||
startEpoch: 1234,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockRead = vi.fn().mockResolvedValue(expected);
|
const mockRead = vi.fn().mockResolvedValue(expected);
|
||||||
@@ -34,7 +33,6 @@ describe('restoreService', () => {
|
|||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
firstStart: 1234,
|
firstStart: 1234,
|
||||||
startEpoch: 1234,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockRead = vi.fn().mockResolvedValue(expected);
|
const mockRead = vi.fn().mockResolvedValue(expected);
|
||||||
@@ -81,7 +79,6 @@ describe('restoreService', () => {
|
|||||||
addedTime: 1234,
|
addedTime: 1234,
|
||||||
pausedAt: 1234,
|
pausedAt: 1234,
|
||||||
firstStart: 1234,
|
firstStart: 1234,
|
||||||
startEpoch: 1234,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockWrite = vi.fn().mockResolvedValue(undefined);
|
const mockWrite = vi.fn().mockResolvedValue(undefined);
|
||||||
@@ -98,7 +95,6 @@ describe('restoreService', () => {
|
|||||||
addedTime: 5678,
|
addedTime: 5678,
|
||||||
pausedAt: 5678,
|
pausedAt: 5678,
|
||||||
firstStart: 5678,
|
firstStart: 5678,
|
||||||
startEpoch: 5678,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockWrite = vi.fn().mockRejectedValue(new Error('Write failed'));
|
const mockWrite = vi.fn().mockRejectedValue(new Error('Write failed'));
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export function isRestorePoint(restorePoint: unknown): restorePoint is RestorePo
|
|||||||
'addedTime',
|
'addedTime',
|
||||||
'pausedAt',
|
'pausedAt',
|
||||||
'firstStart',
|
'firstStart',
|
||||||
'startEpoch',
|
|
||||||
])
|
])
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
@@ -50,9 +49,5 @@ export function isRestorePoint(restorePoint: unknown): restorePoint is RestorePo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is.number(restorePoint.startEpoch) && restorePoint.startEpoch !== null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,4 @@ export type RestorePoint = {
|
|||||||
addedTime: number;
|
addedTime: number;
|
||||||
pausedAt: MaybeNumber;
|
pausedAt: MaybeNumber;
|
||||||
firstStart: MaybeNumber;
|
firstStart: MaybeNumber;
|
||||||
startEpoch: MaybeNumber;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -743,7 +743,6 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
|||||||
addedTime: state.timer.addedTime,
|
addedTime: state.timer.addedTime,
|
||||||
pausedAt: state._timer.pausedAt,
|
pausedAt: state._timer.pausedAt,
|
||||||
firstStart: state.rundown.actualStart,
|
firstStart: state.rundown.actualStart,
|
||||||
startEpoch: state._startEpoch,
|
|
||||||
})
|
})
|
||||||
.catch((_e) => {
|
.catch((_e) => {
|
||||||
//we don't do anything with the error here
|
//we don't do anything with the error here
|
||||||
|
|||||||
@@ -412,7 +412,6 @@ export async function upload(sheetId: string, options: ImportMap) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
|
||||||
// update the corresponding row with event data
|
// update the corresponding row with event data
|
||||||
sheetOrder.forEach((entryId, index) => {
|
sheetOrder.forEach((entryId, index) => {
|
||||||
const isGroupEnd = entryId.startsWith('group-end-');
|
const isGroupEnd = entryId.startsWith('group-end-');
|
||||||
@@ -422,9 +421,6 @@ export async function upload(sheetId: string, options: ImportMap) {
|
|||||||
: structuredClone(rundown.entries[id]);
|
: structuredClone(rundown.entries[id]);
|
||||||
updateRundown.push(cellRequestFromEvent(entry, index, worksheetId, sheetMetadata));
|
updateRundown.push(cellRequestFromEvent(entry, index, worksheetId, sheetMetadata));
|
||||||
});
|
});
|
||||||
} catch (e) {
|
|
||||||
throw new Error(`Sheet write failed to correctly parse rundown: ${e}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const writeResponse = await sheets({ version: 'v4', auth: currentAuthClient }).spreadsheets.batchUpdate({
|
const writeResponse = await sheets({ version: 'v4', auth: currentAuthClient }).spreadsheets.batchUpdate({
|
||||||
spreadsheetId: sheetId,
|
spreadsheetId: sheetId,
|
||||||
|
|||||||
@@ -154,6 +154,12 @@ function getCellData(key: OntimeEntryCommonKeys | 'blank', entry: OntimeEntry) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we need to flatten the milestones
|
||||||
|
if (key.startsWith('custom')) {
|
||||||
|
const customKey = key.split(':')[1];
|
||||||
|
return { userEnteredValue: { stringValue: entry.custom[customKey] } };
|
||||||
|
}
|
||||||
|
|
||||||
// we need to remap the event type to timer type in the case of groups and milestones
|
// we need to remap the event type to timer type in the case of groups and milestones
|
||||||
if (key === 'timerType') {
|
if (key === 'timerType') {
|
||||||
if (isOntimeGroup(entry))
|
if (isOntimeGroup(entry))
|
||||||
@@ -162,17 +168,6 @@ function getCellData(key: OntimeEntryCommonKeys | 'blank', entry: OntimeEntry) {
|
|||||||
return { userEnteredValue: { stringValue: entry.timerType } };
|
return { userEnteredValue: { stringValue: entry.timerType } };
|
||||||
}
|
}
|
||||||
|
|
||||||
// all other data is not relevant for the group end entry
|
|
||||||
if (entry.id.startsWith('group-end')) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to flatten the milestones
|
|
||||||
if (key.startsWith('custom')) {
|
|
||||||
const customKey = key.split(':')[1];
|
|
||||||
return { userEnteredValue: { stringValue: entry.custom[customKey] } };
|
|
||||||
}
|
|
||||||
|
|
||||||
// typescript cannot guarantee that the key exists for every entry
|
// typescript cannot guarantee that the key exists for every entry
|
||||||
// so we check for the key existence and assert the type
|
// so we check for the key existence and assert the type
|
||||||
if (!(key in entry)) return {};
|
if (!(key in entry)) return {};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { MaybeNumber, TimerPhase } from 'ontime-types';
|
import { MaybeNumber, TimerPhase } from 'ontime-types';
|
||||||
import { dayInMs, isPlaybackActive, MILLIS_PER_HOUR } from 'ontime-utils';
|
import { dayInMs, isPlaybackActive } from 'ontime-utils';
|
||||||
|
|
||||||
import type { RuntimeState } from '../stores/runtimeState.js';
|
import type { RuntimeState } from '../stores/runtimeState.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,14 +113,14 @@ export function skippedOutOfEvent(state: RuntimeState, previousTime: number, ski
|
|||||||
* Negative offset is under time / ahead of schedule
|
* Negative offset is under time / ahead of schedule
|
||||||
*/
|
*/
|
||||||
export function getRuntimeOffset(state: RuntimeState): { absolute: number; relative: number } {
|
export function getRuntimeOffset(state: RuntimeState): { absolute: number; relative: number } {
|
||||||
const { eventNow, clock, _startDayOffset } = state;
|
const { eventNow, clock } = state;
|
||||||
const { addedTime, current, startedAt } = state.timer;
|
const { addedTime, current, startedAt } = state.timer;
|
||||||
// nothing to calculate if there are no loaded events or if we havent started
|
// nothing to calculate if there are no loaded events or if we havent started
|
||||||
if (eventNow === null || startedAt === null || _startDayOffset === null) {
|
if (eventNow === null || startedAt === null) {
|
||||||
return { absolute: 0, relative: 0 };
|
return { absolute: 0, relative: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { countToEnd, timeStart, dayOffset } = eventNow;
|
const { countToEnd, timeStart } = eventNow;
|
||||||
const { plannedStart, actualStart } = state.rundown;
|
const { plannedStart, actualStart } = state.rundown;
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-labels -- dev code path
|
// eslint-disable-next-line no-unused-labels -- dev code path
|
||||||
@@ -132,8 +131,8 @@ export function getRuntimeOffset(state: RuntimeState): { absolute: number; relat
|
|||||||
if (actualStart === null) throw new Error('timerUtils.getRuntimeOffset: state.rundown.plannedStart must be set');
|
if (actualStart === null) throw new Error('timerUtils.getRuntimeOffset: state.rundown.plannedStart must be set');
|
||||||
}
|
}
|
||||||
|
|
||||||
// difference between planned event start and actual event start (will be positive if we started behind)
|
// difference between planned event start and actual event start (will be positive if we stared behind )
|
||||||
const eventStartOffset = startedAt + _startDayOffset * dayInMs - (timeStart + dayOffset * dayInMs);
|
const eventStartOffset = startedAt - timeStart;
|
||||||
|
|
||||||
// how long has the event been running over (is a negative number when in over timer so inverted before adding to offset)
|
// how long has the event been running over (is a negative number when in over timer so inverted before adding to offset)
|
||||||
const overtime = Math.abs(Math.min(current, 0));
|
const overtime = Math.abs(Math.min(current, 0));
|
||||||
@@ -141,11 +140,10 @@ export function getRuntimeOffset(state: RuntimeState): { absolute: number; relat
|
|||||||
// time the playback was paused, the different from now to when we paused is added to the offset TODO: brakes when crossing midnight
|
// time the playback was paused, the different from now to when we paused is added to the offset TODO: brakes when crossing midnight
|
||||||
const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt;
|
const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt;
|
||||||
|
|
||||||
// absolute offset is difference between schedule and playback time
|
|
||||||
const absolute = eventStartOffset + overtime + pausedTime + addedTime;
|
const absolute = eventStartOffset + overtime + pausedTime + addedTime;
|
||||||
|
|
||||||
// the relative offset is the same as the absolute but adjusted relative to the actual start time
|
// the relative offset i the same as the absolute offset but adjusted relative to the actual start time
|
||||||
const relative = absolute + plannedStart - actualStart - _startDayOffset * dayInMs;
|
const relative = absolute + plannedStart - actualStart;
|
||||||
|
|
||||||
// in case of count to end, the absolute offset is just the overtime
|
// in case of count to end, the absolute offset is just the overtime
|
||||||
return countToEnd ? { absolute: overtime, relative } : { absolute, relative };
|
return countToEnd ? { absolute: overtime, relative } : { absolute, relative };
|
||||||
@@ -182,14 +180,3 @@ export function getTimerPhase(state: RuntimeState): TimerPhase {
|
|||||||
|
|
||||||
return TimerPhase.Default;
|
return TimerPhase.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the day offset relative to an event start
|
|
||||||
* used byt the runtimeState on first start to get correct offsets
|
|
||||||
*/
|
|
||||||
export function findDayOffset(plannedStart: number, clock: number): number {
|
|
||||||
const distance = clock - plannedStart;
|
|
||||||
if (distance >= 12 * MILLIS_PER_HOUR) return -1;
|
|
||||||
if (distance < -12 * MILLIS_PER_HOUR) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ const baseState: RuntimeState = {
|
|||||||
plannedStart: 0,
|
plannedStart: 0,
|
||||||
plannedEnd: 0,
|
plannedEnd: 0,
|
||||||
actualStart: null,
|
actualStart: null,
|
||||||
actualGroupStart: null,
|
|
||||||
currentDay: 0,
|
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
absolute: 0,
|
absolute: 0,
|
||||||
@@ -48,8 +46,6 @@ const baseState: RuntimeState = {
|
|||||||
_group: null,
|
_group: null,
|
||||||
_end: null,
|
_end: null,
|
||||||
_flag: null,
|
_flag: null,
|
||||||
_startDayOffset: null,
|
|
||||||
_startEpoch: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function makeRuntimeStateData(patch?: Partial<RuntimeState>): RuntimeState {
|
export function makeRuntimeStateData(patch?: Partial<RuntimeState>): RuntimeState {
|
||||||
|
|||||||
@@ -393,7 +393,6 @@ describe('loadGroupFlagAndEnd()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
groupNow: null,
|
groupNow: null,
|
||||||
eventNow: rundown.entries[11],
|
eventNow: rundown.entries[11],
|
||||||
rundown: { actualGroupStart: null },
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const metadata = { playableEventOrder: ['0', '11', '3'], flags: ['1'] } as RundownMetadata;
|
const metadata = { playableEventOrder: ['0', '11', '3'], flags: ['1'] } as RundownMetadata;
|
||||||
@@ -421,7 +420,6 @@ describe('loadGroupFlagAndEnd()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
groupNow: rundown.entries[1],
|
groupNow: rundown.entries[1],
|
||||||
eventNow: rundown.entries[22],
|
eventNow: rundown.entries[22],
|
||||||
rundown: { actualGroupStart: null },
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const metadata = { playableEventOrder: ['0', '11', '22'], flags: ['1'] } as RundownMetadata;
|
const metadata = { playableEventOrder: ['0', '11', '22'], flags: ['1'] } as RundownMetadata;
|
||||||
@@ -449,7 +447,6 @@ describe('loadGroupFlagAndEnd()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
groupNow: rundown.entries[1],
|
groupNow: rundown.entries[1],
|
||||||
eventNow: rundown.entries[0],
|
eventNow: rundown.entries[0],
|
||||||
rundown: { actualGroupStart: null },
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const metadata = { playableEventOrder: ['0', '11', '22'], flags: ['1'] } as RundownMetadata;
|
const metadata = { playableEventOrder: ['0', '11', '22'], flags: ['1'] } as RundownMetadata;
|
||||||
@@ -474,7 +471,6 @@ describe('loadGroupFlagAndEnd()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
groupNow: null,
|
groupNow: null,
|
||||||
eventNow: rundown.entries[0],
|
eventNow: rundown.entries[0],
|
||||||
rundown: { actualGroupStart: null },
|
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const metadata = { playableEventOrder: ['0', '1'], flags: ['1'] } as RundownMetadata;
|
const metadata = { playableEventOrder: ['0', '1'], flags: ['1'] } as RundownMetadata;
|
||||||
|
|||||||
@@ -23,15 +23,9 @@ import {
|
|||||||
isPlaybackActive,
|
isPlaybackActive,
|
||||||
} from 'ontime-utils';
|
} from 'ontime-utils';
|
||||||
|
|
||||||
import { getTimeObject, timeNow } from '../utils/time.js';
|
import { timeNow } from '../utils/time.js';
|
||||||
import type { RestorePoint } from '../services/restore-service/restore.type.js';
|
import type { RestorePoint } from '../services/restore-service/restore.type.js';
|
||||||
import {
|
import { getCurrent, getExpectedFinish, getRuntimeOffset, getTimerPhase } from '../services/timerUtils.js';
|
||||||
findDayOffset,
|
|
||||||
getCurrent,
|
|
||||||
getExpectedFinish,
|
|
||||||
getRuntimeOffset,
|
|
||||||
getTimerPhase,
|
|
||||||
} from '../services/timerUtils.js';
|
|
||||||
import { loadRoll, normaliseRollStart } from '../services/rollUtils.js';
|
import { loadRoll, normaliseRollStart } from '../services/rollUtils.js';
|
||||||
import { timerConfig } from '../setup/config.js';
|
import { timerConfig } from '../setup/config.js';
|
||||||
import { RundownMetadata } from '../api-data/rundown/rundown.types.js';
|
import { RundownMetadata } from '../api-data/rundown/rundown.types.js';
|
||||||
@@ -61,8 +55,6 @@ export type RuntimeState = {
|
|||||||
_group: ExpectedMetadata;
|
_group: ExpectedMetadata;
|
||||||
_flag: ExpectedMetadata;
|
_flag: ExpectedMetadata;
|
||||||
_end: ExpectedMetadata;
|
_end: ExpectedMetadata;
|
||||||
_startEpoch: MaybeNumber;
|
|
||||||
_startDayOffset: MaybeNumber;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const runtimeState: RuntimeState = {
|
const runtimeState: RuntimeState = {
|
||||||
@@ -86,8 +78,6 @@ const runtimeState: RuntimeState = {
|
|||||||
_group: null,
|
_group: null,
|
||||||
_flag: null,
|
_flag: null,
|
||||||
_end: null,
|
_end: null,
|
||||||
_startEpoch: null,
|
|
||||||
_startDayOffset: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getState(): Readonly<RuntimeState> {
|
export function getState(): Readonly<RuntimeState> {
|
||||||
@@ -162,10 +152,6 @@ export function clearState() {
|
|||||||
runtimeState._timer.pausedAt = null;
|
runtimeState._timer.pausedAt = null;
|
||||||
runtimeState._timer.secondaryTarget = null;
|
runtimeState._timer.secondaryTarget = null;
|
||||||
runtimeState._timer.hasFinished = false;
|
runtimeState._timer.hasFinished = false;
|
||||||
|
|
||||||
runtimeState._startEpoch = null;
|
|
||||||
runtimeState._startDayOffset = null;
|
|
||||||
runtimeState.rundown.currentDay = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,8 +190,7 @@ export function updateRundownData(rundownData: {
|
|||||||
runtimeState.rundown.plannedStart = rundownData.firstStart;
|
runtimeState.rundown.plannedStart = rundownData.firstStart;
|
||||||
runtimeState.rundown.plannedEnd =
|
runtimeState.rundown.plannedEnd =
|
||||||
rundownData.firstStart === null ? null : rundownData.firstStart + rundownData.totalDuration;
|
rundownData.firstStart === null ? null : rundownData.firstStart + rundownData.totalDuration;
|
||||||
|
getExpectedTimes();
|
||||||
if (isPlaybackActive(runtimeState.timer.playback)) getExpectedTimes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,14 +229,9 @@ export function load(
|
|||||||
// patch with potential provided data
|
// patch with potential provided data
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
patchTimer(initialData);
|
patchTimer(initialData);
|
||||||
const startEpoch = initialData?.startEpoch;
|
|
||||||
const firstStart = initialData?.firstStart;
|
const firstStart = initialData?.firstStart;
|
||||||
if (
|
if (firstStart === null || typeof firstStart === 'number') {
|
||||||
(firstStart === null || typeof firstStart === 'number') &&
|
|
||||||
(startEpoch === null || typeof startEpoch === 'number')
|
|
||||||
) {
|
|
||||||
runtimeState.rundown.actualStart = firstStart;
|
runtimeState.rundown.actualStart = firstStart;
|
||||||
runtimeState._startEpoch = startEpoch;
|
|
||||||
const { absolute, relative } = getRuntimeOffset(runtimeState);
|
const { absolute, relative } = getRuntimeOffset(runtimeState);
|
||||||
runtimeState.offset.absolute = absolute;
|
runtimeState.offset.absolute = absolute;
|
||||||
runtimeState.offset.relative = relative;
|
runtimeState.offset.relative = relative;
|
||||||
@@ -387,8 +367,7 @@ export function start(state: RuntimeState = runtimeState): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [epoch, now] = getTimeObject();
|
state.clock = timeNow();
|
||||||
state.clock = now;
|
|
||||||
state.timer.secondaryTimer = null;
|
state.timer.secondaryTimer = null;
|
||||||
|
|
||||||
// add paused time if it exists
|
// add paused time if it exists
|
||||||
@@ -407,16 +386,9 @@ export function start(state: RuntimeState = runtimeState): boolean {
|
|||||||
state.timer.elapsed = 0;
|
state.timer.elapsed = 0;
|
||||||
|
|
||||||
if (state.rundown.actualStart === null) {
|
if (state.rundown.actualStart === null) {
|
||||||
state._startDayOffset = findDayOffset(state.eventNow.timeStart, state.clock);
|
|
||||||
state.rundown.currentDay = state._startDayOffset;
|
|
||||||
state._startEpoch = epoch;
|
|
||||||
state.rundown.actualStart = state.clock;
|
state.rundown.actualStart = state.clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.groupNow !== null && state.rundown.actualGroupStart === null) {
|
|
||||||
state.rundown.actualGroupStart = state.clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update timer phase
|
// update timer phase
|
||||||
runtimeState.timer.phase = getTimerPhase(runtimeState);
|
runtimeState.timer.phase = getTimerPhase(runtimeState);
|
||||||
|
|
||||||
@@ -508,20 +480,13 @@ export type UpdateResult = {
|
|||||||
export function update(): UpdateResult {
|
export function update(): UpdateResult {
|
||||||
// 0. there are some things we always do
|
// 0. there are some things we always do
|
||||||
const previousClock = runtimeState.clock;
|
const previousClock = runtimeState.clock;
|
||||||
const [epoch, now] = getTimeObject();
|
runtimeState.clock = timeNow(); // we update the clock on every update call
|
||||||
runtimeState.clock = now; // we update the clock on every update call
|
|
||||||
|
|
||||||
// 1. is playback idle?
|
// 1. is playback idle?
|
||||||
if (!isPlaybackActive(runtimeState.timer.playback)) {
|
if (!isPlaybackActive(runtimeState.timer.playback)) {
|
||||||
return updateIfIdle();
|
return updateIfIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are playing and playback changes. we tick the current runtime day
|
|
||||||
if (runtimeState._startDayOffset !== null && runtimeState._startEpoch) {
|
|
||||||
runtimeState.rundown.currentDay =
|
|
||||||
runtimeState._startDayOffset + Math.floor((epoch - runtimeState._startEpoch) / dayInMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. are we waiting to roll?
|
// 2. are we waiting to roll?
|
||||||
if (runtimeState.timer.playback === Playback.Roll && runtimeState.timer.secondaryTimer !== null) {
|
if (runtimeState.timer.playback === Playback.Roll && runtimeState.timer.secondaryTimer !== null) {
|
||||||
const hasCrossedMidnight = previousClock > runtimeState.clock;
|
const hasCrossedMidnight = previousClock > runtimeState.clock;
|
||||||
@@ -603,10 +568,6 @@ export function roll(
|
|||||||
return { eventId: runtimeState.eventNow?.id ?? null, didStart: false };
|
return { eventId: runtimeState.eventNow?.id ?? null, didStart: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
// we will need to do some calculations, update the time first
|
|
||||||
const [epoch, now] = getTimeObject();
|
|
||||||
runtimeState.clock = now;
|
|
||||||
|
|
||||||
// 2. if there is an event armed, we use it
|
// 2. if there is an event armed, we use it
|
||||||
if (runtimeState.timer.playback === Playback.Armed || runtimeState.timer.phase === TimerPhase.Pending) {
|
if (runtimeState.timer.playback === Playback.Armed || runtimeState.timer.phase === TimerPhase.Pending) {
|
||||||
// eslint-disable-next-line no-unused-labels -- dev code path
|
// eslint-disable-next-line no-unused-labels -- dev code path
|
||||||
@@ -637,24 +598,12 @@ export function roll(
|
|||||||
// check if the event is ready to start or if needs to be pending
|
// check if the event is ready to start or if needs to be pending
|
||||||
const isNow = checkIsNow(runtimeState.eventNow.timeStart, runtimeState.eventNow.timeEnd, offsetClock);
|
const isNow = checkIsNow(runtimeState.eventNow.timeStart, runtimeState.eventNow.timeEnd, offsetClock);
|
||||||
if (isNow) {
|
if (isNow) {
|
||||||
/**
|
runtimeState.timer.startedAt = runtimeState.clock;
|
||||||
* If we are starting an event in roll mode
|
|
||||||
* we backtrace all the start times to the supposed start time of the event
|
|
||||||
*/
|
|
||||||
const plannedStart = runtimeState.eventNow.timeStart;
|
|
||||||
runtimeState.timer.startedAt = plannedStart;
|
|
||||||
// reset the secondary timer to cancel any countdowns
|
|
||||||
runtimeState.timer.secondaryTimer = null;
|
|
||||||
|
|
||||||
if (runtimeState.groupNow !== null && runtimeState.rundown.actualGroupStart === null) {
|
|
||||||
runtimeState.rundown.actualGroupStart = plannedStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtimeState.rundown.actualStart === null) {
|
if (runtimeState.rundown.actualStart === null) {
|
||||||
runtimeState.rundown.actualStart = plannedStart;
|
runtimeState.rundown.actualStart = runtimeState.clock;
|
||||||
runtimeState._startDayOffset = 0;
|
|
||||||
runtimeState._startEpoch = epoch;
|
|
||||||
}
|
}
|
||||||
|
runtimeState.timer.secondaryTimer = null;
|
||||||
} else {
|
} else {
|
||||||
runtimeState._timer.secondaryTarget = normaliseRollStart(runtimeState.eventNow.timeStart, offsetClock);
|
runtimeState._timer.secondaryTarget = normaliseRollStart(runtimeState.eventNow.timeStart, offsetClock);
|
||||||
runtimeState.timer.secondaryTimer = runtimeState._timer.secondaryTarget - offsetClock;
|
runtimeState.timer.secondaryTimer = runtimeState._timer.secondaryTarget - offsetClock;
|
||||||
@@ -709,37 +658,26 @@ export function roll(
|
|||||||
return { eventId: runtimeState.eventNow.id, didStart: false };
|
return { eventId: runtimeState.eventNow.id, didStart: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// there is something to run, load event
|
||||||
* At this point we know that there is something to run and the event is loaded
|
// event will finish on time
|
||||||
* - ensure the event will finish ontime
|
// account for event that finishes the day after
|
||||||
* - account for events that finish the day after
|
|
||||||
*
|
|
||||||
* when we start in roll mode
|
|
||||||
* we need to backtrace all times to the supposed start time of the event
|
|
||||||
*/
|
|
||||||
const plannedStart = runtimeState.eventNow.timeStart;
|
|
||||||
const endTime =
|
const endTime =
|
||||||
runtimeState.eventNow.timeEnd < runtimeState.eventNow.timeStart
|
runtimeState.eventNow.timeEnd < runtimeState.eventNow.timeStart
|
||||||
? runtimeState.eventNow.timeEnd + dayInMs
|
? runtimeState.eventNow.timeEnd + dayInMs
|
||||||
: runtimeState.eventNow.timeEnd;
|
: runtimeState.eventNow.timeEnd;
|
||||||
runtimeState.timer.startedAt = plannedStart;
|
runtimeState.timer.startedAt = runtimeState.clock;
|
||||||
runtimeState.timer.expectedFinish = endTime;
|
runtimeState.timer.expectedFinish = endTime;
|
||||||
|
|
||||||
|
// we add time to allow timer to catch up
|
||||||
|
runtimeState.timer.addedTime = -(runtimeState.clock - runtimeState.eventNow.timeStart);
|
||||||
|
|
||||||
// state catch up
|
// state catch up
|
||||||
runtimeState.timer.duration = calculateDuration(runtimeState.eventNow.timeStart, endTime);
|
runtimeState.timer.duration = calculateDuration(runtimeState.eventNow.timeStart, endTime);
|
||||||
runtimeState.timer.current = getCurrent(runtimeState);
|
runtimeState.timer.current = getCurrent(runtimeState);
|
||||||
runtimeState.timer.elapsed = 0;
|
runtimeState.timer.elapsed = 0;
|
||||||
|
|
||||||
// update runtime
|
// update runtime
|
||||||
runtimeState.rundown.actualStart = plannedStart;
|
runtimeState.rundown.actualStart = runtimeState.clock;
|
||||||
if (runtimeState.groupNow !== null && runtimeState.rundown.actualGroupStart === null) {
|
|
||||||
runtimeState.rundown.actualGroupStart = plannedStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update metadata
|
|
||||||
runtimeState._startDayOffset = 0;
|
|
||||||
runtimeState._startEpoch = epoch;
|
|
||||||
|
|
||||||
return { eventId: runtimeState.eventNow.id, didStart: true };
|
return { eventId: runtimeState.eventNow.id, didStart: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,7 +704,7 @@ function getExpectedTimes(state = runtimeState) {
|
|||||||
if (_group !== null) {
|
if (_group !== null) {
|
||||||
const { event: lastEvent, accumulatedGap, isLinkedToLoaded } = _group;
|
const { event: lastEvent, accumulatedGap, isLinkedToLoaded } = _group;
|
||||||
const lastEventExpectedStart = getExpectedStart(lastEvent, {
|
const lastEventExpectedStart = getExpectedStart(lastEvent, {
|
||||||
currentDay: state.rundown.currentDay!,
|
currentDay: eventNow.dayOffset,
|
||||||
totalGap: accumulatedGap,
|
totalGap: accumulatedGap,
|
||||||
isLinkedToLoaded,
|
isLinkedToLoaded,
|
||||||
mode: offset.mode,
|
mode: offset.mode,
|
||||||
@@ -783,7 +721,7 @@ function getExpectedTimes(state = runtimeState) {
|
|||||||
if (_flag) {
|
if (_flag) {
|
||||||
const { event, accumulatedGap, isLinkedToLoaded } = _flag;
|
const { event, accumulatedGap, isLinkedToLoaded } = _flag;
|
||||||
const expectedStart = getExpectedStart(event, {
|
const expectedStart = getExpectedStart(event, {
|
||||||
currentDay: state.rundown.currentDay!,
|
currentDay: eventNow.dayOffset,
|
||||||
totalGap: accumulatedGap,
|
totalGap: accumulatedGap,
|
||||||
isLinkedToLoaded,
|
isLinkedToLoaded,
|
||||||
mode: offset.mode,
|
mode: offset.mode,
|
||||||
@@ -798,7 +736,7 @@ function getExpectedTimes(state = runtimeState) {
|
|||||||
if (state._end) {
|
if (state._end) {
|
||||||
const { event, accumulatedGap, isLinkedToLoaded } = state._end;
|
const { event, accumulatedGap, isLinkedToLoaded } = state._end;
|
||||||
const expectedStart = getExpectedStart(event, {
|
const expectedStart = getExpectedStart(event, {
|
||||||
currentDay: state.rundown.currentDay!,
|
currentDay: eventNow.dayOffset,
|
||||||
totalGap: accumulatedGap,
|
totalGap: accumulatedGap,
|
||||||
isLinkedToLoaded,
|
isLinkedToLoaded,
|
||||||
mode: offset.mode,
|
mode: offset.mode,
|
||||||
@@ -814,19 +752,16 @@ export function loadGroupFlagAndEnd(
|
|||||||
rundown: Rundown,
|
rundown: Rundown,
|
||||||
metadata: RundownMetadata,
|
metadata: RundownMetadata,
|
||||||
currentIndex: MaybeNumber,
|
currentIndex: MaybeNumber,
|
||||||
state = runtimeState, // used for testing
|
state = runtimeState,
|
||||||
) {
|
) {
|
||||||
const previousGroup = state.groupNow?.id;
|
|
||||||
state.groupNow = null;
|
state.groupNow = null;
|
||||||
state._group = null;
|
state._group = null;
|
||||||
state.eventFlag = null;
|
state.eventFlag = null;
|
||||||
state._flag = null;
|
state._flag = null;
|
||||||
state._end = null;
|
state._end = null;
|
||||||
|
|
||||||
if (currentIndex === null || state.eventNow === null) {
|
if (currentIndex == null) return;
|
||||||
state.rundown.actualGroupStart = null;
|
if (state.eventNow === null) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentGroupId = state.eventNow.parent;
|
const currentGroupId = state.eventNow.parent;
|
||||||
const flagsPresent = metadata.flags.length !== 0;
|
const flagsPresent = metadata.flags.length !== 0;
|
||||||
@@ -838,10 +773,6 @@ export function loadGroupFlagAndEnd(
|
|||||||
state.groupNow = currentGroupId ? (entries[currentGroupId] as OntimeGroup) : null;
|
state.groupNow = currentGroupId ? (entries[currentGroupId] as OntimeGroup) : null;
|
||||||
const lastEventInGroup = orderInGroup ? getLastEventNormal(rundown.entries, orderInGroup).lastEvent : null;
|
const lastEventInGroup = orderInGroup ? getLastEventNormal(rundown.entries, orderInGroup).lastEvent : null;
|
||||||
|
|
||||||
if (previousGroup !== currentGroupId) {
|
|
||||||
state.rundown.actualGroupStart = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we don't have a any flags in the rundown then no need to look for it
|
// if we don't have a any flags in the rundown then no need to look for it
|
||||||
let foundFlag = !flagsPresent;
|
let foundFlag = !flagsPresent;
|
||||||
// if we don't have a last event for the group there is no need to find its end time
|
// if we don't have a last event for the group there is no need to find its end time
|
||||||
@@ -883,5 +814,4 @@ export function loadGroupFlagAndEnd(
|
|||||||
|
|
||||||
export function setOffsetMode(mode: OffsetMode) {
|
export function setOffsetMode(mode: OffsetMode) {
|
||||||
runtimeState.offset.mode = mode;
|
runtimeState.offset.mode = mode;
|
||||||
if (isPlaybackActive(runtimeState.timer.playback)) getExpectedTimes();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,25 +145,16 @@ describe('coerce unknown value to a boolean', () => {
|
|||||||
expect(coerceBoolean('')).toStrictEqual(false);
|
expect(coerceBoolean('')).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid strings', () => {
|
|
||||||
expect(() => coerceBoolean('bla')).toThrowError('Invalid value received');
|
|
||||||
expect(() => coerceBoolean(' ')).toThrowError('Invalid value received');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('true numbers', () => {
|
test('true numbers', () => {
|
||||||
expect(coerceBoolean(1)).toStrictEqual(true);
|
expect(coerceBoolean(1)).toStrictEqual(true);
|
||||||
|
expect(coerceBoolean(2)).toStrictEqual(true);
|
||||||
|
expect(coerceBoolean(100000)).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('false numbers', () => {
|
test.todo('false numbers', () => {
|
||||||
expect(coerceBoolean(0)).toStrictEqual(false);
|
expect(coerceBoolean(0)).toStrictEqual(false);
|
||||||
});
|
expect(coerceBoolean(-1)).toStrictEqual(false);
|
||||||
|
expect(coerceBoolean(-10000)).toStrictEqual(false);
|
||||||
test('invalid numbers', () => {
|
|
||||||
expect(() => coerceBoolean(0.5)).toThrowError('Invalid value received');
|
|
||||||
expect(() => coerceBoolean(-1)).toThrowError('Invalid value received');
|
|
||||||
expect(() => coerceBoolean(2)).toThrowError('Invalid value received');
|
|
||||||
expect(() => coerceBoolean(NaN)).toThrowError('Invalid value received');
|
|
||||||
expect(() => coerceBoolean(Infinity)).toThrowError('Invalid value received');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('booleans', () => {
|
test('booleans', () => {
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ export function coerceString(value: unknown): string {
|
|||||||
* @throws {Error} Throws an error if the value is null or undefined.
|
* @throws {Error} Throws an error if the value is null or undefined.
|
||||||
*/
|
*/
|
||||||
export function coerceBoolean(value: unknown): boolean {
|
export function coerceBoolean(value: unknown): boolean {
|
||||||
if (typeof value === 'boolean') {
|
if (value === undefined || typeof value === 'object') {
|
||||||
return value;
|
throw new Error('Invalid value received');
|
||||||
}
|
}
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
const lowerCaseValue = value.toLocaleLowerCase();
|
const lowerCaseValue = value.toLocaleLowerCase();
|
||||||
@@ -52,11 +52,7 @@ export function coerceBoolean(value: unknown): boolean {
|
|||||||
throw new Error('Invalid value received');
|
throw new Error('Invalid value received');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof value === 'number') {
|
return Boolean(value);
|
||||||
if (value === 0) return false;
|
|
||||||
if (value === 1) return true;
|
|
||||||
}
|
|
||||||
throw new Error('Invalid value received');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,18 +74,3 @@ export function timeNow() {
|
|||||||
elapsed += now.getMilliseconds();
|
elapsed += now.getMilliseconds();
|
||||||
return elapsed;
|
return elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current time from system
|
|
||||||
* @returns [number, number] - [epoch time, milliseconds since midnight]
|
|
||||||
*/
|
|
||||||
export function getTimeObject(): [number, number] {
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
// extract milliseconds since midnight
|
|
||||||
let elapsed = now.getHours() * 3600000;
|
|
||||||
elapsed += now.getMinutes() * 60000;
|
|
||||||
elapsed += now.getSeconds() * 1000;
|
|
||||||
elapsed += now.getMilliseconds();
|
|
||||||
return [now.getTime(), elapsed];
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.common.json",
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"strict": true,
|
||||||
"module": "node16",
|
"target": "ESNext",
|
||||||
"moduleResolution": "node16",
|
"module": "Node16",
|
||||||
"noImplicitReturns": false, //TODO: fix this
|
"moduleResolution": "Node16",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
"types": ["vitest/globals"],
|
"types": ["vitest/globals"],
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
|||||||
@@ -72,6 +72,4 @@ test('time until relative', async ({ page }) => {
|
|||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('30s');
|
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('30s');
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('10m');
|
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('10m');
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('20m');
|
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('20m');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Absolute' }).click();
|
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ontime",
|
"name": "ontime",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.3",
|
||||||
"description": "Time keeping for live events",
|
"description": "Time keeping for live events",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ontime",
|
"ontime",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"e2e": "pnpm clear-temp && cross-env DEBUG=pw:webserver npx playwright test -c playwright.config.ts",
|
"e2e": "pnpm clear-temp && cross-env DEBUG=pw:webserver npx playwright test -c playwright.config.ts",
|
||||||
"e2e:ui": "cross-env DEBUG=pw:webserver npx playwright test --ui -c playwright.config.ts",
|
"e2e:ui": "cross-env DEBUG=pw:webserver npx playwright test --ui -c playwright.config.ts",
|
||||||
"e2e:i": "npx playwright codegen",
|
"e2e:i": "npx playwright codegen",
|
||||||
"cleanup": "pnpm rimraf node_modules && rimraf **/node_modules && rimraf **/**/node_modules",
|
"cleanup": "rm -rf node_modules && rm -rf **/node_modules && rm -rf **/**/node_modules",
|
||||||
"clear-temp": "rm -rf e2e/tests/fixtures/tmp"
|
"clear-temp": "rm -rf e2e/tests/fixtures/tmp"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -47,8 +47,7 @@
|
|||||||
"eslint-plugin-playwright": "^1.5.2",
|
"eslint-plugin-playwright": "^1.5.2",
|
||||||
"prettier": "catalog:",
|
"prettier": "catalog:",
|
||||||
"turbo": "^2.3.3",
|
"turbo": "^2.3.3",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:"
|
||||||
"rimraf": "catalog:"
|
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"version": "4.0.0-beta.4",
|
|
||||||
"name": "ontime-types",
|
"name": "ontime-types",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
@@ -8,8 +7,7 @@
|
|||||||
"description": "shared typings for ontime",
|
"description": "shared typings for ontime",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"cleanup": "rm -rf .turbo && rm -rf node_modules",
|
"cleanup": "rm -rf .turbo && rm -rf node_modules",
|
||||||
"lint": "eslint . --quiet",
|
"lint": "eslint . --quiet"
|
||||||
"build": "tsc"
|
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -18,7 +16,6 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "catalog:",
|
"@typescript-eslint/eslint-plugin": "catalog:",
|
||||||
"@typescript-eslint/parser": "catalog:",
|
"@typescript-eslint/parser": "catalog:",
|
||||||
"eslint": "catalog:",
|
"eslint": "catalog:",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:"
|
||||||
"ts-essentials": "catalog:"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,177 +1,15 @@
|
|||||||
import type { DeepPartial } from 'ts-essentials';
|
|
||||||
|
|
||||||
import type { OntimeEvent } from '../../definitions/core/OntimeEntry.js';
|
|
||||||
import type { SimpleDirection, SimplePlayback } from '../../definitions/runtime/AuxTimer.type.js';
|
|
||||||
import type { MessageState } from '../../definitions/runtime/MessageControl.type.js';
|
|
||||||
import type { OffsetMode } from '../../definitions/runtime/Offset.type.js';
|
|
||||||
import type { RuntimeStore } from '../../definitions/runtime/RuntimeStore.type.js';
|
|
||||||
|
|
||||||
export type VersionAction = {
|
|
||||||
tag: 'version';
|
|
||||||
payload: undefined;
|
|
||||||
};
|
|
||||||
export type VersionResponse = {
|
|
||||||
tag: 'version';
|
|
||||||
payload: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PollAction = {
|
|
||||||
tag: 'poll';
|
|
||||||
payload: undefined;
|
|
||||||
};
|
|
||||||
export type PollResponse = {
|
|
||||||
tag: 'poll';
|
|
||||||
payload: RuntimeStore;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ChangeAction = {
|
|
||||||
tag: 'change';
|
|
||||||
payload: { [x: string]: Partial<OntimeEvent> };
|
|
||||||
};
|
|
||||||
export type ChangeResponse = {
|
|
||||||
tag: 'change';
|
|
||||||
payload: 'success' | 'throttled';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MessageAction = {
|
|
||||||
tag: 'message';
|
|
||||||
payload: DeepPartial<MessageState>;
|
|
||||||
};
|
|
||||||
export type MessageResponse = {
|
|
||||||
tag: 'message';
|
|
||||||
payload: MessageState;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type StartAction = {
|
|
||||||
tag: 'start';
|
|
||||||
payload: undefined | { index: number } | { id: string } | { cue: string } | 'next' | 'previous';
|
|
||||||
};
|
|
||||||
export type StartResponse = {
|
|
||||||
tag: 'start';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PauseAction = {
|
|
||||||
tag: 'pause';
|
|
||||||
payload: undefined;
|
|
||||||
};
|
|
||||||
export type PauseResponse = {
|
|
||||||
tag: 'pause';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type StopAction = {
|
|
||||||
tag: 'stop';
|
|
||||||
payload: undefined;
|
|
||||||
};
|
|
||||||
export type StopResponse = {
|
|
||||||
tag: 'stop';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ReloadAction = {
|
|
||||||
tag: 'reload';
|
|
||||||
payload: undefined;
|
|
||||||
};
|
|
||||||
export type ReloadResponse = {
|
|
||||||
tag: 'reload';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type RollAction = {
|
|
||||||
tag: 'roll';
|
|
||||||
payload: undefined;
|
|
||||||
};
|
|
||||||
export type RollResponse = {
|
|
||||||
tag: 'roll';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LoadAction = {
|
|
||||||
tag: 'load';
|
|
||||||
payload: { index: number } | { id: string } | { cue: string } | 'next' | 'previous';
|
|
||||||
};
|
|
||||||
export type LoadResponse = {
|
|
||||||
tag: 'load';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddtimeAction = {
|
|
||||||
tag: 'addtime';
|
|
||||||
payload: { add: number } | { remove: number } | number;
|
|
||||||
};
|
|
||||||
export type AddtimeResponse = {
|
|
||||||
tag: 'addtime';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AuxtimerAction = {
|
|
||||||
tag: 'auxtimer';
|
|
||||||
payload:
|
|
||||||
| {
|
|
||||||
['1']?: SimplePlayback | { duration?: number; addtime?: number; direction?: SimpleDirection };
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
['2']?: SimplePlayback | { duration?: number; addtime?: number; direction?: SimpleDirection };
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
['3']?: SimplePlayback | { duration?: number; addtime?: number; direction?: SimpleDirection };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AuxtimerResponse = {
|
|
||||||
tag: 'auxtimer';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ClientAction = {
|
|
||||||
tag: 'client';
|
|
||||||
payload: { target: string } & ({ rename: string } | { redirect: string } | { identify: string });
|
|
||||||
};
|
|
||||||
export type ClientResponse = {
|
|
||||||
tag: 'client';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OffsetmodeAction = {
|
|
||||||
tag: 'offsetmode';
|
|
||||||
payload: OffsetMode;
|
|
||||||
};
|
|
||||||
export type OffsetmodeResponse = {
|
|
||||||
tag: 'offsetmode';
|
|
||||||
payload: 'success';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ApiAction =
|
export type ApiAction =
|
||||||
| VersionAction
|
| 'version'
|
||||||
| PollAction
|
| 'poll'
|
||||||
| ChangeAction
|
| 'change'
|
||||||
| MessageAction
|
| 'message'
|
||||||
| StartAction
|
| 'start'
|
||||||
| PauseAction
|
| 'pause'
|
||||||
| StopAction
|
| 'stop'
|
||||||
| ReloadAction
|
| 'reload'
|
||||||
| RollAction
|
| 'roll'
|
||||||
| LoadAction
|
| 'load'
|
||||||
| AddtimeAction
|
| 'addtime'
|
||||||
| AuxtimerAction
|
| 'auxtimer'
|
||||||
| ClientAction
|
| 'client'
|
||||||
| OffsetmodeAction;
|
| 'offsetmode';
|
||||||
|
|
||||||
export type ApiResponse =
|
|
||||||
| VersionResponse
|
|
||||||
| PollResponse
|
|
||||||
| ChangeResponse
|
|
||||||
| MessageResponse
|
|
||||||
| StartResponse
|
|
||||||
| PauseResponse
|
|
||||||
| StopResponse
|
|
||||||
| ReloadResponse
|
|
||||||
| RollResponse
|
|
||||||
| LoadResponse
|
|
||||||
| AddtimeResponse
|
|
||||||
| AuxtimerResponse
|
|
||||||
| ClientResponse
|
|
||||||
| OffsetmodeResponse;
|
|
||||||
|
|
||||||
export type ApiActionTag = ApiAction['tag'];
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
|
import type {
|
||||||
import type { AutomationSettings } from './core/Automation.type.js';
|
AutomationSettings,
|
||||||
import type { CustomFields } from './core/CustomFields.type.js';
|
CustomFields,
|
||||||
import type { ProjectData } from './core/ProjectData.type.js';
|
ProjectData,
|
||||||
import type { ProjectRundowns } from './core/Rundown.type.js';
|
ProjectRundowns,
|
||||||
import type { Settings } from './core/Settings.type.js';
|
Settings,
|
||||||
import type { URLPreset } from './core/UrlPreset.type.js';
|
URLPreset,
|
||||||
import type { ViewSettings } from './core/Views.type.js';
|
ViewSettings,
|
||||||
|
} from '../index.js';
|
||||||
|
|
||||||
export type DatabaseModel = {
|
export type DatabaseModel = {
|
||||||
rundowns: ProjectRundowns;
|
rundowns: ProjectRundowns;
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import type { MaybeNumber } from '../../utils/utils.type.js';
|
import type { EndAction, EntryCustomFields, MaybeNumber, TimerType, TimeStrategy, Trigger } from '../../index.js';
|
||||||
import type { EndAction } from '../EndAction.type.js';
|
|
||||||
import type { TimerType } from '../TimerType.type.js';
|
|
||||||
import type { TimeStrategy } from '../TimeStrategy.type.js';
|
|
||||||
import type { Trigger } from './Automation.type.js';
|
|
||||||
import type { EntryCustomFields } from './CustomFields.type.js';
|
|
||||||
|
|
||||||
export type EntryId = string;
|
export type EntryId = string;
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ export type RundownState = {
|
|||||||
selectedEventIndex: MaybeNumber;
|
selectedEventIndex: MaybeNumber;
|
||||||
numEvents: number;
|
numEvents: number;
|
||||||
plannedStart: MaybeNumber;
|
plannedStart: MaybeNumber;
|
||||||
plannedEnd: MaybeNumber;
|
|
||||||
actualStart: MaybeNumber;
|
actualStart: MaybeNumber;
|
||||||
currentDay: MaybeNumber;
|
plannedEnd: MaybeNumber;
|
||||||
actualGroupStart: MaybeNumber;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ export const runtimeStorePlaceholder: Readonly<RuntimeStore> = {
|
|||||||
plannedStart: 0, // only changes if event changes
|
plannedStart: 0, // only changes if event changes
|
||||||
plannedEnd: 0, // only changes if event changes, overflows over dayInMs
|
plannedEnd: 0, // only changes if event changes, overflows over dayInMs
|
||||||
actualStart: null, // set once we start the timer
|
actualStart: null, // set once we start the timer
|
||||||
actualGroupStart: null, // maybe set once we start the timer
|
|
||||||
currentDay: null,
|
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
absolute: 0, // changes at runtime
|
absolute: 0, // changes at runtime
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MaybeNumber } from '../../utils/utils.type.js';
|
import type { MaybeNumber } from '../../index.js';
|
||||||
import type { Playback } from './Playback.type.js';
|
import type { Playback } from './Playback.type.js';
|
||||||
|
|
||||||
export enum TimerPhase {
|
export enum TimerPhase {
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export type { LinkOptions } from './api/session-controller/BackendResponse.type.
|
|||||||
export { MessageTag } from './api/websocket/data.type.js';
|
export { MessageTag } from './api/websocket/data.type.js';
|
||||||
export type { WsPacketToServer, WsPacketToClient } from './api/websocket/data.type.js';
|
export type { WsPacketToServer, WsPacketToClient } from './api/websocket/data.type.js';
|
||||||
export { RefetchKey } from './api/websocket/refetch.type.js';
|
export { RefetchKey } from './api/websocket/refetch.type.js';
|
||||||
export type { ApiAction, ApiActionTag, ApiResponse } from './api/websocket/api.type.js';
|
export type { ApiAction } from './api/websocket/api.type.js';
|
||||||
// SERVER RUNTIME
|
// SERVER RUNTIME
|
||||||
export { type Log, LogLevel, type LogMessage, LogOrigin } from './definitions/runtime/Logger.type.js';
|
export { type Log, LogLevel, type LogMessage, LogOrigin } from './definitions/runtime/Logger.type.js';
|
||||||
export { Playback } from './definitions/runtime/Playback.type.js';
|
export { Playback } from './definitions/runtime/Playback.type.js';
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.common.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "esnext",
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node10",
|
|
||||||
"allowUnusedLabels": false,
|
|
||||||
"removeComments": true,
|
|
||||||
"preserveConstEnums": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"declaration": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/index.ts",
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules", "dist"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { OffsetMode } from 'ontime-types';
|
import { OffsetMode } from 'ontime-types';
|
||||||
|
|
||||||
import { dayInMs, MILLIS_PER_HOUR } from './conversionUtils';
|
import { dayInMs } from './conversionUtils';
|
||||||
import { getExpectedStart } from './getExpectedStart';
|
import { getExpectedStart } from './getExpectedStart';
|
||||||
|
|
||||||
describe('getExpectedStart()', () => {
|
describe('getExpectedStart()', () => {
|
||||||
@@ -277,41 +277,4 @@ describe('getExpectedStart()', () => {
|
|||||||
// the overlap will be pushed out to the expected available time
|
// the overlap will be pushed out to the expected available time
|
||||||
expect(getExpectedStart(testEvent, { ...testState, totalGap: -5 })).toBe(110);
|
expect(getExpectedStart(testEvent, { ...testState, totalGap: -5 })).toBe(110);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('we started on the day before', () => {
|
|
||||||
const testEvent = {
|
|
||||||
timeStart: 5,
|
|
||||||
dayOffset: 0,
|
|
||||||
delay: 0,
|
|
||||||
};
|
|
||||||
const testState = {
|
|
||||||
currentDay: -1,
|
|
||||||
actualStart: 23 * MILLIS_PER_HOUR,
|
|
||||||
plannedStart: 0,
|
|
||||||
offset: -1 * MILLIS_PER_HOUR,
|
|
||||||
mode: OffsetMode.Absolute,
|
|
||||||
isLinkedToLoaded: true,
|
|
||||||
totalGap: 0,
|
|
||||||
};
|
|
||||||
expect(getExpectedStart(testEvent, { ...testState })).toBe(23 * MILLIS_PER_HOUR + 5);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('next day in multi-day rundown', () => {
|
|
||||||
const testEvent = {
|
|
||||||
timeStart: 5,
|
|
||||||
dayOffset: 1,
|
|
||||||
delay: 0,
|
|
||||||
};
|
|
||||||
const testState = {
|
|
||||||
currentDay: -1,
|
|
||||||
actualStart: 23 * MILLIS_PER_HOUR,
|
|
||||||
plannedStart: 0,
|
|
||||||
offset: -1 * MILLIS_PER_HOUR,
|
|
||||||
mode: OffsetMode.Absolute,
|
|
||||||
isLinkedToLoaded: true,
|
|
||||||
totalGap: 0,
|
|
||||||
};
|
|
||||||
expect(getExpectedStart(testEvent, { ...testState })).toBe(23 * MILLIS_PER_HOUR + 5 + dayInMs);
|
|
||||||
expect(getExpectedStart(testEvent, { ...testState, currentDay: 0 })).toBe(23 * MILLIS_PER_HOUR + 5);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { dayInMs } from './conversionUtils.js';
|
|||||||
export function getExpectedStart(
|
export function getExpectedStart(
|
||||||
event: Pick<OntimeEvent, 'timeStart' | 'dayOffset' | 'delay'>,
|
event: Pick<OntimeEvent, 'timeStart' | 'dayOffset' | 'delay'>,
|
||||||
state: {
|
state: {
|
||||||
currentDay: number; // the current day from the rundown
|
currentDay: number;
|
||||||
totalGap: number;
|
totalGap: number;
|
||||||
isLinkedToLoaded: boolean;
|
isLinkedToLoaded: boolean;
|
||||||
offset: number;
|
offset: number;
|
||||||
@@ -38,7 +38,7 @@ export function getExpectedStart(
|
|||||||
let relativeStartOffset = 0;
|
let relativeStartOffset = 0;
|
||||||
|
|
||||||
if (mode === OffsetMode.Relative) {
|
if (mode === OffsetMode.Relative) {
|
||||||
relativeStartOffset = (actualStart ?? 0) + currentDay * dayInMs - (plannedStart ?? 0);
|
relativeStartOffset = (actualStart ?? 0) - (plannedStart ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const scheduledStartTime = normalisedTimeStart + relativeStartOffset;
|
const scheduledStartTime = normalisedTimeStart + relativeStartOffset;
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.common.json",
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "ESNext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
"allowUnusedLabels": false,
|
"allowUnusedLabels": false,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|||||||
Generated
+16
-350
@@ -27,12 +27,6 @@ catalogs:
|
|||||||
prettier:
|
prettier:
|
||||||
specifier: 3.3.1
|
specifier: 3.3.1
|
||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
rimraf:
|
|
||||||
specifier: 6.0.1
|
|
||||||
version: 6.0.1
|
|
||||||
ts-essentials:
|
|
||||||
specifier: 10.1.1
|
|
||||||
version: 10.1.1
|
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 5.5.3
|
specifier: 5.5.3
|
||||||
version: 5.5.3
|
version: 5.5.3
|
||||||
@@ -71,9 +65,6 @@ importers:
|
|||||||
prettier:
|
prettier:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
rimraf:
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 6.0.1
|
|
||||||
turbo:
|
turbo:
|
||||||
specifier: ^2.3.3
|
specifier: ^2.3.3
|
||||||
version: 2.5.6
|
version: 2.5.6
|
||||||
@@ -280,30 +271,6 @@ importers:
|
|||||||
specifier: ^7.2.0
|
specifier: ^7.2.0
|
||||||
version: 7.2.0
|
version: 7.2.0
|
||||||
|
|
||||||
apps/resolver:
|
|
||||||
devDependencies:
|
|
||||||
'@sprout2000/esbuild-copy-plugin':
|
|
||||||
specifier: ^1.1.19
|
|
||||||
version: 1.1.19
|
|
||||||
'@typescript-eslint/parser':
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 7.16.1(eslint@8.56.0)(typescript@5.5.3)
|
|
||||||
eslint:
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 8.56.0
|
|
||||||
ontime-types:
|
|
||||||
specifier: workspace:^4.0.0
|
|
||||||
version: link:../../packages/types
|
|
||||||
rimraf:
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 6.0.1
|
|
||||||
tsup:
|
|
||||||
specifier: ^8.5.0
|
|
||||||
version: 8.5.0(jiti@2.4.2)(postcss@8.5.4)(tsx@4.20.5)(typescript@5.5.3)
|
|
||||||
typescript:
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 5.5.3
|
|
||||||
|
|
||||||
apps/server:
|
apps/server:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@googleapis/sheets':
|
'@googleapis/sheets':
|
||||||
@@ -351,6 +318,9 @@ importers:
|
|||||||
sanitize-filename:
|
sanitize-filename:
|
||||||
specifier: ^1.6.3
|
specifier: ^1.6.3
|
||||||
version: 1.6.3
|
version: 1.6.3
|
||||||
|
steno:
|
||||||
|
specifier: ^4.0.2
|
||||||
|
version: 4.0.2
|
||||||
ws:
|
ws:
|
||||||
specifier: ^8.18.0
|
specifier: ^8.18.0
|
||||||
version: 8.18.3
|
version: 8.18.3
|
||||||
@@ -407,7 +377,7 @@ importers:
|
|||||||
specifier: ^0.3.4
|
specifier: ^0.3.4
|
||||||
version: 0.3.4
|
version: 0.3.4
|
||||||
ts-essentials:
|
ts-essentials:
|
||||||
specifier: 'catalog:'
|
specifier: ^10.0.3
|
||||||
version: 10.1.1(typescript@5.5.3)
|
version: 10.1.1(typescript@5.5.3)
|
||||||
tsx:
|
tsx:
|
||||||
specifier: ^4.19.2
|
specifier: ^4.19.2
|
||||||
@@ -430,9 +400,6 @@ importers:
|
|||||||
eslint:
|
eslint:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 8.56.0
|
version: 8.56.0
|
||||||
ts-essentials:
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 10.1.1(typescript@5.5.3)
|
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.5.3
|
version: 5.5.3
|
||||||
@@ -1608,10 +1575,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
|
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
'@sprout2000/esbuild-copy-plugin@1.1.19':
|
|
||||||
resolution: {integrity: sha512-KXI1nDBWKLubg5EJy+jkxhqvtg9wlshF+ycVMoad6j2pr/APQiDMwAv6JUzkgU6INxg40E4/7xfgefi/Gn+blA==}
|
|
||||||
engines: {node: '>=16.7'}
|
|
||||||
|
|
||||||
'@svgr/babel-plugin-add-jsx-attribute@8.0.0':
|
'@svgr/babel-plugin-add-jsx-attribute@8.0.0':
|
||||||
resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==}
|
resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -2067,9 +2030,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
|
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
any-promise@1.3.0:
|
|
||||||
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
|
||||||
|
|
||||||
anymatch@3.1.3:
|
anymatch@3.1.3:
|
||||||
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -2273,12 +2233,6 @@ packages:
|
|||||||
builder-util@26.0.17:
|
builder-util@26.0.17:
|
||||||
resolution: {integrity: sha512-fym+vg0kegrHBSCmkYYql2EbsLvnlUhIUKRQJ7EHjyftwMz8mibpvTRll3pzK1rtWm/VRdjl7AB397jdtg/Jmw==}
|
resolution: {integrity: sha512-fym+vg0kegrHBSCmkYYql2EbsLvnlUhIUKRQJ7EHjyftwMz8mibpvTRll3pzK1rtWm/VRdjl7AB397jdtg/Jmw==}
|
||||||
|
|
||||||
bundle-require@5.1.0:
|
|
||||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
esbuild: '>=0.18'
|
|
||||||
|
|
||||||
busboy@1.6.0:
|
busboy@1.6.0:
|
||||||
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
||||||
engines: {node: '>=10.16.0'}
|
engines: {node: '>=10.16.0'}
|
||||||
@@ -2423,10 +2377,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
commander@4.1.1:
|
|
||||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
|
|
||||||
commander@5.1.0:
|
commander@5.1.0:
|
||||||
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
|
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -2446,16 +2396,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
||||||
engines: {'0': node >= 6.0}
|
engines: {'0': node >= 6.0}
|
||||||
|
|
||||||
confbox@0.1.8:
|
|
||||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
|
||||||
|
|
||||||
config-file-ts@0.2.6:
|
config-file-ts@0.2.6:
|
||||||
resolution: {integrity: sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==}
|
resolution: {integrity: sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==}
|
||||||
|
|
||||||
consola@3.4.2:
|
|
||||||
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
|
|
||||||
engines: {node: ^14.18.0 || >=16.10.0}
|
|
||||||
|
|
||||||
content-disposition@1.0.0:
|
content-disposition@1.0.0:
|
||||||
resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
|
resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -3042,9 +2985,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
fix-dts-default-cjs-exports@1.0.1:
|
|
||||||
resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}
|
|
||||||
|
|
||||||
flat-cache@3.1.1:
|
flat-cache@3.1.1:
|
||||||
resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==}
|
resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -3186,11 +3126,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
|
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
glob@11.0.3:
|
|
||||||
resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
glob@7.2.3:
|
glob@7.2.3:
|
||||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||||
deprecated: Glob versions prior to v9 are no longer supported
|
deprecated: Glob versions prior to v9 are no longer supported
|
||||||
@@ -3571,10 +3506,6 @@ packages:
|
|||||||
jackspeak@3.4.3:
|
jackspeak@3.4.3:
|
||||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||||
|
|
||||||
jackspeak@4.1.1:
|
|
||||||
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
|
|
||||||
jake@10.9.2:
|
jake@10.9.2:
|
||||||
resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
|
resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -3587,10 +3518,6 @@ packages:
|
|||||||
joi@17.13.3:
|
joi@17.13.3:
|
||||||
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
|
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
|
||||||
|
|
||||||
joycon@3.1.1:
|
|
||||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
|
|
||||||
js-tokens@4.0.0:
|
js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
@@ -3670,17 +3597,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
lilconfig@3.1.3:
|
|
||||||
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
|
||||||
engines: {node: '>=14'}
|
|
||||||
|
|
||||||
lines-and-columns@1.2.4:
|
lines-and-columns@1.2.4:
|
||||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
|
|
||||||
load-tsconfig@0.2.5:
|
|
||||||
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -3700,9 +3619,6 @@ packages:
|
|||||||
lodash.merge@4.6.2:
|
lodash.merge@4.6.2:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
|
|
||||||
lodash.sortby@4.7.0:
|
|
||||||
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
|
|
||||||
|
|
||||||
lodash.union@4.6.0:
|
lodash.union@4.6.0:
|
||||||
resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==}
|
resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==}
|
||||||
|
|
||||||
@@ -3734,10 +3650,6 @@ packages:
|
|||||||
lru-cache@10.4.3:
|
lru-cache@10.4.3:
|
||||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||||
|
|
||||||
lru-cache@11.2.1:
|
|
||||||
resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
|
|
||||||
lru-cache@5.1.1:
|
lru-cache@5.1.1:
|
||||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||||
|
|
||||||
@@ -3896,9 +3808,6 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
mlly@1.8.0:
|
|
||||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@@ -3906,9 +3815,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ug8bXeTIUlxurg8xLTEskKShvcKDZALo1THEX5E41pYCD2sCVub5/kIRIGqWNoqV6szyLyQKV6mD4QUrWE5GCQ==}
|
resolution: {integrity: sha512-Ug8bXeTIUlxurg8xLTEskKShvcKDZALo1THEX5E41pYCD2sCVub5/kIRIGqWNoqV6szyLyQKV6mD4QUrWE5GCQ==}
|
||||||
engines: {node: '>= 10.16.0'}
|
engines: {node: '>= 10.16.0'}
|
||||||
|
|
||||||
mz@2.7.0:
|
|
||||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
|
||||||
|
|
||||||
nanoid@3.3.11:
|
nanoid@3.3.11:
|
||||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
@@ -4093,10 +3999,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||||
engines: {node: '>=16 || 14 >=14.18'}
|
engines: {node: '>=16 || 14 >=14.18'}
|
||||||
|
|
||||||
path-scurry@2.0.0:
|
|
||||||
resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
|
|
||||||
path-to-regexp@8.2.0:
|
path-to-regexp@8.2.0:
|
||||||
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
|
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@@ -4119,6 +4021,9 @@ packages:
|
|||||||
pend@1.2.0:
|
pend@1.2.0:
|
||||||
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
||||||
|
|
||||||
|
picocolors@1.0.1:
|
||||||
|
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
|
||||||
|
|
||||||
picocolors@1.1.1:
|
picocolors@1.1.1:
|
||||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
@@ -4130,13 +4035,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
pirates@4.0.7:
|
|
||||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
|
|
||||||
pkg-types@1.3.1:
|
|
||||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
|
||||||
|
|
||||||
playwright-core@1.55.0:
|
playwright-core@1.55.0:
|
||||||
resolution: {integrity: sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==}
|
resolution: {integrity: sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4155,24 +4053,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
postcss-load-config@6.0.1:
|
|
||||||
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
|
|
||||||
engines: {node: '>= 18'}
|
|
||||||
peerDependencies:
|
|
||||||
jiti: '>=1.21.0'
|
|
||||||
postcss: '>=8.0.9'
|
|
||||||
tsx: ^4.8.1
|
|
||||||
yaml: ^2.4.2
|
|
||||||
peerDependenciesMeta:
|
|
||||||
jiti:
|
|
||||||
optional: true
|
|
||||||
postcss:
|
|
||||||
optional: true
|
|
||||||
tsx:
|
|
||||||
optional: true
|
|
||||||
yaml:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
postcss@8.5.4:
|
postcss@8.5.4:
|
||||||
resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==}
|
resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
@@ -4388,10 +4268,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
resolve-from@5.0.0:
|
|
||||||
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
|
|
||||||
resolve-pkg-maps@1.0.0:
|
resolve-pkg-maps@1.0.0:
|
||||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||||
|
|
||||||
@@ -4424,11 +4300,6 @@ packages:
|
|||||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
rimraf@6.0.1:
|
|
||||||
resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
roarr@2.15.4:
|
roarr@2.15.4:
|
||||||
resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==}
|
resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
@@ -4627,11 +4498,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
source-map@0.8.0-beta.0:
|
|
||||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
|
||||||
engines: {node: '>= 8'}
|
|
||||||
deprecated: The work that was done in this beta branch won't be included in future versions
|
|
||||||
|
|
||||||
sprintf-js@1.1.3:
|
sprintf-js@1.1.3:
|
||||||
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
|
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
|
||||||
|
|
||||||
@@ -4714,11 +4580,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
sucrase@3.35.0:
|
|
||||||
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
|
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
sumchecker@3.0.1:
|
sumchecker@3.0.1:
|
||||||
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
|
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
|
||||||
engines: {node: '>= 8.0'}
|
engines: {node: '>= 8.0'}
|
||||||
@@ -4765,13 +4626,6 @@ packages:
|
|||||||
text-table@0.2.0:
|
text-table@0.2.0:
|
||||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||||
|
|
||||||
thenify-all@1.6.0:
|
|
||||||
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
|
|
||||||
engines: {node: '>=0.8'}
|
|
||||||
|
|
||||||
thenify@3.3.1:
|
|
||||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
|
||||||
|
|
||||||
tiny-async-pool@1.3.0:
|
tiny-async-pool@1.3.0:
|
||||||
resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==}
|
resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==}
|
||||||
|
|
||||||
@@ -4823,17 +4677,10 @@ packages:
|
|||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
tr46@1.0.1:
|
|
||||||
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
|
|
||||||
|
|
||||||
tr46@3.0.0:
|
tr46@3.0.0:
|
||||||
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
|
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
tree-kill@1.2.2:
|
|
||||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
truncate-utf8-bytes@1.0.2:
|
truncate-utf8-bytes@1.0.2:
|
||||||
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
|
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
|
||||||
|
|
||||||
@@ -4857,9 +4704,6 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
ts-interface-checker@0.1.13:
|
|
||||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
|
||||||
|
|
||||||
tsconfck@3.1.6:
|
tsconfck@3.1.6:
|
||||||
resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
|
resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
|
||||||
engines: {node: ^18 || >=20}
|
engines: {node: ^18 || >=20}
|
||||||
@@ -4873,25 +4717,6 @@ packages:
|
|||||||
tslib@2.6.2:
|
tslib@2.6.2:
|
||||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||||
|
|
||||||
tsup@8.5.0:
|
|
||||||
resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
'@microsoft/api-extractor': ^7.36.0
|
|
||||||
'@swc/core': ^1
|
|
||||||
postcss: ^8.4.12
|
|
||||||
typescript: '>=4.5.0'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@microsoft/api-extractor':
|
|
||||||
optional: true
|
|
||||||
'@swc/core':
|
|
||||||
optional: true
|
|
||||||
postcss:
|
|
||||||
optional: true
|
|
||||||
typescript:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
tsx@4.20.5:
|
tsx@4.20.5:
|
||||||
resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==}
|
resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
@@ -4980,9 +4805,6 @@ packages:
|
|||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
ufo@1.6.1:
|
|
||||||
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
|
|
||||||
|
|
||||||
unbox-primitive@1.1.0:
|
unbox-primitive@1.1.0:
|
||||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -5172,9 +4994,6 @@ packages:
|
|||||||
webidl-conversions@3.0.1:
|
webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
webidl-conversions@4.0.2:
|
|
||||||
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
|
||||||
|
|
||||||
webidl-conversions@7.0.0:
|
webidl-conversions@7.0.0:
|
||||||
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -5201,9 +5020,6 @@ packages:
|
|||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||||
|
|
||||||
whatwg-url@7.1.0:
|
|
||||||
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
|
|
||||||
|
|
||||||
which-boxed-primitive@1.1.1:
|
which-boxed-primitive@1.1.1:
|
||||||
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
|
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -5361,7 +5177,7 @@ snapshots:
|
|||||||
'@babel/code-frame@7.24.2':
|
'@babel/code-frame@7.24.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/highlight': 7.24.5
|
'@babel/highlight': 7.24.5
|
||||||
picocolors: 1.1.1
|
picocolors: 1.0.1
|
||||||
|
|
||||||
'@babel/code-frame@7.27.1':
|
'@babel/code-frame@7.27.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5436,8 +5252,8 @@ snapshots:
|
|||||||
'@babel/generator@7.23.6':
|
'@babel/generator@7.23.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.2
|
||||||
'@jridgewell/gen-mapping': 0.3.13
|
'@jridgewell/gen-mapping': 0.3.3
|
||||||
'@jridgewell/trace-mapping': 0.3.30
|
'@jridgewell/trace-mapping': 0.3.20
|
||||||
jsesc: 2.5.2
|
jsesc: 2.5.2
|
||||||
|
|
||||||
'@babel/generator@7.27.5':
|
'@babel/generator@7.27.5':
|
||||||
@@ -5610,7 +5426,7 @@ snapshots:
|
|||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
chalk: 2.4.2
|
chalk: 2.4.2
|
||||||
js-tokens: 4.0.0
|
js-tokens: 4.0.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.0.1
|
||||||
|
|
||||||
'@babel/parser@7.23.6':
|
'@babel/parser@7.23.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6486,8 +6302,6 @@ snapshots:
|
|||||||
|
|
||||||
'@sindresorhus/is@4.6.0': {}
|
'@sindresorhus/is@4.6.0': {}
|
||||||
|
|
||||||
'@sprout2000/esbuild-copy-plugin@1.1.19': {}
|
|
||||||
|
|
||||||
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.23.6)':
|
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.23.6)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.23.6
|
'@babel/core': 7.23.6
|
||||||
@@ -6966,7 +6780,8 @@ snapshots:
|
|||||||
|
|
||||||
acorn@8.14.0: {}
|
acorn@8.14.0: {}
|
||||||
|
|
||||||
acorn@8.15.0: {}
|
acorn@8.15.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
adler-32@1.3.1: {}
|
adler-32@1.3.1: {}
|
||||||
|
|
||||||
@@ -7016,8 +6831,6 @@ snapshots:
|
|||||||
|
|
||||||
ansi-styles@6.2.1: {}
|
ansi-styles@6.2.1: {}
|
||||||
|
|
||||||
any-promise@1.3.0: {}
|
|
||||||
|
|
||||||
anymatch@3.1.3:
|
anymatch@3.1.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
normalize-path: 3.0.0
|
normalize-path: 3.0.0
|
||||||
@@ -7381,11 +7194,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
bundle-require@5.1.0(esbuild@0.25.5):
|
|
||||||
dependencies:
|
|
||||||
esbuild: 0.25.5
|
|
||||||
load-tsconfig: 0.2.5
|
|
||||||
|
|
||||||
busboy@1.6.0:
|
busboy@1.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
streamsearch: 1.1.0
|
streamsearch: 1.1.0
|
||||||
@@ -7553,8 +7361,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
commander@4.1.1: {}
|
|
||||||
|
|
||||||
commander@5.1.0: {}
|
commander@5.1.0: {}
|
||||||
|
|
||||||
compare-version@0.1.2: {}
|
compare-version@0.1.2: {}
|
||||||
@@ -7575,15 +7381,11 @@ snapshots:
|
|||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
typedarray: 0.0.6
|
typedarray: 0.0.6
|
||||||
|
|
||||||
confbox@0.1.8: {}
|
|
||||||
|
|
||||||
config-file-ts@0.2.6:
|
config-file-ts@0.2.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
glob: 10.4.5
|
glob: 10.4.5
|
||||||
typescript: 5.9.2
|
typescript: 5.9.2
|
||||||
|
|
||||||
consola@3.4.2: {}
|
|
||||||
|
|
||||||
content-disposition@1.0.0:
|
content-disposition@1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@@ -8389,12 +8191,6 @@ snapshots:
|
|||||||
locate-path: 6.0.0
|
locate-path: 6.0.0
|
||||||
path-exists: 4.0.0
|
path-exists: 4.0.0
|
||||||
|
|
||||||
fix-dts-default-cjs-exports@1.0.1:
|
|
||||||
dependencies:
|
|
||||||
magic-string: 0.30.17
|
|
||||||
mlly: 1.8.0
|
|
||||||
rollup: 4.41.1
|
|
||||||
|
|
||||||
flat-cache@3.1.1:
|
flat-cache@3.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
flatted: 3.2.9
|
flatted: 3.2.9
|
||||||
@@ -8566,15 +8362,6 @@ snapshots:
|
|||||||
package-json-from-dist: 1.0.1
|
package-json-from-dist: 1.0.1
|
||||||
path-scurry: 1.11.1
|
path-scurry: 1.11.1
|
||||||
|
|
||||||
glob@11.0.3:
|
|
||||||
dependencies:
|
|
||||||
foreground-child: 3.3.1
|
|
||||||
jackspeak: 4.1.1
|
|
||||||
minimatch: 10.0.3
|
|
||||||
minipass: 7.1.2
|
|
||||||
package-json-from-dist: 1.0.1
|
|
||||||
path-scurry: 2.0.0
|
|
||||||
|
|
||||||
glob@7.2.3:
|
glob@7.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
fs.realpath: 1.0.0
|
fs.realpath: 1.0.0
|
||||||
@@ -8993,10 +8780,6 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@pkgjs/parseargs': 0.11.0
|
'@pkgjs/parseargs': 0.11.0
|
||||||
|
|
||||||
jackspeak@4.1.1:
|
|
||||||
dependencies:
|
|
||||||
'@isaacs/cliui': 8.0.2
|
|
||||||
|
|
||||||
jake@10.9.2:
|
jake@10.9.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
async: 3.2.6
|
async: 3.2.6
|
||||||
@@ -9014,8 +8797,6 @@ snapshots:
|
|||||||
'@sideway/formula': 3.0.1
|
'@sideway/formula': 3.0.1
|
||||||
'@sideway/pinpoint': 2.0.0
|
'@sideway/pinpoint': 2.0.0
|
||||||
|
|
||||||
joycon@3.1.1: {}
|
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
|
|
||||||
js-yaml@4.1.0:
|
js-yaml@4.1.0:
|
||||||
@@ -9118,12 +8899,8 @@ snapshots:
|
|||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
|
|
||||||
lilconfig@3.1.3: {}
|
|
||||||
|
|
||||||
lines-and-columns@1.2.4: {}
|
lines-and-columns@1.2.4: {}
|
||||||
|
|
||||||
load-tsconfig@0.2.5: {}
|
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate: 5.0.0
|
p-locate: 5.0.0
|
||||||
@@ -9138,8 +8915,6 @@ snapshots:
|
|||||||
|
|
||||||
lodash.merge@4.6.2: {}
|
lodash.merge@4.6.2: {}
|
||||||
|
|
||||||
lodash.sortby@4.7.0: {}
|
|
||||||
|
|
||||||
lodash.union@4.6.0: {}
|
lodash.union@4.6.0: {}
|
||||||
|
|
||||||
lodash@4.17.21: {}
|
lodash@4.17.21: {}
|
||||||
@@ -9167,8 +8942,6 @@ snapshots:
|
|||||||
|
|
||||||
lru-cache@10.4.3: {}
|
lru-cache@10.4.3: {}
|
||||||
|
|
||||||
lru-cache@11.2.1: {}
|
|
||||||
|
|
||||||
lru-cache@5.1.1:
|
lru-cache@5.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
yallist: 3.1.1
|
yallist: 3.1.1
|
||||||
@@ -9320,13 +9093,6 @@ snapshots:
|
|||||||
|
|
||||||
mkdirp@1.0.4: {}
|
mkdirp@1.0.4: {}
|
||||||
|
|
||||||
mlly@1.8.0:
|
|
||||||
dependencies:
|
|
||||||
acorn: 8.15.0
|
|
||||||
pathe: 2.0.3
|
|
||||||
pkg-types: 1.3.1
|
|
||||||
ufo: 1.6.1
|
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
multer@2.0.1:
|
multer@2.0.1:
|
||||||
@@ -9339,12 +9105,6 @@ snapshots:
|
|||||||
type-is: 1.6.18
|
type-is: 1.6.18
|
||||||
xtend: 4.0.2
|
xtend: 4.0.2
|
||||||
|
|
||||||
mz@2.7.0:
|
|
||||||
dependencies:
|
|
||||||
any-promise: 1.3.0
|
|
||||||
object-assign: 4.1.1
|
|
||||||
thenify-all: 1.6.0
|
|
||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
nanoid@5.1.5: {}
|
nanoid@5.1.5: {}
|
||||||
@@ -9528,11 +9288,6 @@ snapshots:
|
|||||||
lru-cache: 10.4.3
|
lru-cache: 10.4.3
|
||||||
minipass: 7.1.2
|
minipass: 7.1.2
|
||||||
|
|
||||||
path-scurry@2.0.0:
|
|
||||||
dependencies:
|
|
||||||
lru-cache: 11.2.1
|
|
||||||
minipass: 7.1.2
|
|
||||||
|
|
||||||
path-to-regexp@8.2.0: {}
|
path-to-regexp@8.2.0: {}
|
||||||
|
|
||||||
path-type@4.0.0: {}
|
path-type@4.0.0: {}
|
||||||
@@ -9545,20 +9300,14 @@ snapshots:
|
|||||||
|
|
||||||
pend@1.2.0: {}
|
pend@1.2.0: {}
|
||||||
|
|
||||||
|
picocolors@1.0.1: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
picomatch@2.3.1: {}
|
picomatch@2.3.1: {}
|
||||||
|
|
||||||
picomatch@4.0.2: {}
|
picomatch@4.0.2: {}
|
||||||
|
|
||||||
pirates@4.0.7: {}
|
|
||||||
|
|
||||||
pkg-types@1.3.1:
|
|
||||||
dependencies:
|
|
||||||
confbox: 0.1.8
|
|
||||||
mlly: 1.8.0
|
|
||||||
pathe: 2.0.3
|
|
||||||
|
|
||||||
playwright-core@1.55.0: {}
|
playwright-core@1.55.0: {}
|
||||||
|
|
||||||
playwright@1.55.0:
|
playwright@1.55.0:
|
||||||
@@ -9575,14 +9324,6 @@ snapshots:
|
|||||||
|
|
||||||
possible-typed-array-names@1.1.0: {}
|
possible-typed-array-names@1.1.0: {}
|
||||||
|
|
||||||
postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.4)(tsx@4.20.5):
|
|
||||||
dependencies:
|
|
||||||
lilconfig: 3.1.3
|
|
||||||
optionalDependencies:
|
|
||||||
jiti: 2.4.2
|
|
||||||
postcss: 8.5.4
|
|
||||||
tsx: 4.20.5
|
|
||||||
|
|
||||||
postcss@8.5.4:
|
postcss@8.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.11
|
nanoid: 3.3.11
|
||||||
@@ -9793,8 +9534,6 @@ snapshots:
|
|||||||
|
|
||||||
resolve-from@4.0.0: {}
|
resolve-from@4.0.0: {}
|
||||||
|
|
||||||
resolve-from@5.0.0: {}
|
|
||||||
|
|
||||||
resolve-pkg-maps@1.0.0: {}
|
resolve-pkg-maps@1.0.0: {}
|
||||||
|
|
||||||
resolve@1.22.10:
|
resolve@1.22.10:
|
||||||
@@ -9826,11 +9565,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
glob: 7.2.3
|
glob: 7.2.3
|
||||||
|
|
||||||
rimraf@6.0.1:
|
|
||||||
dependencies:
|
|
||||||
glob: 11.0.3
|
|
||||||
package-json-from-dist: 1.0.1
|
|
||||||
|
|
||||||
roarr@2.15.4:
|
roarr@2.15.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolean: 3.2.0
|
boolean: 3.2.0
|
||||||
@@ -10098,10 +9832,6 @@ snapshots:
|
|||||||
|
|
||||||
source-map@0.6.1: {}
|
source-map@0.6.1: {}
|
||||||
|
|
||||||
source-map@0.8.0-beta.0:
|
|
||||||
dependencies:
|
|
||||||
whatwg-url: 7.1.0
|
|
||||||
|
|
||||||
sprintf-js@1.1.3:
|
sprintf-js@1.1.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -10204,16 +9934,6 @@ snapshots:
|
|||||||
|
|
||||||
strip-json-comments@3.1.1: {}
|
strip-json-comments@3.1.1: {}
|
||||||
|
|
||||||
sucrase@3.35.0:
|
|
||||||
dependencies:
|
|
||||||
'@jridgewell/gen-mapping': 0.3.13
|
|
||||||
commander: 4.1.1
|
|
||||||
glob: 10.4.5
|
|
||||||
lines-and-columns: 1.2.4
|
|
||||||
mz: 2.7.0
|
|
||||||
pirates: 4.0.7
|
|
||||||
ts-interface-checker: 0.1.13
|
|
||||||
|
|
||||||
sumchecker@3.0.1:
|
sumchecker@3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
@@ -10268,14 +9988,6 @@ snapshots:
|
|||||||
|
|
||||||
text-table@0.2.0: {}
|
text-table@0.2.0: {}
|
||||||
|
|
||||||
thenify-all@1.6.0:
|
|
||||||
dependencies:
|
|
||||||
thenify: 3.3.1
|
|
||||||
|
|
||||||
thenify@3.3.1:
|
|
||||||
dependencies:
|
|
||||||
any-promise: 1.3.0
|
|
||||||
|
|
||||||
tiny-async-pool@1.3.0:
|
tiny-async-pool@1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
semver: 5.7.2
|
semver: 5.7.2
|
||||||
@@ -10321,17 +10033,11 @@ snapshots:
|
|||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
tr46@1.0.1:
|
|
||||||
dependencies:
|
|
||||||
punycode: 2.3.1
|
|
||||||
|
|
||||||
tr46@3.0.0:
|
tr46@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
tree-kill@1.2.2: {}
|
|
||||||
|
|
||||||
truncate-utf8-bytes@1.0.2:
|
truncate-utf8-bytes@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
utf8-byte-length: 1.0.4
|
utf8-byte-length: 1.0.4
|
||||||
@@ -10348,42 +10054,12 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.5.3
|
typescript: 5.5.3
|
||||||
|
|
||||||
ts-interface-checker@0.1.13: {}
|
|
||||||
|
|
||||||
tsconfck@3.1.6(typescript@5.5.3):
|
tsconfck@3.1.6(typescript@5.5.3):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.5.3
|
typescript: 5.5.3
|
||||||
|
|
||||||
tslib@2.6.2: {}
|
tslib@2.6.2: {}
|
||||||
|
|
||||||
tsup@8.5.0(jiti@2.4.2)(postcss@8.5.4)(tsx@4.20.5)(typescript@5.5.3):
|
|
||||||
dependencies:
|
|
||||||
bundle-require: 5.1.0(esbuild@0.25.5)
|
|
||||||
cac: 6.7.14
|
|
||||||
chokidar: 4.0.3
|
|
||||||
consola: 3.4.2
|
|
||||||
debug: 4.4.1
|
|
||||||
esbuild: 0.25.5
|
|
||||||
fix-dts-default-cjs-exports: 1.0.1
|
|
||||||
joycon: 3.1.1
|
|
||||||
picocolors: 1.1.1
|
|
||||||
postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.4)(tsx@4.20.5)
|
|
||||||
resolve-from: 5.0.0
|
|
||||||
rollup: 4.41.1
|
|
||||||
source-map: 0.8.0-beta.0
|
|
||||||
sucrase: 3.35.0
|
|
||||||
tinyexec: 0.3.2
|
|
||||||
tinyglobby: 0.2.14
|
|
||||||
tree-kill: 1.2.2
|
|
||||||
optionalDependencies:
|
|
||||||
postcss: 8.5.4
|
|
||||||
typescript: 5.5.3
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- jiti
|
|
||||||
- supports-color
|
|
||||||
- tsx
|
|
||||||
- yaml
|
|
||||||
|
|
||||||
tsx@4.20.5:
|
tsx@4.20.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.5
|
esbuild: 0.25.5
|
||||||
@@ -10477,8 +10153,6 @@ snapshots:
|
|||||||
|
|
||||||
typescript@5.9.2: {}
|
typescript@5.9.2: {}
|
||||||
|
|
||||||
ufo@1.6.1: {}
|
|
||||||
|
|
||||||
unbox-primitive@1.1.0:
|
unbox-primitive@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@@ -10516,7 +10190,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.22.2
|
browserslist: 4.22.2
|
||||||
escalade: 3.1.1
|
escalade: 3.1.1
|
||||||
picocolors: 1.1.1
|
picocolors: 1.0.1
|
||||||
|
|
||||||
update-browserslist-db@1.1.3(browserslist@4.25.0):
|
update-browserslist-db@1.1.3(browserslist@4.25.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -10689,8 +10363,6 @@ snapshots:
|
|||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
||||||
webidl-conversions@4.0.2: {}
|
|
||||||
|
|
||||||
webidl-conversions@7.0.0:
|
webidl-conversions@7.0.0:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -10717,12 +10389,6 @@ snapshots:
|
|||||||
tr46: 0.0.3
|
tr46: 0.0.3
|
||||||
webidl-conversions: 3.0.1
|
webidl-conversions: 3.0.1
|
||||||
|
|
||||||
whatwg-url@7.1.0:
|
|
||||||
dependencies:
|
|
||||||
lodash.sortby: 4.7.0
|
|
||||||
tr46: 1.0.1
|
|
||||||
webidl-conversions: 4.0.2
|
|
||||||
|
|
||||||
which-boxed-primitive@1.1.1:
|
which-boxed-primitive@1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-bigint: 1.1.0
|
is-bigint: 1.1.0
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ catalog:
|
|||||||
eslint-config-prettier: 9.1.0
|
eslint-config-prettier: 9.1.0
|
||||||
eslint-plugin-prettier: 5.1.3
|
eslint-plugin-prettier: 5.1.3
|
||||||
vitest: 3.2.1
|
vitest: 3.2.1
|
||||||
rimraf: 6.0.1
|
|
||||||
ts-essentials: 10.1.1
|
|
||||||
onlyBuiltDependencies:
|
onlyBuiltDependencies:
|
||||||
- electron
|
- electron
|
||||||
- esbuild
|
- esbuild
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"allowUnreachableCode": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,9 +26,6 @@
|
|||||||
"cache": false
|
"cache": false
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"dependsOn": [
|
|
||||||
"^build"
|
|
||||||
],
|
|
||||||
"env": ["SENTRY_AUTH_TOKEN"]
|
"env": ["SENTRY_AUTH_TOKEN"]
|
||||||
},
|
},
|
||||||
"build:local": {},
|
"build:local": {},
|
||||||
|
|||||||
Reference in New Issue
Block a user