Compare commits

..

1 Commits

Author SHA1 Message Date
arc-alex d89309a120 lock cusheet edits 2025-05-27 15:33:39 +02:00
52 changed files with 774 additions and 1942 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

+6 -6
View File
@@ -14,12 +14,12 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 20
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v3 uses: pnpm/action-setup@v3
with: with:
version: 10 version: 9
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -56,12 +56,12 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 20
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v3 uses: pnpm/action-setup@v3
with: with:
version: 10 version: 9
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -89,12 +89,12 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 20
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v3 uses: pnpm/action-setup@v3
with: with:
version: 10 version: 9
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
+2 -2
View File
@@ -20,13 +20,13 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 20
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v3 uses: pnpm/action-setup@v3
with: with:
version: 10 version: 9
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
+4 -4
View File
@@ -17,12 +17,12 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 20
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v3 uses: pnpm/action-setup@v3
with: with:
version: 10 version: 9
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -73,12 +73,12 @@ jobs:
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 20
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v3 uses: pnpm/action-setup@v3
with: with:
version: 10 version: 9
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
+1 -1
View File
@@ -1 +1 @@
v22.15.1 v20.15.1
+2 -2
View File
@@ -9,8 +9,8 @@ Ontime consists of 3 distinct parts
The steps below will assume you have locally installed the necessary dependencies. The steps below will assume you have locally installed the necessary dependencies.
Other dependencies will be installed as part of the setup Other dependencies will be installed as part of the setup
- __node__ (~22) - __node__ (~20)
- __pnpm__ (~10) - __pnpm__ (~9)
- __docker__ (only necessary to run and build docker images) - __docker__ (only necessary to run and build docker images)
## LOCAL DEVELOPMENT ## LOCAL DEVELOPMENT
+3 -3
View File
@@ -1,13 +1,13 @@
FROM node:22-bullseye AS builder FROM node:20-bullseye AS builder
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
RUN npm install -g pnpm@10.11.0 RUN npm install -g pnpm@9.5.0
COPY . /app COPY . /app
WORKDIR /app WORKDIR /app
RUN pnpm --filter=ontime-ui --filter=ontime-server --filter=ontime-utils install --config.dedupe-peer-dependents=false --frozen-lockfile RUN pnpm --filter=ontime-ui --filter=ontime-server --filter=ontime-utils install --config.dedupe-peer-dependents=false --frozen-lockfile
RUN pnpm --filter=ontime-ui --filter=ontime-server run build:docker RUN pnpm --filter=ontime-ui --filter=ontime-server run build:docker
FROM node:22-alpine FROM node:20-alpine
# Set environment variables # Set environment variables
# Environment Variable to signal that we are running production # Environment Variable to signal that we are running production
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@getontime/cli", "name": "@getontime/cli",
"version": "3.16.1", "version": "3.15.2",
"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",
+6 -6
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime-ui", "name": "ontime-ui",
"version": "3.16.1", "version": "3.15.2",
"private": true, "private": true,
"type": "module", "type": "module",
"dependencies": { "dependencies": {
@@ -72,7 +72,7 @@
"@types/react-dom": "^18.0.10", "@types/react-dom": "^18.0.10",
"@typescript-eslint/eslint-plugin": "catalog:", "@typescript-eslint/eslint-plugin": "catalog:",
"@typescript-eslint/parser": "catalog:", "@typescript-eslint/parser": "catalog:",
"@vitejs/plugin-react": "4.5.1", "@vitejs/plugin-react": "^4.2.1",
"eslint": "catalog:", "eslint": "catalog:",
"eslint-config-prettier": "catalog:", "eslint-config-prettier": "catalog:",
"eslint-plugin-jest": "^28.6.0", "eslint-plugin-jest": "^28.6.0",
@@ -86,10 +86,10 @@
"prettier": "catalog:", "prettier": "catalog:",
"sass": "^1.57.1", "sass": "^1.57.1",
"typescript": "catalog:", "typescript": "catalog:",
"vite": "6.3.1", "vite": "^5.2.11",
"vite-plugin-compression2": "1.4.0", "vite-plugin-compression2": "^1.3.3",
"vite-plugin-svgr": "4.3.0", "vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "5.1.4", "vite-tsconfig-paths": "^4.3.1",
"vitest": "catalog:" "vitest": "catalog:"
} }
} }
@@ -25,4 +25,4 @@ export const AutoTextArea = (props: TextareaProps & { inputref: RefObject<unknow
{...props} {...props}
/> />
); );
}; };
@@ -1,7 +1,6 @@
import { IoChevronDown } from 'react-icons/io5'; import { IoChevronDown } from 'react-icons/io5';
import { useLocalStorage } from '@mantine/hooks'; import { useLocalStorage } from '@mantine/hooks';
import { baseURI } from '../../../externals';
import { cx } from '../../utils/styleUtils'; import { cx } from '../../utils/styleUtils';
import ParamInput from './ParamInput'; import ParamInput from './ParamInput';
@@ -18,7 +17,7 @@ interface ViewParamsSectionProps {
export default function ViewParamsSection(props: ViewParamsSectionProps) { export default function ViewParamsSection(props: ViewParamsSectionProps) {
const { title, collapsible, options } = props; const { title, collapsible, options } = props;
const [collapsed, setCollapsed] = useLocalStorage({ key: `${baseURI}params-${title}`, defaultValue: false }); const [collapsed, setCollapsed] = useLocalStorage({ key: `params-${title}`, defaultValue: false });
const handleCollapse = () => { const handleCollapse = () => {
if (collapsible) { if (collapsible) {
@@ -1,6 +1,5 @@
import { createContext, PropsWithChildren, useCallback, useEffect, useState } from 'react'; import { createContext, PropsWithChildren, useCallback, useEffect, useState } from 'react';
import { baseURI } from '../../externals';
import useSettings from '../hooks-query/useSettings'; import useSettings from '../hooks-query/useSettings';
interface AppContextType { interface AppContextType {
@@ -27,7 +26,7 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
useEffect(() => { useEffect(() => {
if (status === 'pending') return; if (status === 'pending') return;
const previousEditor = sessionStorage.getItem(`${baseURI}${storageKeys.editor}`); const previousEditor = sessionStorage.getItem(storageKeys.editor);
if (previousEditor && previousEditor === data.editorKey) { if (previousEditor && previousEditor === data.editorKey) {
setEditorAuth(true); setEditorAuth(true);
@@ -35,7 +34,7 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
setEditorAuth(data.editorKey == null || data.editorKey === ''); setEditorAuth(data.editorKey == null || data.editorKey === '');
} }
const previousOperator = sessionStorage.getItem(`${baseURI}${storageKeys.operator}`); const previousOperator = sessionStorage.getItem(storageKeys.operator);
if (previousOperator && previousOperator === data.operatorKey) { if (previousOperator && previousOperator === data.operatorKey) {
setOperatorAuth(true); setOperatorAuth(true);
} else { } else {
@@ -56,14 +55,14 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
if (permission === 'editor') { if (permission === 'editor') {
const correct = isValid(pin, data.editorKey); const correct = isValid(pin, data.editorKey);
if (correct) { if (correct) {
sessionStorage.setItem(`${baseURI}${storageKeys.editor}`, pin); sessionStorage.setItem(storageKeys.editor, pin);
} }
setEditorAuth(correct); setEditorAuth(correct);
return correct; return correct;
} else if (permission === 'operator') { } else if (permission === 'operator') {
const correct = isValid(pin, data.operatorKey); const correct = isValid(pin, data.operatorKey);
if (correct) { if (correct) {
sessionStorage.setItem(`${baseURI}${storageKeys.operator}`, pin); sessionStorage.setItem(storageKeys.operator, pin);
} }
setOperatorAuth(correct); setOperatorAuth(correct);
return correct; return correct;
@@ -41,7 +41,7 @@ export function useFlatRundown() {
// update data whenever the revision changes // update data whenever the revision changes
useEffect(() => { useEffect(() => {
if (data.revision !== -1 || data.revision !== prevRevision) { if (data.revision !== -1 && data.revision !== prevRevision) {
const flatRundown = data.order.map((id) => data.rundown[id]); const flatRundown = data.order.map((id) => data.rundown[id]);
setFlatRunDown(flatRundown); setFlatRunDown(flatRundown);
setPrevRevision(data.revision); setPrevRevision(data.revision);
@@ -1,14 +1,12 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { baseURI } from '../../externals';
export enum AppMode { export enum AppMode {
Run = 'run', Run = 'run',
Edit = 'edit', Edit = 'edit',
Freeze = 'freeze', Freeze = 'freeze',
} }
const appModeKey = `${baseURI}ontime-app-mode`; const appModeKey = 'ontime-app-mode';
function getModeFromSession() { function getModeFromSession() {
return sessionStorage.getItem(appModeKey) === AppMode.Run ? AppMode.Run : AppMode.Edit; return sessionStorage.getItem(appModeKey) === AppMode.Run ? AppMode.Run : AppMode.Edit;
+1 -3
View File
@@ -1,8 +1,6 @@
import { ClientList } from 'ontime-types'; import { ClientList } from 'ontime-types';
import { create } from 'zustand'; import { create } from 'zustand';
import { baseURI } from '../../externals';
interface ClientStore { interface ClientStore {
name?: string; name?: string;
setName: (newValue: string) => void; setName: (newValue: string) => void;
@@ -17,7 +15,7 @@ interface ClientStore {
setClients: (clients: ClientList) => void; setClients: (clients: ClientList) => void;
} }
const clientNameKey = `${baseURI}ontime-client-name`; const clientNameKey = 'ontime-client-name';
function persistNameInStorage(newValue: string) { function persistNameInStorage(newValue: string) {
localStorage.setItem(clientNameKey, newValue); localStorage.setItem(clientNameKey, newValue);
+2 -4
View File
@@ -1,8 +1,6 @@
// eslint-disable-next-line simple-import-sort/imports
import { create } from 'zustand'; import { create } from 'zustand';
import { booleanFromLocalStorage } from '../utils/localStorage'; import { booleanFromLocalStorage } from '../utils/localStorage';
import { baseURI } from '../../externals';
enum LocalEventKeys { enum LocalEventKeys {
Mirror = 'ontime-view-mirror', Mirror = 'ontime-view-mirror',
@@ -14,11 +12,11 @@ type ViewOptionsStore = {
}; };
export const useViewOptionsStore = create<ViewOptionsStore>()((set) => ({ export const useViewOptionsStore = create<ViewOptionsStore>()((set) => ({
mirror: booleanFromLocalStorage(`${baseURI}${LocalEventKeys.Mirror}`, false), mirror: booleanFromLocalStorage(LocalEventKeys.Mirror, false),
toggleMirror: (newValue?: boolean) => toggleMirror: (newValue?: boolean) =>
set((state) => { set((state) => {
const val = typeof newValue === 'undefined' ? !state.mirror : newValue; const val = typeof newValue === 'undefined' ? !state.mirror : newValue;
localStorage.setItem(`${baseURI}${LocalEventKeys.Mirror}`, String(val)); localStorage.setItem(LocalEventKeys.Mirror, String(val));
return { mirror: val }; return { mirror: val };
}), }),
})); }));
@@ -2,4 +2,4 @@
exports[`cx() > ignores falsy values 1`] = `""`; exports[`cx() > ignores falsy values 1`] = `""`;
exports[`cx() > merges styles 1`] = `"_test_d5d33f _another_d5d33f"`; exports[`cx() > merges styles 1`] = `"_test_98a1e0 _another_98a1e0"`;
+1
View File
@@ -31,6 +31,7 @@ declare module '@tanstack/react-table' {
options: { options: {
showDelayedTimes: boolean; showDelayedTimes: boolean;
hideTableSeconds: boolean; hideTableSeconds: boolean;
allowEdits: boolean;
}; };
} }
} }
@@ -1,7 +1,5 @@
import { ImportCustom, ImportMap } from 'ontime-utils'; import { ImportCustom, ImportMap } from 'ontime-utils';
import { baseURI } from '../../../../../externals';
export type NamedImportMap = typeof namedImportMap; export type NamedImportMap = typeof namedImportMap;
// Record of label and import name // Record of label and import name
@@ -66,11 +64,11 @@ export function convertToImportMap(namedImportMap: NamedImportMap): ImportMap {
} }
export function persistImportMap(options: NamedImportMap) { export function persistImportMap(options: NamedImportMap) {
localStorage.setItem(`${baseURI}ontime-import-options`, JSON.stringify(options)); localStorage.setItem('ontime-import-options', JSON.stringify(options));
} }
function getPersistImportMap(): unknown { function getPersistImportMap(): unknown {
const options = localStorage.getItem(`${baseURI}ontime-import-options`); const options = localStorage.getItem('ontime-import-options');
if (!options) { if (!options) {
throw new Error('no import options found'); throw new Error('no import options found');
} }
@@ -6,7 +6,6 @@ import { MILLIS_PER_HOUR, MILLIS_PER_SECOND, parseUserTime } from 'ontime-utils'
import TimeInput from '../../../../common/components/input/time-input/TimeInput'; import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import { setPlayback } from '../../../../common/hooks/useSocket'; import { setPlayback } from '../../../../common/hooks/useSocket';
import { baseURI } from '../../../../externals';
import { tooltipDelayMid } from '../../../../ontimeConfig'; import { tooltipDelayMid } from '../../../../ontimeConfig';
import TapButton from '../tap-button/TapButton'; import TapButton from '../tap-button/TapButton';
@@ -18,7 +17,7 @@ interface AddTimeProps {
export default function AddTime(props: AddTimeProps) { export default function AddTime(props: AddTimeProps) {
const { playback } = props; const { playback } = props;
const [time, setTime] = useLocalStorage({ key: `${baseURI}add-time`, defaultValue: 300_000 }); // 5 minutes const [time, setTime] = useLocalStorage({ key: 'add-time', defaultValue: 300_000 }); // 5 minutes
const handleTimeChange = (_field: string, value: string) => { const handleTimeChange = (_field: string, value: string) => {
const newTime = parseUserTime(value); const newTime = parseUserTime(value);
@@ -96,7 +96,6 @@ describe('makeTable()', () => {
"Is Public? (x)", "Is Public? (x)",
"Skip?", "Skip?",
"lighting", "lighting",
"Type",
], ],
[ [
"00:00:00", "00:00:00",
@@ -110,7 +109,6 @@ describe('makeTable()', () => {
"x", "x",
"", "",
"", "",
"",
], ],
] ]
`); `);
@@ -1,4 +1,5 @@
import { useCallback, useRef } from 'react'; import { useCallback, useRef } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useTableNav } from '@table-nav/react'; import { useTableNav } from '@table-nav/react';
import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table';
import { isOntimeEvent, MaybeString, OntimeEvent, OntimeRundown, OntimeRundownEntry, TimeField } from 'ontime-types'; import { isOntimeEvent, MaybeString, OntimeEvent, OntimeRundown, OntimeRundownEntry, TimeField } from 'ontime-types';
@@ -25,6 +26,9 @@ export default function CuesheetTable(props: CuesheetTableProps) {
const { data, columns, showModal } = props; const { data, columns, showModal } = props;
const { updateEvent, updateTimer } = useEventAction(); const { updateEvent, updateTimer } = useEventAction();
const [searchParams] = useSearchParams();
const blockEdits = searchParams.get('locked') ?? false;
const { followSelected, showDelayedTimes, hideTableSeconds } = useCuesheetOptions(); const { followSelected, showDelayedTimes, hideTableSeconds } = useCuesheetOptions();
const { columnVisibility, columnOrder, columnSizing, resetColumnOrder, setColumnVisibility, setColumnSizing } = const { columnVisibility, columnOrder, columnSizing, resetColumnOrder, setColumnVisibility, setColumnSizing } =
useColumnManager(columns); useColumnManager(columns);
@@ -77,6 +81,7 @@ export default function CuesheetTable(props: CuesheetTableProps) {
options: { options: {
showDelayedTimes, showDelayedTimes,
hideTableSeconds, hideTableSeconds,
allowEdits: !blockEdits,
}, },
}, },
}); });
@@ -29,7 +29,6 @@ interface EventRowProps {
export default memo(EventRow, (prevProps, nextProps) => { export default memo(EventRow, (prevProps, nextProps) => {
return ( return (
prevProps.rowId === nextProps.rowId && prevProps.rowId === nextProps.rowId &&
prevProps.event.id === nextProps.event.id &&
prevProps.event.revision === nextProps.event.revision && prevProps.event.revision === nextProps.event.revision &&
prevProps.eventIndex === nextProps.eventIndex && prevProps.eventIndex === nextProps.eventIndex &&
prevProps.rowIndex === nextProps.rowIndex && prevProps.rowIndex === nextProps.rowIndex &&
@@ -6,12 +6,13 @@ import useReactiveTextInput from '../../../../common/components/input/text-input
interface MultiLineCellProps { interface MultiLineCellProps {
initialValue: string; initialValue: string;
handleUpdate: (newValue: string) => void; handleUpdate: (newValue: string) => void;
allowEdits?: boolean;
} }
export default memo(MultiLineCell); export default memo(MultiLineCell);
function MultiLineCell(props: MultiLineCellProps) { function MultiLineCell(props: MultiLineCellProps) {
const { initialValue, handleUpdate } = props; const { initialValue, handleUpdate, allowEdits } = props;
const ref = useRef<HTMLInputElement | null>(null); const ref = useRef<HTMLInputElement | null>(null);
const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]); const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]);
@@ -38,6 +39,7 @@ function MultiLineCell(props: MultiLineCellProps) {
onBlur={onBlur} onBlur={onBlur}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
spellCheck={false} spellCheck={false}
isDisabled={!allowEdits}
/> />
); );
} }
@@ -1,17 +1,18 @@
import { forwardRef, memo, useCallback, useImperativeHandle, useRef } from 'react'; import { forwardRef, memo, useCallback, useImperativeHandle, useRef } from 'react';
import { Input } from '@chakra-ui/react'; import { Input, Text } from '@chakra-ui/react';
import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput'; import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput';
interface SingleLineCellProps { interface SingleLineCellProps {
initialValue: string; initialValue: string;
allowSubmitSameValue?: boolean; allowSubmitSameValue?: boolean;
allowEdits?: boolean;
handleUpdate: (newValue: string) => void; handleUpdate: (newValue: string) => void;
handleCancelUpdate?: () => void; handleCancelUpdate?: () => void;
} }
const SingleLineCell = forwardRef((props: SingleLineCellProps, inputRef) => { const SingleLineCell = forwardRef((props: SingleLineCellProps, inputRef) => {
const { initialValue, allowSubmitSameValue, handleUpdate, handleCancelUpdate } = props; const { initialValue, allowSubmitSameValue, handleUpdate, handleCancelUpdate, allowEdits } = props;
const ref = useRef<HTMLInputElement | null>(null); const ref = useRef<HTMLInputElement | null>(null);
const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]); const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]);
@@ -38,6 +39,14 @@ const SingleLineCell = forwardRef((props: SingleLineCellProps, inputRef) => {
}; };
}, [ref]); }, [ref]);
if (allowEdits === false) {
return (
<Text ref={ref} size='sm' variant='ontime-transparent' padding={0} fontSize='md'>
{initialValue}
</Text>
);
}
return ( return (
<Input <Input
ref={ref} ref={ref}
@@ -8,6 +8,7 @@ interface TimeInputDurationProps {
initialValue: number; initialValue: number;
lockedValue: boolean; lockedValue: boolean;
delayed?: boolean; delayed?: boolean;
allowEdits?: boolean;
onSubmit: (value: string) => void; onSubmit: (value: string) => void;
} }
@@ -18,7 +19,7 @@ interface ParentFocusableInput extends HTMLInputElement {
export default memo(TimeInputDuration); export default memo(TimeInputDuration);
function TimeInputDuration(props: PropsWithChildren<TimeInputDurationProps>) { function TimeInputDuration(props: PropsWithChildren<TimeInputDurationProps>) {
const { initialValue, lockedValue, delayed, onSubmit, children } = props; const { initialValue, lockedValue, delayed, onSubmit, children, allowEdits } = props;
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [value, setValue] = useState(initialValue); const [value, setValue] = useState(initialValue);
@@ -86,7 +87,7 @@ function TimeInputDuration(props: PropsWithChildren<TimeInputDurationProps>) {
const timeString = millisToString(value); const timeString = millisToString(value);
return isEditing ? ( return isEditing && allowEdits ? (
<SingleLineCell <SingleLineCell
ref={inputRef} ref={inputRef}
initialValue={timeString} initialValue={timeString}
@@ -32,7 +32,13 @@ function MakeStart({ getValue, row, table }: CellContext<OntimeRundownEntry, unk
} }
return ( return (
<TimeInput initialValue={startTime} onSubmit={update} lockedValue={isStartLocked} delayed={delayValue !== 0}> <TimeInput
initialValue={startTime}
onSubmit={update}
lockedValue={isStartLocked}
delayed={delayValue !== 0}
allowEdits={table.options.meta?.options.allowEdits}
>
{formattedTime} {formattedTime}
<DelayIndicator delayValue={delayValue} tooltipPrefix={millisToString(startTime)} /> <DelayIndicator delayValue={delayValue} tooltipPrefix={millisToString(startTime)} />
</TimeInput> </TimeInput>
@@ -60,7 +66,13 @@ function MakeEnd({ getValue, row, table }: CellContext<OntimeRundownEntry, unkno
} }
return ( return (
<TimeInput initialValue={endTime} onSubmit={update} lockedValue={isEndLocked} delayed={delayValue !== 0}> <TimeInput
initialValue={endTime}
onSubmit={update}
lockedValue={isEndLocked}
delayed={delayValue !== 0}
allowEdits={table.options.meta?.options.allowEdits}
>
{formattedTime} {formattedTime}
<DelayIndicator delayValue={delayValue} tooltipPrefix={millisToString(endTime)} /> <DelayIndicator delayValue={delayValue} tooltipPrefix={millisToString(endTime)} />
</TimeInput> </TimeInput>
@@ -81,7 +93,12 @@ function MakeDuration({ getValue, row, table }: CellContext<OntimeRundownEntry,
const formattedDuration = formatDuration(duration, false); const formattedDuration = formatDuration(duration, false);
return ( return (
<TimeInput initialValue={duration} onSubmit={update} lockedValue={isDurationLocked}> <TimeInput
initialValue={duration}
onSubmit={update}
lockedValue={isDurationLocked}
allowEdits={table.options.meta?.options.allowEdits}
>
{formattedDuration} {formattedDuration}
</TimeInput> </TimeInput>
); );
@@ -103,7 +120,13 @@ function MakeMultiLineField({ row, column, table }: CellContext<OntimeRundownEnt
const initialValue = event[column.id as keyof OntimeRundownEntry] ?? ''; const initialValue = event[column.id as keyof OntimeRundownEntry] ?? '';
return <MultiLineCell initialValue={initialValue} handleUpdate={update} />; return (
<MultiLineCell
initialValue={initialValue}
handleUpdate={update}
allowEdits={table.options.meta?.options.allowEdits}
/>
);
} }
function LazyImage({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) { function LazyImage({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
@@ -140,7 +163,13 @@ function MakeSingleLineField({ row, column, table }: CellContext<OntimeRundownEn
const initialValue = event[column.id as keyof OntimeRundownEntry] ?? ''; const initialValue = event[column.id as keyof OntimeRundownEntry] ?? '';
return <SingleLineCell initialValue={initialValue} handleUpdate={update} />; return (
<SingleLineCell
initialValue={initialValue}
handleUpdate={update}
allowEdits={table.options.meta?.options.allowEdits}
/>
);
} }
function MakeCustomField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) { function MakeCustomField({ row, column, table }: CellContext<OntimeRundownEntry, unknown>) {
@@ -158,7 +187,13 @@ function MakeCustomField({ row, column, table }: CellContext<OntimeRundownEntry,
} }
const initialValue = event.custom[column.id] ?? ''; const initialValue = event.custom[column.id] ?? '';
return <MultiLineCell initialValue={initialValue} handleUpdate={update} />; return (
<MultiLineCell
initialValue={initialValue}
handleUpdate={update}
allowEdits={table.options.meta?.options.allowEdits}
/>
);
} }
export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<OntimeRundownEntry>[] { export function makeCuesheetColumns(customFields: CustomFields): ColumnDef<OntimeRundownEntry>[] {
@@ -3,18 +3,13 @@ import { useLocalStorage } from '@mantine/hooks';
import { ColumnDef } from '@tanstack/react-table'; import { ColumnDef } from '@tanstack/react-table';
import { OntimeRundownEntry } from 'ontime-types'; import { OntimeRundownEntry } from 'ontime-types';
import { baseURI } from '../../../externals';
export default function useColumnManager(columns: ColumnDef<OntimeRundownEntry>[]) { export default function useColumnManager(columns: ColumnDef<OntimeRundownEntry>[]) {
const [columnVisibility, setColumnVisibility] = useLocalStorage({ key: `${baseURI}table-hidden`, defaultValue: {} }); const [columnVisibility, setColumnVisibility] = useLocalStorage({ key: 'table-hidden', defaultValue: {} });
const [columnOrder, saveColumnOrder] = useLocalStorage<string[]>({ const [columnOrder, saveColumnOrder] = useLocalStorage<string[]>({
key: `${baseURI}table-order`, key: 'table-order',
defaultValue: columns.map((col) => col.id as string), defaultValue: columns.map((col) => col.id as string),
}); });
const [columnSizing, setColumnSizing] = useLocalStorage({ const [columnSizing, setColumnSizing] = useLocalStorage({ key: 'table-sizes', defaultValue: {} });
key: `${baseURI}table-sizes`,
defaultValue: {},
});
// if the columns change, we update the dataset // if the columns change, we update the dataset
useEffect(() => { useEffect(() => {
@@ -59,7 +59,6 @@ export const makeTable = (headerData: ProjectData, rundown: OntimeRundown, custo
'isPublic', 'isPublic',
'skip', 'skip',
...customFieldKeys, ...customFieldKeys,
'type',
]; ];
const fieldTitles = [ const fieldTitles = [
@@ -74,7 +73,6 @@ export const makeTable = (headerData: ProjectData, rundown: OntimeRundown, custo
'Is Public? (x)', 'Is Public? (x)',
'Skip?', 'Skip?',
...customFieldLabels, ...customFieldLabels,
'Type',
]; ];
// add header row to data // add header row to data
+3 -3
View File
@@ -70,9 +70,9 @@ export default defineConfig({
preprocessorOptions: { preprocessorOptions: {
scss: { scss: {
additionalData: ` additionalData: `
@use '@/theme/ontimeColours' as *; @use './src/theme/ontimeColours' as *;
@use '@/theme/ontimeStyles' as *; @use './src/theme/ontimeStyles' as *;
@use '@/theme/mixins' as *; @use './src/theme/mixins' as *;
`, `,
}, },
}, },
+6 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime-electron", "name": "ontime-electron",
"version": "3.16.1", "version": "3.15.2",
"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",
@@ -12,8 +12,8 @@
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"main": "src/main.js", "main": "src/main.js",
"devDependencies": { "devDependencies": {
"electron": "36.3.1", "electron": "^31.2.0",
"electron-builder": "26.0.12", "electron-builder": "^24.13.3",
"eslint": "catalog:", "eslint": "catalog:",
"eslint-config-prettier": "catalog:", "eslint-config-prettier": "catalog:",
"prettier": "catalog:", "prettier": "catalog:",
@@ -38,7 +38,9 @@
"icon": "icon.icns" "icon": "icon.icns"
}, },
"mac": { "mac": {
"notarize": true, "notarize": {
"teamId": "MDAU6QK6R4"
},
"hardenedRuntime": true, "hardenedRuntime": true,
"gatekeeperAssess": false, "gatekeeperAssess": false,
"entitlements": "./entitlements.plist", "entitlements": "./entitlements.plist",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ontime-server", "name": "ontime-server",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"version": "3.16.1", "version": "3.15.2",
"exports": "./src/index.js", "exports": "./src/index.js",
"dependencies": { "dependencies": {
"@googleapis/sheets": "^5.0.5", "@googleapis/sheets": "^5.0.5",
+1 -1
View File
@@ -5,7 +5,7 @@ import * as dgram from 'node:dgram';
import { logger } from '../classes/Logger.js'; import { logger } from '../classes/Logger.js';
import { dispatchFromAdapter } from '../api-integration/integration.controller.js'; import { dispatchFromAdapter } from '../api-integration/integration.controller.js';
import { isOntimeCloud } from '../setup/environment.js'; import { isOntimeCloud } from '../externals.js';
import { integrationPayloadFromPath } from './utils/parse.js'; import { integrationPayloadFromPath } from './utils/parse.js';
import type { IAdapter } from './IAdapter.js'; import type { IAdapter } from './IAdapter.js';
@@ -12,7 +12,7 @@ import { getPropertyFromPath } from 'ontime-utils';
import { logger } from '../../classes/Logger.js'; import { logger } from '../../classes/Logger.js';
import { getState, type RuntimeState } from '../../stores/runtimeState.js'; import { getState, type RuntimeState } from '../../stores/runtimeState.js';
import { isOntimeCloud } from '../../setup/environment.js'; import { isOntimeCloud } from '../../externals.js';
import { emitOSC } from './clients/osc.client.js'; import { emitOSC } from './clients/osc.client.js';
import { emitHTTP } from './clients/http.client.js'; import { emitHTTP } from './clients/http.client.js';
@@ -10,7 +10,6 @@ import { getNetworkInterfaces } from '../../utils/network.js';
import { getTimezoneLabel } from '../../utils/time.js'; import { getTimezoneLabel } from '../../utils/time.js';
import { password, routerPrefix } from '../../externals.js'; import { password, routerPrefix } from '../../externals.js';
import { hashPassword } from '../../utils/hash.js'; import { hashPassword } from '../../utils/hash.js';
import { ONTIME_VERSION } from '../../ONTIME_VERSION.js';
const startedAt = new Date(); const startedAt = new Date();
@@ -29,7 +28,6 @@ export async function getSessionStats(): Promise<SessionStats> {
projectName, projectName,
playback, playback,
timezone: getTimezoneLabel(startedAt), timezone: getTimezoneLabel(startedAt),
version: ONTIME_VERSION,
}; };
} }
@@ -3,7 +3,7 @@ import { getErrorMessage, obfuscate } from 'ontime-utils';
import type { Request, Response } from 'express'; import type { Request, Response } from 'express';
import { isDocker } from '../../setup/environment.js'; import { isDocker } from '../../externals.js';
import { failEmptyObjects } from '../../utils/routerUtils.js'; import { failEmptyObjects } from '../../utils/routerUtils.js';
import { getDataProvider } from '../../classes/data-provider/DataProvider.js'; import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
import * as appState from '../../services/app-state-service/AppStateService.js'; import * as appState from '../../services/app-state-service/AppStateService.js';
+1 -2
View File
@@ -9,8 +9,7 @@ import cookieParser from 'cookie-parser';
// import utils // import utils
import { publicDir, srcDir } from './setup/index.js'; import { publicDir, srcDir } from './setup/index.js';
import { environment, isProduction } from './setup/environment.js'; import { environment, isProduction, updateRouterPrefix } from './externals.js';
import { updateRouterPrefix } from './externals.js';
import { ONTIME_VERSION } from './ONTIME_VERSION.js'; import { ONTIME_VERSION } from './ONTIME_VERSION.js';
import { consoleSuccess, consoleHighlight, consoleError } from './utils/console.js'; import { consoleSuccess, consoleHighlight, consoleError } from './utils/console.js';
+1 -1
View File
@@ -4,7 +4,7 @@ import { generateId, millisToString } from 'ontime-utils';
import { clock } from '../services/Clock.js'; import { clock } from '../services/Clock.js';
import { socket } from '../adapters/WebsocketAdapter.js'; import { socket } from '../adapters/WebsocketAdapter.js';
import { consoleSubdued, consoleError } from '../utils/console.js'; import { consoleSubdued, consoleError } from '../utils/console.js';
import { isProduction } from '../setup/environment.js'; import { isProduction } from '../externals.js';
class Logger { class Logger {
private queue: Log[]; private queue: Log[];
@@ -14,7 +14,7 @@ import { JSONFilePreset } from 'lowdb/node';
import { isPath } from '../../utils/fileManagement.js'; import { isPath } from '../../utils/fileManagement.js';
import { shouldCrashDev } from '../../utils/development.js'; import { shouldCrashDev } from '../../utils/development.js';
import { isTest } from '../../setup/environment.js'; import { isTest } from '../../externals.js';
import { safeMerge } from './DataProvider.utils.js'; import { safeMerge } from './DataProvider.utils.js';
+8
View File
@@ -7,6 +7,14 @@ import { readFileSync, writeFileSync } from 'node:fs';
import { srcFiles } from './setup/index.js'; import { srcFiles } from './setup/index.js';
// ================================================= // =================================================
// resolve running environment
const env = process.env.NODE_ENV || 'production';
export const isTest = Boolean(process.env.IS_TEST);
export const environment = isTest ? 'test' : env;
export const isDocker = env === 'docker';
export const isProduction = isDocker || (env === 'production' && !isTest);
export const isOntimeCloud = Boolean(process.env.IS_CLOUD);
export const password = process.env.SESSION_PASSWORD; export const password = process.env.SESSION_PASSWORD;
export const routerPrefix = process.env.ROUTER_PREFIX; export const routerPrefix = process.env.ROUTER_PREFIX;
@@ -2,7 +2,7 @@ import { Low } from 'lowdb';
import { JSONFile } from 'lowdb/node'; import { JSONFile } from 'lowdb/node';
import { publicFiles } from '../../setup/index.js'; import { publicFiles } from '../../setup/index.js';
import { isTest } from '../../setup/environment.js'; import { isTest } from '../../externals.js';
import { isPath } from '../../utils/fileManagement.js'; import { isPath } from '../../utils/fileManagement.js';
import { shouldCrashDev } from '../../utils/development.js'; import { shouldCrashDev } from '../../utils/development.js';
-8
View File
@@ -1,8 +0,0 @@
// resolve running environment
const env = process.env.NODE_ENV || 'production';
export const isTest = Boolean(process.env.IS_TEST);
export const environment = isTest ? 'test' : env;
export const isDocker = env === 'docker';
export const isProduction = isDocker || (env === 'production' && !isTest);
export const isOntimeCloud = Boolean(process.env.IS_CLOUD);
+1 -1
View File
@@ -10,7 +10,7 @@ import { dirname, join } from 'path';
import { config } from './config.js'; import { config } from './config.js';
import { ensureDirectory } from '../utils/fileManagement.js'; import { ensureDirectory } from '../utils/fileManagement.js';
import { isProduction } from './environment.js'; import { isProduction } from '../externals.js';
/** /**
* Returns public path depending on OS * Returns public path depending on OS
+1 -1
View File
@@ -1,4 +1,4 @@
import { isProduction } from '../setup/environment.js'; import { isProduction } from '../externals.js';
import { consoleError } from './console.js'; import { consoleError } from './console.js';
+1 -1
View File
@@ -4,7 +4,7 @@ import type { Server } from 'http';
import { networkInterfaces } from 'os'; import { networkInterfaces } from 'os';
import type { AddressInfo } from 'net'; import type { AddressInfo } from 'net';
import { isDocker, isOntimeCloud, isProduction } from '../setup/environment.js'; import { isDocker, isOntimeCloud, isProduction } from '../externals.js';
import { logger } from '../classes/Logger.js'; import { logger } from '../classes/Logger.js';
/** /**
+1 -1
View File
@@ -215,7 +215,7 @@ export const parseExcel = (
const maybeTimeType = makeString(column, ''); const maybeTimeType = makeString(column, '');
if (maybeTimeType === 'block') { if (maybeTimeType === 'block') {
event.type = SupportedEvent.Block; event.type = SupportedEvent.Block;
} else if (maybeTimeType === '' || maybeTimeType === 'event' || isKnownTimerType(maybeTimeType)) { } else if (maybeTimeType === '' || isKnownTimerType(maybeTimeType)) {
event.type = SupportedEvent.Event; event.type = SupportedEvent.Event;
event.timerType = validateTimerType(maybeTimeType); event.timerType = validateTimerType(maybeTimeType);
} else { } else {
+4 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime", "name": "ontime",
"version": "3.16.1", "version": "3.15.2",
"description": "Time keeping for live events", "description": "Time keeping for live events",
"keywords": [ "keywords": [
"ontime", "ontime",
@@ -16,8 +16,8 @@
}, },
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"engines": { "engines": {
"node": "~22", "node": "~20",
"pnpm": "~10" "pnpm": "~9"
}, },
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -50,5 +50,5 @@
"turbo": "^2.3.3", "turbo": "^2.3.3",
"typescript": "catalog:" "typescript": "catalog:"
}, },
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977" "packageManager": "pnpm@9.15.0"
} }
@@ -15,7 +15,6 @@ export interface SessionStats {
projectName: string; projectName: string;
playback: Playback; playback: Playback;
timezone: string; timezone: string;
version: string;
} }
export interface GetInfo { export interface GetInfo {
+627 -1823
View File
File diff suppressed because it is too large Load Diff
+7 -9
View File
@@ -1,16 +1,14 @@
# https://pnpm.io/pnpm-workspace_yaml
packages: packages:
- apps/* - "apps/*"
- packages/* - "packages/*"
catalog: catalog:
typescript: 5.5.3 typescript: 5.5.3
'@typescript-eslint/eslint-plugin': 7.16.1 "@typescript-eslint/eslint-plugin": 7.16.1
'@typescript-eslint/parser': 7.16.1 "@typescript-eslint/parser": 7.16.1
'@types/node': 22.15.26 "@types/node": 20.17.16
prettier: 3.3.1 prettier: 3.3.1
eslint: 8.56.0 eslint: 8.56.0
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: 2.1.6
onlyBuiltDependencies:
- electron
- esbuild