From 0f5c47bc82c3800b65a08fdedfc98c63a2e68b3a Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Sat, 30 Nov 2024 10:11:36 +0100 Subject: [PATCH 01/47] Small fixes (#1345) * cleanup: remove console log * use UI Index --- .../client/src/features/editors/finder/Finder.tsx | 15 ++++++++------- .../src/translation/TranslationProvider.tsx | 2 -- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/client/src/features/editors/finder/Finder.tsx b/apps/client/src/features/editors/finder/Finder.tsx index 2a8f9e3fb..379554cb9 100644 --- a/apps/client/src/features/editors/finder/Finder.tsx +++ b/apps/client/src/features/editors/finder/Finder.tsx @@ -1,7 +1,7 @@ import { KeyboardEvent, useState } from 'react'; import { Input, Modal, ModalBody, ModalContent, ModalFooter, ModalOverlay } from '@chakra-ui/react'; import { useDebouncedCallback } from '@mantine/hooks'; -import { isOntimeEvent, SupportedEvent } from 'ontime-types'; +import { SupportedEvent } from 'ontime-types'; import { useEventSelection } from '../../rundown/useEventSelection'; @@ -65,14 +65,15 @@ export default function Finder(props: FinderProps) { {error &&
  • {error}
  • } {results.length === 0 &&
  • No results
  • } {results.length > 0 && - results.map((event, index) => { + results.map((entry, index) => { const isSelected = selected === index; - const displayIndex = event.type === SupportedEvent.Block ? '-' : event.index; - const colour = event.type === SupportedEvent.Event ? event.colour : ''; + const displayIndex = entry.type === SupportedEvent.Event ? entry.eventIndex : '-'; + const displayCue = entry.type === SupportedEvent.Event ? entry.cue : ''; + const colour = entry.type === SupportedEvent.Event ? entry.colour : ''; return (
  • {displayIndex} - {isOntimeEvent(event) &&
    {event.cue}
    } -
    {event.title}
    +
    {displayCue}
    +
    {entry.title}
    {isSelected && Go ⏎}
  • diff --git a/apps/client/src/translation/TranslationProvider.tsx b/apps/client/src/translation/TranslationProvider.tsx index fd3b70abf..7aa37cb01 100644 --- a/apps/client/src/translation/TranslationProvider.tsx +++ b/apps/client/src/translation/TranslationProvider.tsx @@ -39,8 +39,6 @@ export const TranslationContext = createContext({ export const TranslationProvider = ({ children }: PropsWithChildren) => { const { data } = useSettings(); - console.log('....', data.language) - const getLocalizedString = useCallback( (key: keyof typeof langEn, lang = data?.language || 'en'): string => { if (lang in translationsList) { From 6529a05e2abc3c1e394e439db614da2440f76ed8 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 28 Nov 2024 22:25:08 +0100 Subject: [PATCH 02/47] fix: previous eventid is any entry --- apps/client/src/features/rundown/Rundown.tsx | 57 ++++++++++--------- .../src/features/rundown/RundownEntry.tsx | 8 ++- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/apps/client/src/features/rundown/Rundown.tsx b/apps/client/src/features/rundown/Rundown.tsx index 27aa0ce22..ce77e8361 100644 --- a/apps/client/src/features/rundown/Rundown.tsx +++ b/apps/client/src/features/rundown/Rundown.tsx @@ -256,10 +256,12 @@ export default function Rundown({ data }: RundownProps) { return insertAtId(SupportedEvent.Event, cursor)} />; } - let lastEntry: PlayableEvent | undefined; // used by indicators - let thisEntry: PlayableEvent | undefined; - let previousEventId: string | undefined; - let thisId = previousEventId; + // last event is used to calculate relative timings + let lastEvent: PlayableEvent | undefined; // used by indicators + let thisEvent: PlayableEvent | undefined; + // previous entry is used to infer position in the rundown for new events + let previousEntryId: string | undefined; + let thisId = previousEntryId; let eventIndex = 0; // all events before the current selected are in the past @@ -272,63 +274,64 @@ export default function Rundown({ data }: RundownProps) {
    - {statefulEntries.map((eventId, index) => { + {statefulEntries.map((entryId, index) => { // we iterate through a stateful copy of order to make the operations smoother // this means that this can be out of sync with order until the useEffect runs // instead of writing all the logic guards, we simply short circuit rendering here - const event = rundown[eventId]; - if (!event) { + const entry = rundown[entryId]; + if (!entry) { return null; } if (index === 0) { eventIndex = 0; } - if (isOntimeEvent(event)) { + previousEntryId = thisId; + thisId = entryId; + if (isOntimeEvent(entry)) { // event indexes are 1 based in frontend eventIndex++; - previousEventId = thisId; - lastEntry = thisEntry; + lastEvent = thisEvent; - if (isPlayableEvent(event)) { + if (isPlayableEvent(entry)) { // populate previous entry - if (isNewLatest(event.timeStart, event.timeEnd, lastEntry?.timeStart, lastEntry?.timeEnd)) { - thisEntry = event; + if (isNewLatest(entry.timeStart, entry.timeEnd, lastEvent?.timeStart, lastEvent?.timeEnd)) { + thisEvent = entry; } - thisId = eventId; } } const isFirst = index === 0; const isLast = index === order.length - 1; - const isLoaded = featureData?.selectedEventId === event.id; - const isNext = featureData?.nextEventId === event.id; - const hasCursor = event.id === cursor; + const isLoaded = featureData?.selectedEventId === entry.id; + const isNext = featureData?.nextEventId === entry.id; + const hasCursor = entry.id === cursor; if (isLoaded) { isPast = false; } return ( - - {isEditMode && (hasCursor || isFirst) && } + + {isEditMode && (hasCursor || isFirst) && }
    - {isOntimeEvent(event) &&
    {eventIndex}
    } -
    + {isOntimeEvent(entry) &&
    {eventIndex}
    } +
    - {isEditMode && (hasCursor || isLast) && } + {isEditMode && (hasCursor || isLast) && } ); })} diff --git a/apps/client/src/features/rundown/RundownEntry.tsx b/apps/client/src/features/rundown/RundownEntry.tsx index 163129916..5df99938c 100644 --- a/apps/client/src/features/rundown/RundownEntry.tsx +++ b/apps/client/src/features/rundown/RundownEntry.tsx @@ -34,6 +34,7 @@ interface RundownEntryProps { isNext: boolean; previousStart?: number; previousEnd?: number; + previousEntryId?: string; previousEventId?: string; playback?: Playback; // we only care about this if this event is playing isRolling: boolean; // we need to know even if not related to this event @@ -48,6 +49,7 @@ export default function RundownEntry(props: RundownEntryProps) { isNext, previousStart, previousEnd, + previousEntryId, previousEventId, playback, isRolling, @@ -84,7 +86,7 @@ export default function RundownEntry(props: RundownEntryProps) { case 'event-before': { const newEvent = { type: SupportedEvent.Event }; const options = { - after: previousEventId, + after: previousEntryId, }; return addEvent(newEvent, options); } @@ -92,13 +94,13 @@ export default function RundownEntry(props: RundownEntryProps) { return addEvent({ type: SupportedEvent.Delay }, { after: data.id }); } case 'delay-before': { - return addEvent({ type: SupportedEvent.Delay }, { after: previousEventId }); + return addEvent({ type: SupportedEvent.Delay }, { after: previousEntryId }); } case 'block': { return addEvent({ type: SupportedEvent.Block }, { after: data.id }); } case 'block-before': { - return addEvent({ type: SupportedEvent.Block }, { after: previousEventId }); + return addEvent({ type: SupportedEvent.Block }, { after: previousEntryId }); } case 'swap': { const { value } = payload as FieldValue; From 8f2a93d6a39a2e118228c0c2c8b88b808c206ebb Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Sat, 30 Nov 2024 22:27:36 +0100 Subject: [PATCH 03/47] FIX: OSC TX and RX shutdown was swapped (#1352) --- .../integration-service/OscIntegration.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/server/src/services/integration-service/OscIntegration.ts b/apps/server/src/services/integration-service/OscIntegration.ts index ac03398cb..8e5ae5c67 100644 --- a/apps/server/src/services/integration-service/OscIntegration.ts +++ b/apps/server/src/services/integration-service/OscIntegration.ts @@ -128,18 +128,18 @@ export class OscIntegration implements IIntegration Date: Sat, 30 Nov 2024 10:20:03 +0100 Subject: [PATCH 04/47] fix: prevent stale data in finder --- .../src/features/editors/finder/useFinder.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/client/src/features/editors/finder/useFinder.tsx b/apps/client/src/features/editors/finder/useFinder.tsx index 9ec95fa1a..d5b2468c6 100644 --- a/apps/client/src/features/editors/finder/useFinder.tsx +++ b/apps/client/src/features/editors/finder/useFinder.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, useState } from 'react'; +import { ChangeEvent, useEffect, useRef, useState } from 'react'; import { isOntimeBlock, isOntimeEvent, MaybeString, SupportedEvent } from 'ontime-types'; import { useFlatRundown } from '../../../common/hooks-query/useRundown'; @@ -28,6 +28,17 @@ export default function useFinder() { const { data } = useFlatRundown(); const [results, setResults] = useState([]); const [error, setError] = useState(null); + const lastSearchString = useRef(''); + + /** clear results when source data changes */ + useEffect(() => { + setResults([]); + setError(null); + // fake a submit event to re-run the search + if (lastSearchString.current) { + find({ target: { value: lastSearchString.current } } as ChangeEvent); + } + }, [data]); /** Returns a single item with a matching index */ const searchByIndex = (searchString: string) => { @@ -155,6 +166,7 @@ export default function useFinder() { } const searchValue = event.target.value.toLowerCase(); + lastSearchString.current = searchValue; if (searchValue.startsWith('index ')) { const searchString = searchValue.replace('index ', '').trim(); From 29e682ee0656289d553519886bd9df6691eb7059 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sat, 30 Nov 2024 22:13:13 +0100 Subject: [PATCH 05/47] refactor: remove frozen implementation --- .../src/api-data/rundown/rundown.controller.ts | 12 ------------ .../src/api-data/rundown/rundown.middleware.ts | 9 --------- apps/server/src/api-data/rundown/rundown.router.ts | 12 ++++-------- .../src/api-data/rundown/rundown.validation.ts | 9 --------- apps/server/src/app.ts | 1 - .../src/services/rundown-service/RundownService.ts | 5 ----- .../types/src/definitions/runtime/RuntimeStore.ts | 1 - .../src/definitions/runtime/RuntimeStore.type.ts | 3 +-- 8 files changed, 5 insertions(+), 47 deletions(-) delete mode 100644 apps/server/src/api-data/rundown/rundown.middleware.ts diff --git a/apps/server/src/api-data/rundown/rundown.controller.ts b/apps/server/src/api-data/rundown/rundown.controller.ts index d5c77d4cb..0c196fc55 100644 --- a/apps/server/src/api-data/rundown/rundown.controller.ts +++ b/apps/server/src/api-data/rundown/rundown.controller.ts @@ -19,7 +19,6 @@ import { deleteEvent, editEvent, reorderEvent, - setFrozenState, swapEvents, } from '../../services/rundown-service/RundownService.js'; import { @@ -127,17 +126,6 @@ export async function rundownBatchPut(req: Request, res: Response) { - try { - const { frozen } = req.body; - setFrozenState(frozen); - res.status(200).send({ message: 'Rundown frozen state updated.' }); - } catch (error) { - const message = getErrorMessage(error); - res.status(400).send({ message }); - } -} - export async function rundownReorder(req: Request, res: Response) { if (failEmptyObjects(req.body, res)) { return; diff --git a/apps/server/src/api-data/rundown/rundown.middleware.ts b/apps/server/src/api-data/rundown/rundown.middleware.ts deleted file mode 100644 index 41f2d852e..000000000 --- a/apps/server/src/api-data/rundown/rundown.middleware.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { eventStore } from '../../stores/EventStore.js'; - -export const preventIfFrozen = function (req, res, next) { - if (eventStore.get('frozen')) { - res.status(403).send({ message: 'Rundown is frozen' }); - } else { - next(); - } -}; diff --git a/apps/server/src/api-data/rundown/rundown.router.ts b/apps/server/src/api-data/rundown/rundown.router.ts index 5cefd66d6..ebac101cb 100644 --- a/apps/server/src/api-data/rundown/rundown.router.ts +++ b/apps/server/src/api-data/rundown/rundown.router.ts @@ -5,7 +5,6 @@ import { rundownApplyDelay, rundownBatchPut, rundownDelete, - rundownFrozenPost, rundownGetAll, rundownGetById, rundownGetNormalised, @@ -19,14 +18,12 @@ import { paramsMustHaveEventId, rundownArrayOfIds, rundownBatchPutValidator, - rundownFrozenPostValidator, rundownGetPaginatedQueryParams, rundownPostValidator, rundownPutValidator, rundownReorderValidator, rundownSwapValidator, } from './rundown.validation.js'; -import { preventIfFrozen } from './rundown.middleware.js'; export const router = express.Router(); @@ -36,14 +33,13 @@ router.get('/normalised', rundownGetNormalised); router.get('/:eventId', paramsMustHaveEventId, rundownGetById); // not used in Ontime frontend router.post('/', rundownPostValidator, rundownPost); -router.post('/frozen', rundownFrozenPostValidator, rundownFrozenPost); router.put('/', rundownPutValidator, rundownPut); router.put('/batch', rundownBatchPutValidator, rundownBatchPut); -router.patch('/reorder/', rundownReorderValidator, preventIfFrozen, rundownReorder); -router.patch('/swap', rundownSwapValidator, preventIfFrozen, rundownSwap); +router.patch('/reorder/', rundownReorderValidator, rundownReorder); +router.patch('/swap', rundownSwapValidator, rundownSwap); router.patch('/applydelay/:eventId', paramsMustHaveEventId, rundownApplyDelay); -router.delete('/', rundownArrayOfIds, preventIfFrozen, deletesEventById); -router.delete('/all', preventIfFrozen, rundownDelete); +router.delete('/', rundownArrayOfIds, deletesEventById); +router.delete('/all', rundownDelete); diff --git a/apps/server/src/api-data/rundown/rundown.validation.ts b/apps/server/src/api-data/rundown/rundown.validation.ts index 117fb6fdc..2de741ff9 100644 --- a/apps/server/src/api-data/rundown/rundown.validation.ts +++ b/apps/server/src/api-data/rundown/rundown.validation.ts @@ -21,15 +21,6 @@ export const rundownPutValidator = [ }, ]; -export const rundownFrozenPostValidator = [ - body('frozen').isBoolean().exists(), - (req: Request, res: Response, next: NextFunction) => { - const errors = validationResult(req); - if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() }); - next(); - }, -] - export const rundownBatchPutValidator = [ body('data').isObject().exists(), body('ids').isArray().exists(), diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index d01d551d7..751808032 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -202,7 +202,6 @@ export const startServer = async ( playback: SimplePlayback.Stop, direction: SimpleDirection.CountDown, }, - frozen: false, ping: -1, }); diff --git a/apps/server/src/services/rundown-service/RundownService.ts b/apps/server/src/services/rundown-service/RundownService.ts index bd008d7a8..3fa8c3ef7 100644 --- a/apps/server/src/services/rundown-service/RundownService.ts +++ b/apps/server/src/services/rundown-service/RundownService.ts @@ -21,7 +21,6 @@ import { runtimeService } from '../runtime-service/RuntimeService.js'; import * as cache from './rundownCache.js'; import { getPlayableEvents, getTimedEvents } from './rundownUtils.js'; -import { eventStore } from '../../stores/EventStore.js'; type PatchWithId = (Partial | Partial | Partial) & { id: string }; @@ -275,7 +274,3 @@ export async function initRundown(rundown: Readonly, customFields // notify timer of change notifyChanges({ timer: true, external: true, reload: true }); } - -export async function setFrozenState(state: boolean) { - eventStore.set('frozen', state); -} diff --git a/packages/types/src/definitions/runtime/RuntimeStore.ts b/packages/types/src/definitions/runtime/RuntimeStore.ts index 13dec8b30..bed1a8229 100644 --- a/packages/types/src/definitions/runtime/RuntimeStore.ts +++ b/packages/types/src/definitions/runtime/RuntimeStore.ts @@ -51,6 +51,5 @@ export const runtimeStorePlaceholder: RuntimeStore = { duration: 0, playback: SimplePlayback.Stop, }, - frozen: false, ping: -1, }; diff --git a/packages/types/src/definitions/runtime/RuntimeStore.type.ts b/packages/types/src/definitions/runtime/RuntimeStore.type.ts index 074b04c9f..b2886441c 100644 --- a/packages/types/src/definitions/runtime/RuntimeStore.type.ts +++ b/packages/types/src/definitions/runtime/RuntimeStore.type.ts @@ -25,7 +25,6 @@ export type RuntimeStore = { // extra timers auxtimer1: SimpleTimerState; - // flags - frozen: boolean; + // utils ping: number; }; From e6dfe9c3635b4b16a6620091b6283458946641cf Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 18 Dec 2024 23:51:51 +0100 Subject: [PATCH 06/47] fix: rolling over midnight wrongly classified as skip --- apps/server/src/config/config.ts | 2 +- apps/server/src/services/runtime-service/RuntimeService.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/server/src/config/config.ts b/apps/server/src/config/config.ts index 67af650e8..80778d468 100644 --- a/apps/server/src/config/config.ts +++ b/apps/server/src/config/config.ts @@ -1,7 +1,7 @@ import { MILLIS_PER_MINUTE } from 'ontime-utils'; export const timerConfig = { - skipLimit: 1000, // threshold of skip for recalculating + skipLimit: 1000, // threshold of skip for recalculating, values lower than updateRate can cause issues with rolling over midnight updateRate: 32, // how often do we update the timer notificationRate: 1000, // how often do we notify clients and integrations triggerAhead: 10, // how far ahead do we trigger the end event diff --git a/apps/server/src/services/runtime-service/RuntimeService.ts b/apps/server/src/services/runtime-service/RuntimeService.ts index 43c50e888..1d8be1d4f 100644 --- a/apps/server/src/services/runtime-service/RuntimeService.ts +++ b/apps/server/src/services/runtime-service/RuntimeService.ts @@ -99,10 +99,15 @@ class RuntimeService { }); this.handleLoadNext(); this.rollLoaded(keepOffset); - } else if (skippedOutOfEvent(newState, this.lastIntegrationClockUpdate, timerConfig.skipLimit)) { + } else if ( + // if there is no previous clock, we could not have skipped + RuntimeService.previousState?.clock && + skippedOutOfEvent(newState, RuntimeService.previousState.clock, timerConfig.skipLimit) + ) { // if we have skipped out of the event, we will recall roll // to push the playback to the right place // this comes with the caveat that we will lose our runtime data + logger.warning(LogOrigin.Playback, 'Time skip detected, reloading roll'); this.roll(true); } } From 7e4cf6ffced37f2ddb2eadd2dfbf1dff2eada845 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 19 Dec 2024 00:06:55 +0100 Subject: [PATCH 07/47] refactor: improve time added display --- .../playback/playback-timer/PlaybackTimer.tsx | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/apps/client/src/features/control/playback/playback-timer/PlaybackTimer.tsx b/apps/client/src/features/control/playback/playback-timer/PlaybackTimer.tsx index e58a3db0f..e168fd588 100644 --- a/apps/client/src/features/control/playback/playback-timer/PlaybackTimer.tsx +++ b/apps/client/src/features/control/playback/playback-timer/PlaybackTimer.tsx @@ -1,9 +1,10 @@ import { PropsWithChildren } from 'react'; import { Tooltip } from '@chakra-ui/react'; import { Playback, TimerPhase } from 'ontime-types'; -import { dayInMs, millisToMinutes, millisToSeconds, millisToString } from 'ontime-utils'; +import { dayInMs, millisToString } from 'ontime-utils'; import { useTimer } from '../../../../common/hooks/useSocket'; +import { formatDuration } from '../../../../common/utils/time'; import TimerDisplay from '../timer-display/TimerDisplay'; import style from './PlaybackTimer.module.scss'; @@ -13,22 +14,12 @@ interface PlaybackTimerProps { } function resolveAddedTimeLabel(addedTime: number) { - function resolveClosestUnit(ms: number) { - if (ms < 6000) { - return `${millisToSeconds(ms)} seconds`; - } else if (ms < 12000) { - return '1 minute'; - } else { - return `${millisToMinutes(ms)} minutes`; - } - } - if (addedTime > 0) { - return `Added ${resolveClosestUnit(addedTime)}`; + return `Added ${formatDuration(addedTime, false)}`; } if (addedTime < 0) { - return `Removed ${resolveClosestUnit(addedTime)}`; + return `Removed ${formatDuration(Math.abs(addedTime), false)}`; } return ''; From 7dec32aea709a6258ea58ae9ceeefed72b5a390a Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 1 Dec 2024 15:00:26 +0100 Subject: [PATCH 08/47] bump version to 3.9.0 --- apps/cli/package.json | 2 +- apps/client/package.json | 2 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 98fa3fd9c..08827f5e8 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getontime/cli", - "version": "3.8.0", + "version": "3.9.0", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/client/package.json b/apps/client/package.json index 4a22ba68c..c5b13ebeb 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "3.8.0", + "version": "3.9.0", "private": true, "type": "module", "dependencies": { diff --git a/apps/electron/package.json b/apps/electron/package.json index f09544585..d0885f671 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.8.0", + "version": "3.9.0", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index 914594ea0..b947742ac 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "3.8.0", + "version": "3.9.0", "exports": "./src/index.js", "dependencies": { "@googleapis/sheets": "^5.0.5", diff --git a/package.json b/package.json index f3a6c3cab..d5fb74113 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.8.0", + "version": "3.9.0", "description": "Time keeping for live events", "keywords": [ "ontime", From 1e8706aa73c51b3a06952cd55e3f865ac61f3607 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 1 Dec 2024 22:20:40 +0100 Subject: [PATCH 09/47] feat: allow add time to aux timer --- apps/server/src/api-integration/integration.controller.ts | 5 +++++ .../server/src/services/aux-timer-service/AuxTimerService.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/apps/server/src/api-integration/integration.controller.ts b/apps/server/src/api-integration/integration.controller.ts index a9e83e035..ded76835e 100644 --- a/apps/server/src/api-integration/integration.controller.ts +++ b/apps/server/src/api-integration/integration.controller.ts @@ -241,6 +241,11 @@ const actionHandlers: Record = { const timeInMs = numberOrError(command.duration) * 1000; reply.payload = auxTimerService.setTime(timeInMs); } + if ('addtime' in command) { + // convert addTime in seconds to ms + const timeInMs = numberOrError(command.addtime) * 1000; + reply.payload = auxTimerService.addTime(timeInMs); + } if ('direction' in command) { if (command.direction === SimpleDirection.CountUp || command.direction === SimpleDirection.CountDown) { reply.payload = auxTimerService.setDirection(command.direction); diff --git a/apps/server/src/services/aux-timer-service/AuxTimerService.ts b/apps/server/src/services/aux-timer-service/AuxTimerService.ts index 48d9157f2..396d4cb3b 100644 --- a/apps/server/src/services/aux-timer-service/AuxTimerService.ts +++ b/apps/server/src/services/aux-timer-service/AuxTimerService.ts @@ -57,6 +57,11 @@ export class AuxTimerService { return this.timer.setTime(duration); } + @broadcastReturn + addTime(millis: number) { + return this.timer.setTime(this.timer.state.current + millis); + } + @broadcastReturn private update() { return this.timer.update(this.getTime()); From 82a2660fbc14a58d9c3a31cf7071b75cfa394df6 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Mon, 2 Dec 2024 14:41:59 +0100 Subject: [PATCH 10/47] fix: router prefix --- apps/server/src/externals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/externals.ts b/apps/server/src/externals.ts index 7593833ff..83f02ccb3 100644 --- a/apps/server/src/externals.ts +++ b/apps/server/src/externals.ts @@ -28,7 +28,7 @@ export function updateRouterPrefix(prefix: string | undefined = process.env.ROUT try { const data = readFileSync(indexFile, { encoding: 'utf-8', flag: 'r' }).replace( //g, - ``, ); writeFileSync(indexFile, data, { encoding: 'utf-8', flag: 'w' }); } catch (_error) { From b3ce247f5486896191d727524c06d7429c3cb671 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Mon, 2 Dec 2024 14:43:53 +0100 Subject: [PATCH 11/47] bump version to 3.9.1 --- apps/cli/package.json | 2 +- apps/client/package.json | 2 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 08827f5e8..864279059 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getontime/cli", - "version": "3.9.0", + "version": "3.9.1", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/client/package.json b/apps/client/package.json index c5b13ebeb..b2ac635ab 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "3.9.0", + "version": "3.9.1", "private": true, "type": "module", "dependencies": { diff --git a/apps/electron/package.json b/apps/electron/package.json index d0885f671..503bd882a 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.0", + "version": "3.9.1", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index b947742ac..05cb0e1a4 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "3.9.0", + "version": "3.9.1", "exports": "./src/index.js", "dependencies": { "@googleapis/sheets": "^5.0.5", diff --git a/package.json b/package.json index d5fb74113..bb9094298 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.0", + "version": "3.9.1", "description": "Time keeping for live events", "keywords": [ "ontime", From b9ba416366de02600b771697fbc2a5b7e478f5f0 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Mon, 2 Dec 2024 15:49:28 +0100 Subject: [PATCH 12/47] refactor: add prefix to relative assets refactor: add prefix to server entrypoints refactor: add prefix to express router refactor: add prefix to router basename --- apps/client/index.html | 54 +++++++++----------- apps/client/src/App.tsx | 3 +- apps/client/src/externals.ts | 24 +++++++-- apps/client/vite.config.js | 3 +- apps/server/src/adapters/WebsocketAdapter.ts | 4 +- apps/server/src/app.ts | 38 ++++++++------ apps/server/src/externals.ts | 18 ++++--- apps/server/src/setup/index.ts | 2 + 8 files changed, 86 insertions(+), 60 deletions(-) diff --git a/apps/client/index.html b/apps/client/index.html index 7254d879b..a37a61f8a 100644 --- a/apps/client/index.html +++ b/apps/client/index.html @@ -1,31 +1,27 @@ - - - - - - - - - - - - - ontime - - - - -
    - - + + + + + + + + + + + + + ontime + + + + +
    + + diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx index 6ebce9acb..c07768b94 100644 --- a/apps/client/src/App.tsx +++ b/apps/client/src/App.tsx @@ -11,6 +11,7 @@ import { connectSocket } from './common/utils/socket'; import theme from './theme/theme'; import { TranslationProvider } from './translation/TranslationProvider'; import AppRouter from './AppRouter'; +import { baseURI } from './externals'; connectSocket(); @@ -19,7 +20,7 @@ function App() { - +
    diff --git a/apps/client/src/externals.ts b/apps/client/src/externals.ts index ec771ba29..1fd3e4618 100644 --- a/apps/client/src/externals.ts +++ b/apps/client/src/externals.ts @@ -22,7 +22,25 @@ export const isOntimeCloud = Boolean(import.meta.env.VITE_IS_CLOUD); const socketProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; // resolve port -const STATIC_PORT = 4001; +const STATIC_PORT = 4001; // this is used as a fallback port for development export const serverPort = isProduction ? window.location.port : STATIC_PORT; -export const serverURL = `${window.location.protocol}//${location.hostname}:${serverPort}`; -export const websocketUrl = `${socketProtocol}://${location.hostname}:${serverPort}/ws`; +export const baseURI = resolveBaseURI(); +export const serverURL = `${window.location.protocol}//${window.location.hostname}:${serverPort}${baseURI}`; +export const websocketUrl = `${socketProtocol}://${window.location.hostname}:${serverPort}${baseURI}/ws`; + +/** + * Resolves a base URI for a client that is not at the root segment + * ie: https://cloud.getontime.com/client-hash/timer + * This is necessary for ontime cloud and should otherwise not affect the client + */ +function resolveBaseURI() { + if (!isOntimeCloud) { + return ''; + } + const [_, base, location] = window.location.pathname.split('/'); + if (!location) { + return ''; + } + + return `/${base}`; +} diff --git a/apps/client/vite.config.js b/apps/client/vite.config.js index d8e53fa85..25b2d5dc4 100644 --- a/apps/client/vite.config.js +++ b/apps/client/vite.config.js @@ -11,6 +11,7 @@ const sentryAuthToken = process.env.SENTRY_AUTH_TOKEN; const isDev = process.env.NODE_ENV === 'local' || process.env.NODE_ENV === 'development'; export default defineConfig({ + base: './', // Ontime cloud: we use relative paths to allow them to reference a dynamic base set at runtime plugins: [ react(), svgrPlugin(), @@ -33,7 +34,7 @@ export default defineConfig({ }), compression({ algorithm: 'brotliCompress', - exclude: /\.(html)$/, // Exclude HTML files from compression so we can change the base property at runtime + exclude: /\.(html)$/, // Ontime cloud: Exclude HTML files from compression so we can change the base property at runtime }), ], server: { diff --git a/apps/server/src/adapters/WebsocketAdapter.ts b/apps/server/src/adapters/WebsocketAdapter.ts index 6fd5e7274..cc87be0de 100644 --- a/apps/server/src/adapters/WebsocketAdapter.ts +++ b/apps/server/src/adapters/WebsocketAdapter.ts @@ -47,8 +47,8 @@ export class SocketServer implements IAdapter { this.wss = null; } - init(server: Server) { - this.wss = new WebSocketServer({ path: '/ws', server, maxPayload: this.MAX_PAYLOAD }); + init(server: Server, prefix?: string) { + this.wss = new WebSocketServer({ path: `${prefix}/ws`, server, maxPayload: this.MAX_PAYLOAD }); this.wss.on('connection', (ws) => { const clientId = generateId(); diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 751808032..6f6cf9ac5 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -6,10 +6,10 @@ import expressStaticGzip from 'express-static-gzip'; import http, { type Server } from 'http'; import cors from 'cors'; import serverTiming from 'server-timing'; -import { extname, resolve } from 'path'; +import { extname } from 'node:path'; // import utils -import { publicDir, srcDir } from './setup/index.js'; +import { publicDir, srcDir, srcFiles } from './setup/index.js'; import { environment, isProduction, updateRouterPrefix } from './externals.js'; import { ONTIME_VERSION } from './ONTIME_VERSION.js'; import { consoleSuccess, consoleHighlight, consoleError } from './utils/console.js'; @@ -53,8 +53,14 @@ if (!canLog) { console.log(`Ontime public directory at ${publicDir.root} `); } -// calls an update to the client router prefix -updateRouterPrefix(); +/** + * When running in Ontime cloud, the client is not at the root segment + * ie: https://cloud.getontime.com/client-hash/timer + * This means: + * - changing the base path in the index.html file + * - prepending all express routes with the given prefix + */ +const prefix = updateRouterPrefix(); // Create express APP const app = express(); @@ -75,20 +81,20 @@ app.use(express.urlencoded({ extended: true })); app.use(express.json({ limit: '1mb' })); // Implement route endpoints -app.use('/data', appRouter); // router for application data -app.use('/api', integrationRouter); // router for integrations +app.use(`${prefix}/data`, appRouter); // router for application data +app.use(`${prefix}/api`, integrationRouter); // router for integrations // serve static external files -app.use('/external', express.static(publicDir.externalDir)); -app.use('/user', express.static(publicDir.userDir)); - -// if the user reaches to the root, we show a 404 -app.use('/external', (req, res) => { +app.use(`${prefix}/external`, express.static(publicDir.externalDir)); +app.use(`${prefix}/external`, (req, res) => { + // if the user reaches to the root, we show a 404 res.status(404).send(`${req.originalUrl} not found`); }); +app.use(`${prefix}/user`, express.static(publicDir.userDir)); // serve static - react, in dev/test mode we fetch the React app from module app.use( + prefix, expressStaticGzip(srcDir.clientDir, { enableBrotli: true, orderPreference: ['br'], @@ -111,8 +117,8 @@ app.use( }), ); -app.get('*', (_req, res) => { - res.sendFile(resolve(srcDir.clientDir, 'index.html')); +app.get(`${prefix}/*`, (_req, res) => { + res.sendFile(srcFiles.clientIndexHtml); }); // Implement catch all @@ -176,7 +182,7 @@ export const startServer = async ( const { serverPort } = getDataProvider().getSettings(); expressServer = http.createServer(app); - socket.init(expressServer); + socket.init(expressServer, prefix); /** * Module initialises the services and provides initial payload for the store @@ -221,10 +227,10 @@ export const startServer = async ( expressServer.listen(serverPort, '0.0.0.0', () => { const nif = getNetworkInterfaces(); - consoleSuccess(`Local: http://localhost:${serverPort}/editor`); + consoleSuccess(`Local: http://localhost:${serverPort}${prefix}/editor`); for (const key in nif) { const address = nif[key].address; - consoleSuccess(`Network: http://${address}:${serverPort}/editor`); + consoleSuccess(`Network: http://${address}:${serverPort}${prefix}/editor`); } }); diff --git a/apps/server/src/externals.ts b/apps/server/src/externals.ts index 83f02ccb3..6bbbab2dd 100644 --- a/apps/server/src/externals.ts +++ b/apps/server/src/externals.ts @@ -3,7 +3,8 @@ */ import { readFileSync, writeFileSync } from 'node:fs'; -import { resolve } from 'node:path'; + +import { srcFiles } from './setup/index.js'; // ================================================= // resolve running environment @@ -19,19 +20,20 @@ export const isProduction = isDocker || (env === 'production' && !isTest); * This is only needed in the cloud environment where the client is not at the root segment * ie: https://cloud.getontime.com/client-hash/timer */ -export function updateRouterPrefix(prefix: string | undefined = process.env.ROUTER_PREFIX) { +export function updateRouterPrefix(prefix: string | undefined = process.env.ROUTER_PREFIX): string { if (!prefix) { - return; + return ''; } - const indexFile = resolve('.', 'client', 'index.html'); try { - const data = readFileSync(indexFile, { encoding: 'utf-8', flag: 'r' }).replace( - //g, - ``, + const data = readFileSync(srcFiles.clientIndexHtml, { encoding: 'utf-8', flag: 'r' }).replace( + '', + ``, ); - writeFileSync(indexFile, data, { encoding: 'utf-8', flag: 'w' }); + writeFileSync(srcFiles.clientIndexHtml, data, { encoding: 'utf-8', flag: 'w' }); } catch (_error) { /** unhandled */ } + + return `/${prefix}`; } diff --git a/apps/server/src/setup/index.ts b/apps/server/src/setup/index.ts index 3a1c7c96e..0990d69c0 100644 --- a/apps/server/src/setup/index.ts +++ b/apps/server/src/setup/index.ts @@ -77,6 +77,8 @@ export const srcDir = { } as const; export const srcFiles = { + /** Path to start index.html */ + clientIndexHtml: join(srcDir.clientDir, 'index.html'), /** Path to bundled CSS */ cssOverride: join(srcDir.root, config.user, config.styles.directory, config.styles.filename), /** Path to bundled external readme */ From d622a7738fb08bf8049944857089089cfd92ce69 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Tue, 3 Dec 2024 21:24:50 +0100 Subject: [PATCH 13/47] refactor: remove deprecated field --- docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 88ca8b333..6720dfbff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3" - services: ontime: container_name: ontime From e6aa7404f726012048e472602cd88475508484ae Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 4 Dec 2024 15:39:52 +0100 Subject: [PATCH 14/47] chore: correct documentation --- DEVELOPMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 2d887d0b7..6a4a5d7a0 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -91,7 +91,7 @@ While it should allow for a generic setup, it might need to be modified to fit y From the project root, run the following commands -- __Build docker image from__ by running `docker build -t getontime/ontime` +- __Build docker image from__ by running `docker build -t getontime/ontime .` - __Run docker image from compose__ by running `docker-compose up -d` Other useful commands From 607bc406734fbd508658bde28ca78431bcd8ea01 Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Wed, 4 Dec 2024 20:25:49 +0100 Subject: [PATCH 15/47] create addTime function in simple timer (#1363) * create addTime function in simple timer --- .../src/classes/simple-timer/SimpleTimer.ts | 8 +++ .../__tests__/SimpleTimer.test.ts | 55 +++++++++++++++++++ .../aux-timer-service/AuxTimerService.ts | 8 ++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/apps/server/src/classes/simple-timer/SimpleTimer.ts b/apps/server/src/classes/simple-timer/SimpleTimer.ts index cc3e03fde..8ae23cb46 100644 --- a/apps/server/src/classes/simple-timer/SimpleTimer.ts +++ b/apps/server/src/classes/simple-timer/SimpleTimer.ts @@ -37,6 +37,14 @@ export class SimpleTimer { return this.state; } + public addTime(millis: number): SimpleTimerState { + this.state.duration += millis; + // the value of current will be overridden when update is called, + // but if we are in pause or stop state it will not be changed so we do it here + this.state.current += millis; + return this.state; + } + public setDirection(direction: SimpleDirection, timeNow: number): SimpleTimerState { // if we are playing, we need to reset the targets if (this.state.playback === SimplePlayback.Start) { diff --git a/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts b/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts index c516eb6fa..cc6c924c8 100644 --- a/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts +++ b/apps/server/src/classes/simple-timer/__tests__/SimpleTimer.test.ts @@ -177,5 +177,60 @@ describe('SimpleTimer count-down', () => { playback: SimplePlayback.Start, }); }); + + test('adding time affects final result', () => { + timer.reset(); + + timer.setTime(1000); + timer.start(0); + timer.update(100); + expect(timer.state).toMatchObject({ current: 900, duration: 1000 }); + + timer.addTime(1000); + timer.update(200); + expect(timer.state).toMatchObject({ current: 1800, duration: 2000 }); + + timer.update(300); + expect(timer.state).toMatchObject({ current: 1700, duration: 2000 }); + + timer.stop(); + expect(timer.state).toMatchObject({ current: 1000, duration: 1000 }); + }); + + test('adding time affects paused timer', () => { + timer.reset(); + + timer.setTime(1000); + timer.start(0); + timer.update(100); + expect(timer.state).toMatchObject({ current: 900, duration: 1000 }); + + timer.pause(200); + expect(timer.state).toMatchObject({ current: 900, duration: 1000 }); + + timer.addTime(1000); + timer.update(200); + expect(timer.state).toMatchObject({ current: 1900, duration: 2000 }); + + timer.start(300); + expect(timer.state).toMatchObject({ current: 1800, duration: 2000 }); + }); + + test('adding time affects stopped timer, but returns to initial valuses when stopped again', () => { + timer.reset(); + + timer.setTime(1000); + expect(timer.state).toMatchObject({ current: 1000, duration: 1000 }); + + timer.addTime(1000); + expect(timer.state).toMatchObject({ current: 2000, duration: 2000 }); + + timer.start(0); + timer.update(100); + expect(timer.state).toMatchObject({ current: 1900, duration: 2000 }); + + timer.stop(); + expect(timer.state).toMatchObject({ current: 1000, duration: 1000 }); + }); }); }); diff --git a/apps/server/src/services/aux-timer-service/AuxTimerService.ts b/apps/server/src/services/aux-timer-service/AuxTimerService.ts index 396d4cb3b..e0b4c59e5 100644 --- a/apps/server/src/services/aux-timer-service/AuxTimerService.ts +++ b/apps/server/src/services/aux-timer-service/AuxTimerService.ts @@ -1,4 +1,4 @@ -import { SimpleDirection, SimpleTimerState } from 'ontime-types'; +import { SimpleDirection, SimplePlayback, SimpleTimerState } from 'ontime-types'; import { SimpleTimer } from '../../classes/simple-timer/SimpleTimer.js'; import { eventStore } from '../../stores/EventStore.js'; @@ -59,7 +59,11 @@ export class AuxTimerService { @broadcastReturn addTime(millis: number) { - return this.timer.setTime(this.timer.state.current + millis); + if (this.timer.state.playback === SimplePlayback.Start) { + this.timer.addTime(millis); + return this.timer.update(this.getTime()); + } + return this.timer.addTime(millis); } @broadcastReturn From 8e587128a116fc1fc087f09e0df8f25443471d36 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 4 Dec 2024 15:45:48 +0100 Subject: [PATCH 16/47] refactor: ensure element height --- apps/client/src/features/editors/welcome/Welcome.module.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/client/src/features/editors/welcome/Welcome.module.scss b/apps/client/src/features/editors/welcome/Welcome.module.scss index 3965310ea..22b3249f6 100644 --- a/apps/client/src/features/editors/welcome/Welcome.module.scss +++ b/apps/client/src/features/editors/welcome/Welcome.module.scss @@ -27,6 +27,7 @@ } .tableContainer { + height: 350px; max-height: 350px; overflow-y: auto; } From d8e2a8d0924231b9a130d5712b9d3be432764c2b Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 4 Dec 2024 15:46:15 +0100 Subject: [PATCH 17/47] bump version to 3.9.2 --- apps/cli/package.json | 2 +- apps/client/package.json | 2 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 864279059..f07fd9d11 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getontime/cli", - "version": "3.9.1", + "version": "3.9.2", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/client/package.json b/apps/client/package.json index b2ac635ab..8bfcd3489 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "3.9.1", + "version": "3.9.2", "private": true, "type": "module", "dependencies": { diff --git a/apps/electron/package.json b/apps/electron/package.json index 503bd882a..f60b19fe1 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.1", + "version": "3.9.2", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index 05cb0e1a4..36206f19b 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "3.9.1", + "version": "3.9.2", "exports": "./src/index.js", "dependencies": { "@googleapis/sheets": "^5.0.5", diff --git a/package.json b/package.json index bb9094298..c01073e36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.1", + "version": "3.9.2", "description": "Time keeping for live events", "keywords": [ "ontime", From acf1afb5e908b23dadeb987896c1a1613528e83c Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 6 Dec 2024 14:53:34 +0100 Subject: [PATCH 18/47] fix: prevent overflow --- apps/client/src/features/viewers/studio/StudioClock.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/client/src/features/viewers/studio/StudioClock.scss b/apps/client/src/features/viewers/studio/StudioClock.scss index 7ebe263e9..66fd12b5f 100644 --- a/apps/client/src/features/viewers/studio/StudioClock.scss +++ b/apps/client/src/features/viewers/studio/StudioClock.scss @@ -149,6 +149,7 @@ $orange-active: #f60; grid-area: schedule; font-family: monospace; margin-right: 2vw; + overflow: hidden; } .onAir { From 8bc3f5a56cc0f4a59718cce7644a3be2d0265ff2 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:48:35 +0100 Subject: [PATCH 19/47] Fix links (#1366) * chore: remove unused code * bump version to 3.9.3 * chore: use constant links * refactor: build links * chore: ignore ontime-data --- .gitignore | 1 + apps/cli/package.json | 2 +- apps/client/package.json | 4 +- .../navigation-menu/NavigationMenu.tsx | 7 ++- apps/client/src/common/utils/linkUtils.js | 30 ---------- apps/client/src/common/utils/linkUtils.ts | 40 +++++++++++++ apps/client/src/externals.ts | 60 +++++++++++++------ .../panel/network-panel/NetworkInterfaces.tsx | 8 +-- .../panel/network-panel/NetworkLogPanel.tsx | 4 +- .../panel/project-panel/ProjectCreateForm.tsx | 5 +- .../panel/project-panel/ProjectData.tsx | 5 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- apps/server/src/utils/__tests__/url.test.ts | 33 ---------- apps/server/src/utils/url.ts | 20 ------- e2e/tests/000-upload-showfile.spec.ts | 4 ++ ...mote.spec.ts => 210-client-remote.spec.ts} | 0 package.json | 2 +- 18 files changed, 110 insertions(+), 119 deletions(-) delete mode 100644 apps/client/src/common/utils/linkUtils.js create mode 100644 apps/client/src/common/utils/linkUtils.ts delete mode 100644 apps/server/src/utils/__tests__/url.test.ts delete mode 100644 apps/server/src/utils/url.ts rename e2e/tests/features/{302-client-remote.spec.ts => 210-client-remote.spec.ts} (100%) diff --git a/.gitignore b/.gitignore index 0cf66a490..a73158227 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ dist/ # docker utils ontime-db ontime-external/ +ontime-data/ # versioning file **/ONTIME_VERSION.js diff --git a/apps/cli/package.json b/apps/cli/package.json index f07fd9d11..021140b01 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getontime/cli", - "version": "3.9.2", + "version": "3.9.3", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/client/package.json b/apps/client/package.json index 8bfcd3489..1f655beed 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "3.9.2", + "version": "3.9.3", "private": true, "type": "module", "dependencies": { @@ -39,7 +39,7 @@ "build": "vite build", "build:local": "cross-env NODE_ENV=local vite build", "build:electron": "cross-env NODE_ENV=local vite build", - "build:docker": "cross-env VITE_IS_CLOUD=true vite build", + "build:docker": "cross-env VITE_IS_DOCKER=true vite build", "build:localdocker": "cross-env NODE_ENV=local vite build", "lint": "eslint . --quiet", "test": "vitest", diff --git a/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx b/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx index 7180f2d36..97371d8e9 100644 --- a/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx +++ b/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx @@ -17,7 +17,7 @@ import { IoExpand } from '@react-icons/all-files/io5/IoExpand'; import { IoLockClosedOutline } from '@react-icons/all-files/io5/IoLockClosedOutline'; import { IoSwapVertical } from '@react-icons/all-files/io5/IoSwapVertical'; -import { isLocalhost, serverPort } from '../../../externals'; +import { isLocalhost } from '../../../externals'; import { navigatorConstants } from '../../../viewerConfig'; import useClickOutside from '../../hooks/useClickOutside'; import { useElectronEvent } from '../../hooks/useElectronEvent'; @@ -25,7 +25,7 @@ import useInfo from '../../hooks-query/useInfo'; import { useClientStore } from '../../stores/clientStore'; import { useViewOptionsStore } from '../../stores/viewOptions'; import { isKeyEnter } from '../../utils/keyEvent'; -import { handleLinks, openLink } from '../../utils/linkUtils'; +import { handleLinks, linkToOtherHost, openLink } from '../../utils/linkUtils'; import { cx } from '../../utils/styleUtils'; import { RenameClientModal } from '../client-modal/RenameClientModal'; import CopyTag from '../copy-tag/CopyTag'; @@ -154,7 +154,8 @@ function OtherAddresses(props: OtherAddressesProps) { return null; } - const address = `http://${nif.address}:${serverPort}${currentLocation}`; + const address = linkToOtherHost(nif.address, currentLocation); + return ( - {data.networkInterfaces?.map((nif) => { + {data.networkInterfaces.map((nif) => { // interfaces outside localhost wont have access if (nif.name === 'localhost' && !isLocalhost) return null; + const address = linkToOtherHost(nif.address); - const address = `http://${nif.address}:${serverPort}`; return ( Network - {isOntimeCloud && } + {isDockerImage && } Ontime is streaming on the following network interfaces diff --git a/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx b/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx index d88bfd7e1..fa5b902de 100644 --- a/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx +++ b/apps/client/src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx @@ -6,6 +6,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { PROJECT_LIST } from '../../../../common/api/constants'; import { createProject } from '../../../../common/api/db'; import { maybeAxiosError } from '../../../../common/api/utils'; +import { documentationUrl, websiteUrl } from '../../../../externals'; import * as Panel from '../../panel-utils/PanelUtils'; import style from './ProjectPanel.module.scss'; @@ -118,7 +119,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) { @@ -140,7 +141,7 @@ export default function ProjectCreateForm(props: ProjectCreateFromProps) { diff --git a/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx b/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx index 960ceb218..7f3094f64 100644 --- a/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx +++ b/apps/client/src/features/app-settings/panel/project-panel/ProjectData.tsx @@ -10,6 +10,7 @@ import { postProjectData, uploadProjectLogo } from '../../../../common/api/proje import { maybeAxiosError } from '../../../../common/api/utils'; import useProjectData from '../../../../common/hooks-query/useProjectData'; import { validateLogo } from '../../../../common/utils/uploadUtils'; +import { documentationUrl, websiteUrl } from '../../../../externals'; import * as Panel from '../../panel-utils/PanelUtils'; import style from './ProjectPanel.module.scss'; @@ -203,7 +204,7 @@ export default function ProjectData() { @@ -225,7 +226,7 @@ export default function ProjectData() { diff --git a/apps/electron/package.json b/apps/electron/package.json index f60b19fe1..e6274e056 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.2", + "version": "3.9.3", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index 36206f19b..1e2d68481 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "3.9.2", + "version": "3.9.3", "exports": "./src/index.js", "dependencies": { "@googleapis/sheets": "^5.0.5", diff --git a/apps/server/src/utils/__tests__/url.test.ts b/apps/server/src/utils/__tests__/url.test.ts deleted file mode 100644 index 326a33357..000000000 --- a/apps/server/src/utils/__tests__/url.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { cleanURL } from '../url.js'; - -describe('url is correctly formatted', () => { - it('has no leading spaces', () => { - const test = ' http://testing'; - const expected = 'http://testing'; - expect(cleanURL(test)).toBe(expected); - }); - - it('has no trailing spaces', () => { - const test = 'http://testing '; - const expected = 'http://testing'; - expect(cleanURL(test)).toBe(expected); - }); - - it('doesnt contain spaces', () => { - const test = 'http://t e s t i n g'; - const expected = 'http://t%20e%20s%20t%20i%20n%20g'; - expect(cleanURL(test)).toBe(expected); - }); - - it('only contains allowed characters', () => { - const test = 'http://<>[]{}|^'; - const expected = 'http://'; - expect(cleanURL(test)).toBe(expected); - }); - - it('begins with http://', () => { - const test = 'ontime.com'; - const expected = 'http://ontime.com'; - expect(cleanURL(test)).toBe(expected); - }); -}); diff --git a/apps/server/src/utils/url.ts b/apps/server/src/utils/url.ts deleted file mode 100644 index 9f8fd7bba..000000000 --- a/apps/server/src/utils/url.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @description Cleans given url - * @param {string} url - URL to be checked - * @returns {string} Sanitized url - */ -export const cleanURL = (url: string): string => { - // trim whitespaces - let sanitised = url.trim(); - - // clear any whitespaces - sanitised = sanitised.split(' ').join('%20'); - - // contain only allowed characters - sanitised = sanitised.replace(/([@\s<>[\]{}|\\^])+/g, ''); - - // starts with http:// - if (!sanitised.startsWith('http://')) sanitised = `http://${sanitised}`; - - return sanitised; -}; diff --git a/e2e/tests/000-upload-showfile.spec.ts b/e2e/tests/000-upload-showfile.spec.ts index 5517b83ab..f1245ac82 100644 --- a/e2e/tests/000-upload-showfile.spec.ts +++ b/e2e/tests/000-upload-showfile.spec.ts @@ -4,6 +4,10 @@ const fileToUpload = 'e2e/tests/fixtures/test-db.json'; test('project file upload', async ({ page }) => { await page.goto('http://localhost:4001/editor'); + + // close the welcome modal if it is open + await page.keyboard.down('Escape'); + await page.getByRole('button', { name: 'Edit' }).click(); await page.getByRole('button', { name: 'Clear rundown' }).click(); await page.getByRole('button', { name: 'Delete all' }).click(); diff --git a/e2e/tests/features/302-client-remote.spec.ts b/e2e/tests/features/210-client-remote.spec.ts similarity index 100% rename from e2e/tests/features/302-client-remote.spec.ts rename to e2e/tests/features/210-client-remote.spec.ts diff --git a/package.json b/package.json index c01073e36..31d644e5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.2", + "version": "3.9.3", "description": "Time keeping for live events", "keywords": [ "ontime", From bfb9b51073c6dea01c19cb6cfafbfec1975f8f67 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 6 Dec 2024 21:15:12 +0100 Subject: [PATCH 20/47] fix: secure protocol resolution --- apps/client/src/externals.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/client/src/externals.ts b/apps/client/src/externals.ts index e2e4b082e..963ae663c 100644 --- a/apps/client/src/externals.ts +++ b/apps/client/src/externals.ts @@ -34,9 +34,12 @@ export const websocketUrl = resolveUrl('ws', 'ws'); function resolveUrl(protocol: 'http' | 'ws', path: string) { const url = new URL(window.location.origin); - // check if protocol URL is secure - url.protocol = protocol === 'http' ? 'http' : 'ws'; - url.protocol += window.location.protocol === 'https:' ? 's' : ''; + // generate ws url + if (protocol === 'ws') { + // ensure we remain in a secure context + const isSecure = window.location.protocol === 'https:'; + url.protocol = isSecure ? 'wss' : 'ws'; + } // make path name relative to the base URI url.pathname = baseURI ? `${baseURI}/${path}` : path; From fa7ec623f1476fa34e8f5df79564fd5f99354b14 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 6 Dec 2024 21:20:25 +0100 Subject: [PATCH 21/47] bump version to 3.9.4 --- apps/cli/package.json | 2 +- apps/client/package.json | 2 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 021140b01..b09f1f881 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getontime/cli", - "version": "3.9.3", + "version": "3.9.4", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/client/package.json b/apps/client/package.json index 1f655beed..55625a0ae 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "3.9.3", + "version": "3.9.4", "private": true, "type": "module", "dependencies": { diff --git a/apps/electron/package.json b/apps/electron/package.json index e6274e056..1cdd1a8a7 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.3", + "version": "3.9.4", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index 1e2d68481..468d168ec 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "3.9.3", + "version": "3.9.4", "exports": "./src/index.js", "dependencies": { "@googleapis/sheets": "^5.0.5", diff --git a/package.json b/package.json index 31d644e5e..d5073a6cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.3", + "version": "3.9.4", "description": "Time keeping for live events", "keywords": [ "ontime", From 6ffbf2af9d8e893932873ddf58417bc3c15ffd53 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Tue, 10 Dec 2024 14:31:50 +0100 Subject: [PATCH 22/47] chore: move files to new structure --- apps/client/src/AppRouter.tsx | 2 +- apps/client/src/common/api/db.ts | 2 +- .../src/{features => views}/cuesheet/Cuesheet.module.scss | 0 apps/client/src/{features => views}/cuesheet/Cuesheet.tsx | 0 .../{features => views}/cuesheet/CuesheetWrapper.module.scss | 0 .../src/{features => views}/cuesheet/CuesheetWrapper.tsx | 2 +- .../src/{features => views}/cuesheet/ProtectedCuesheet.tsx | 0 .../cuesheet/__tests__/__snapshots__/utils.test.js.snap | 0 .../src/{features => views}/cuesheet/__tests__/utils.test.js | 0 .../cuesheet/cuesheet-progress/CuesheetProgress.module.scss | 0 .../cuesheet/cuesheet-progress/CuesheetProgress.tsx | 0 .../cuesheet/cuesheet-table-elements/BlockRow.tsx | 0 .../cuesheet/cuesheet-table-elements/CuesheetHeader.tsx | 0 .../cuesheet/cuesheet-table-elements/DelayRow.tsx | 0 .../cuesheet/cuesheet-table-elements/EditableCell.tsx | 0 .../cuesheet/cuesheet-table-elements/EventRow.tsx | 0 .../cuesheet/cuesheet-table-elements/SortableCell.tsx | 0 .../cuesheet-table-header/CuesheetTableHeader.module.scss | 0 .../cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx | 0 .../cuesheet-table-header/CuesheetTableHeaderTimers.tsx | 4 ++-- .../cuesheet-table-settings/CuesheetTableSettings.module.scss | 0 .../cuesheet-table-settings/CuesheetTableSettings.tsx | 0 apps/client/src/{features => views}/cuesheet/cuesheetCols.tsx | 2 +- apps/client/src/{features => views}/cuesheet/cuesheetUtils.ts | 0 apps/client/src/{features => views}/cuesheet/defaults.ts | 0 .../{features => views}/cuesheet/store/CuesheetSettings.tsx | 0 .../src/{features => views}/cuesheet/useColumnManager.tsx | 0 27 files changed, 6 insertions(+), 6 deletions(-) rename apps/client/src/{features => views}/cuesheet/Cuesheet.module.scss (100%) rename apps/client/src/{features => views}/cuesheet/Cuesheet.tsx (100%) rename apps/client/src/{features => views}/cuesheet/CuesheetWrapper.module.scss (100%) rename apps/client/src/{features => views}/cuesheet/CuesheetWrapper.tsx (98%) rename apps/client/src/{features => views}/cuesheet/ProtectedCuesheet.tsx (100%) rename apps/client/src/{features => views}/cuesheet/__tests__/__snapshots__/utils.test.js.snap (100%) rename apps/client/src/{features => views}/cuesheet/__tests__/utils.test.js (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-progress/CuesheetProgress.module.scss (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-progress/CuesheetProgress.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-elements/BlockRow.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-elements/CuesheetHeader.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-elements/DelayRow.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-elements/EditableCell.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-elements/EventRow.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-elements/SortableCell.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx (79%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss (100%) rename apps/client/src/{features => views}/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx (100%) rename apps/client/src/{features => views}/cuesheet/cuesheetCols.tsx (97%) rename apps/client/src/{features => views}/cuesheet/cuesheetUtils.ts (100%) rename apps/client/src/{features => views}/cuesheet/defaults.ts (100%) rename apps/client/src/{features => views}/cuesheet/store/CuesheetSettings.tsx (100%) rename apps/client/src/{features => views}/cuesheet/useColumnManager.tsx (100%) diff --git a/apps/client/src/AppRouter.tsx b/apps/client/src/AppRouter.tsx index 24789c754..70e3fb8bd 100644 --- a/apps/client/src/AppRouter.tsx +++ b/apps/client/src/AppRouter.tsx @@ -19,7 +19,7 @@ import { ONTIME_VERSION } from './ONTIME_VERSION'; import { sentryDsn, sentryRecommendedIgnore } from './sentry.config'; const Editor = React.lazy(() => import('./features/editors/ProtectedEditor')); -const Cuesheet = React.lazy(() => import('./features/cuesheet/ProtectedCuesheet')); +const Cuesheet = React.lazy(() => import('./views/cuesheet/ProtectedCuesheet')); const Operator = React.lazy(() => import('./features/operator/OperatorExport')); const TimerView = React.lazy(() => import('./features/viewers/timer/Timer')); diff --git a/apps/client/src/common/api/db.ts b/apps/client/src/common/api/db.ts index dcc1af003..e9a29b3da 100644 --- a/apps/client/src/common/api/db.ts +++ b/apps/client/src/common/api/db.ts @@ -1,7 +1,7 @@ import axios, { AxiosResponse } from 'axios'; import { DatabaseModel, MessageResponse, ProjectData, ProjectFileListResponse, QuickStartData } from 'ontime-types'; -import { makeCSV, makeTable } from '../../features/cuesheet/cuesheetUtils'; +import { makeCSV, makeTable } from '../../views/cuesheet/cuesheet.utils'; import { apiEntryUrl } from './constants'; import { createBlob, downloadBlob } from './utils'; diff --git a/apps/client/src/features/cuesheet/Cuesheet.module.scss b/apps/client/src/views/cuesheet/Cuesheet.module.scss similarity index 100% rename from apps/client/src/features/cuesheet/Cuesheet.module.scss rename to apps/client/src/views/cuesheet/Cuesheet.module.scss diff --git a/apps/client/src/features/cuesheet/Cuesheet.tsx b/apps/client/src/views/cuesheet/Cuesheet.tsx similarity index 100% rename from apps/client/src/features/cuesheet/Cuesheet.tsx rename to apps/client/src/views/cuesheet/Cuesheet.tsx diff --git a/apps/client/src/features/cuesheet/CuesheetWrapper.module.scss b/apps/client/src/views/cuesheet/CuesheetWrapper.module.scss similarity index 100% rename from apps/client/src/features/cuesheet/CuesheetWrapper.module.scss rename to apps/client/src/views/cuesheet/CuesheetWrapper.module.scss diff --git a/apps/client/src/features/cuesheet/CuesheetWrapper.tsx b/apps/client/src/views/cuesheet/CuesheetWrapper.tsx similarity index 98% rename from apps/client/src/features/cuesheet/CuesheetWrapper.tsx rename to apps/client/src/views/cuesheet/CuesheetWrapper.tsx index efb71ae81..f6b9cab87 100644 --- a/apps/client/src/features/cuesheet/CuesheetWrapper.tsx +++ b/apps/client/src/views/cuesheet/CuesheetWrapper.tsx @@ -11,7 +11,7 @@ import { useCuesheet } from '../../common/hooks/useSocket'; import { useWindowTitle } from '../../common/hooks/useWindowTitle'; import useCustomFields from '../../common/hooks-query/useCustomFields'; import { useFlatRundown } from '../../common/hooks-query/useRundown'; -import { CuesheetOverview } from '../overview/Overview'; +import { CuesheetOverview } from '../../features/overview/Overview'; import CuesheetProgress from './cuesheet-progress/CuesheetProgress'; import { useCuesheetSettings } from './store/CuesheetSettings'; diff --git a/apps/client/src/features/cuesheet/ProtectedCuesheet.tsx b/apps/client/src/views/cuesheet/ProtectedCuesheet.tsx similarity index 100% rename from apps/client/src/features/cuesheet/ProtectedCuesheet.tsx rename to apps/client/src/views/cuesheet/ProtectedCuesheet.tsx diff --git a/apps/client/src/features/cuesheet/__tests__/__snapshots__/utils.test.js.snap b/apps/client/src/views/cuesheet/__tests__/__snapshots__/utils.test.js.snap similarity index 100% rename from apps/client/src/features/cuesheet/__tests__/__snapshots__/utils.test.js.snap rename to apps/client/src/views/cuesheet/__tests__/__snapshots__/utils.test.js.snap diff --git a/apps/client/src/features/cuesheet/__tests__/utils.test.js b/apps/client/src/views/cuesheet/__tests__/utils.test.js similarity index 100% rename from apps/client/src/features/cuesheet/__tests__/utils.test.js rename to apps/client/src/views/cuesheet/__tests__/utils.test.js diff --git a/apps/client/src/features/cuesheet/cuesheet-progress/CuesheetProgress.module.scss b/apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.module.scss similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-progress/CuesheetProgress.module.scss rename to apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.module.scss diff --git a/apps/client/src/features/cuesheet/cuesheet-progress/CuesheetProgress.tsx b/apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-progress/CuesheetProgress.tsx rename to apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-elements/BlockRow.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/BlockRow.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-elements/BlockRow.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-elements/BlockRow.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-elements/CuesheetHeader.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/CuesheetHeader.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-elements/CuesheetHeader.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-elements/CuesheetHeader.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-elements/DelayRow.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/DelayRow.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-elements/DelayRow.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-elements/DelayRow.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-elements/EditableCell.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/EditableCell.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-elements/EditableCell.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-elements/EditableCell.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-elements/EventRow.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/EventRow.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-elements/EventRow.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-elements/EventRow.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-elements/SortableCell.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/SortableCell.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-elements/SortableCell.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-elements/SortableCell.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss rename to apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss diff --git a/apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx diff --git a/apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx similarity index 79% rename from apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx index 147e15a47..fdd6e032c 100644 --- a/apps/client/src/features/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx @@ -1,6 +1,6 @@ import { useClock, useTimer } from '../../../common/hooks/useSocket'; -import ClockTime from '../../viewers/common/clock-time/ClockTime'; -import RunningTime from '../../viewers/common/running-time/RunningTime'; +import ClockTime from '../../../features/viewers/common/clock-time/ClockTime'; +import RunningTime from '../../../features/viewers/common/running-time/RunningTime'; import style from './CuesheetTableHeader.module.scss'; diff --git a/apps/client/src/features/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss rename to apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss diff --git a/apps/client/src/features/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx similarity index 100% rename from apps/client/src/features/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx rename to apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx diff --git a/apps/client/src/features/cuesheet/cuesheetCols.tsx b/apps/client/src/views/cuesheet/cuesheetCols.tsx similarity index 97% rename from apps/client/src/features/cuesheet/cuesheetCols.tsx rename to apps/client/src/views/cuesheet/cuesheetCols.tsx index 29d8a3c06..24b9ab850 100644 --- a/apps/client/src/features/cuesheet/cuesheetCols.tsx +++ b/apps/client/src/views/cuesheet/cuesheetCols.tsx @@ -4,7 +4,7 @@ import { CellContext, ColumnDef } from '@tanstack/react-table'; import { CustomFields, isOntimeEvent, OntimeEvent, OntimeRundownEntry } from 'ontime-types'; import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator'; -import RunningTime from '../viewers/common/running-time/RunningTime'; +import RunningTime from '../../features/viewers/common/running-time/RunningTime'; import EditableCell from './cuesheet-table-elements/EditableCell'; import { useCuesheetSettings } from './store/CuesheetSettings'; diff --git a/apps/client/src/features/cuesheet/cuesheetUtils.ts b/apps/client/src/views/cuesheet/cuesheetUtils.ts similarity index 100% rename from apps/client/src/features/cuesheet/cuesheetUtils.ts rename to apps/client/src/views/cuesheet/cuesheetUtils.ts diff --git a/apps/client/src/features/cuesheet/defaults.ts b/apps/client/src/views/cuesheet/defaults.ts similarity index 100% rename from apps/client/src/features/cuesheet/defaults.ts rename to apps/client/src/views/cuesheet/defaults.ts diff --git a/apps/client/src/features/cuesheet/store/CuesheetSettings.tsx b/apps/client/src/views/cuesheet/store/CuesheetSettings.tsx similarity index 100% rename from apps/client/src/features/cuesheet/store/CuesheetSettings.tsx rename to apps/client/src/views/cuesheet/store/CuesheetSettings.tsx diff --git a/apps/client/src/features/cuesheet/useColumnManager.tsx b/apps/client/src/views/cuesheet/useColumnManager.tsx similarity index 100% rename from apps/client/src/features/cuesheet/useColumnManager.tsx rename to apps/client/src/views/cuesheet/useColumnManager.tsx From 7dbf64d1000735798a1d00136fde19a2b4712e79 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Tue, 10 Dec 2024 14:44:48 +0100 Subject: [PATCH 23/47] chore: restructure directory --- apps/client/src/views/cuesheet/Cuesheet.tsx | 2 +- ...r.module.scss => CuesheetPage.module.scss} | 0 .../{CuesheetWrapper.tsx => CuesheetPage.tsx} | 6 +-- .../src/views/cuesheet/ProtectedCuesheet.tsx | 4 +- .../__snapshots__/utils.test.js.snap | 41 --------------- .../{utils.test.js => cuesheet.utils.test.ts} | 50 +++++++++++++++++-- .../CuesheetTableHeader.tsx | 2 +- .../CuesheetTableSettings.tsx | 2 +- .../{defaults.ts => cuesheet.options.ts} | 0 .../{cuesheetUtils.ts => cuesheet.utils.ts} | 0 .../src/views/cuesheet/cuesheetCols.tsx | 2 +- ...Settings.tsx => cuesheetSettingsStore.tsx} | 4 +- 12 files changed, 58 insertions(+), 55 deletions(-) rename apps/client/src/views/cuesheet/{CuesheetWrapper.module.scss => CuesheetPage.module.scss} (100%) rename apps/client/src/views/cuesheet/{CuesheetWrapper.tsx => CuesheetPage.tsx} (95%) delete mode 100644 apps/client/src/views/cuesheet/__tests__/__snapshots__/utils.test.js.snap rename apps/client/src/views/cuesheet/__tests__/{utils.test.js => cuesheet.utils.test.ts} (67%) rename apps/client/src/views/cuesheet/{defaults.ts => cuesheet.options.ts} (100%) rename apps/client/src/views/cuesheet/{cuesheetUtils.ts => cuesheet.utils.ts} (100%) rename apps/client/src/views/cuesheet/store/{CuesheetSettings.tsx => cuesheetSettingsStore.tsx} (96%) diff --git a/apps/client/src/views/cuesheet/Cuesheet.tsx b/apps/client/src/views/cuesheet/Cuesheet.tsx index deaf586e5..7c4eb412e 100644 --- a/apps/client/src/views/cuesheet/Cuesheet.tsx +++ b/apps/client/src/views/cuesheet/Cuesheet.tsx @@ -11,7 +11,7 @@ import CuesheetHeader from './cuesheet-table-elements/CuesheetHeader'; import DelayRow from './cuesheet-table-elements/DelayRow'; import EventRow from './cuesheet-table-elements/EventRow'; import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings'; -import { useCuesheetSettings } from './store/CuesheetSettings'; +import { useCuesheetSettings } from './store/cuesheetSettingsStore'; import useColumnManager from './useColumnManager'; import style from './Cuesheet.module.scss'; diff --git a/apps/client/src/views/cuesheet/CuesheetWrapper.module.scss b/apps/client/src/views/cuesheet/CuesheetPage.module.scss similarity index 100% rename from apps/client/src/views/cuesheet/CuesheetWrapper.module.scss rename to apps/client/src/views/cuesheet/CuesheetPage.module.scss diff --git a/apps/client/src/views/cuesheet/CuesheetWrapper.tsx b/apps/client/src/views/cuesheet/CuesheetPage.tsx similarity index 95% rename from apps/client/src/views/cuesheet/CuesheetWrapper.tsx rename to apps/client/src/views/cuesheet/CuesheetPage.tsx index f6b9cab87..a404aa48b 100644 --- a/apps/client/src/views/cuesheet/CuesheetWrapper.tsx +++ b/apps/client/src/views/cuesheet/CuesheetPage.tsx @@ -14,13 +14,13 @@ import { useFlatRundown } from '../../common/hooks-query/useRundown'; import { CuesheetOverview } from '../../features/overview/Overview'; import CuesheetProgress from './cuesheet-progress/CuesheetProgress'; -import { useCuesheetSettings } from './store/CuesheetSettings'; +import { useCuesheetSettings } from './store/cuesheetSettingsStore'; import Cuesheet from './Cuesheet'; import { makeCuesheetColumns } from './cuesheetCols'; -import styles from './CuesheetWrapper.module.scss'; +import styles from './CuesheetPage.module.scss'; -export default function CuesheetWrapper() { +export default function CuesheetPage() { // TODO: can we use the normalised rundown for the table? const { data: flatRundown, status: rundownStatus } = useFlatRundown(); const { data: customFields } = useCustomFields(); diff --git a/apps/client/src/views/cuesheet/ProtectedCuesheet.tsx b/apps/client/src/views/cuesheet/ProtectedCuesheet.tsx index 6a31c1742..af8c4aee7 100644 --- a/apps/client/src/views/cuesheet/ProtectedCuesheet.tsx +++ b/apps/client/src/views/cuesheet/ProtectedCuesheet.tsx @@ -1,11 +1,11 @@ import ProtectRoute from '../../common/components/protect-route/ProtectRoute'; -import CuesheetWrapper from './CuesheetWrapper'; +import CuesheetPage from './CuesheetPage'; export default function ProtectedCuesheet() { return ( - + ); } diff --git a/apps/client/src/views/cuesheet/__tests__/__snapshots__/utils.test.js.snap b/apps/client/src/views/cuesheet/__tests__/__snapshots__/utils.test.js.snap deleted file mode 100644 index 5214b2670..000000000 --- a/apps/client/src/views/cuesheet/__tests__/__snapshots__/utils.test.js.snap +++ /dev/null @@ -1,41 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`makeTable() > returns array of arrays with given fields 1`] = ` -[ - [ - "Ontime · Rundown export", - ], - [ - "Project title: test title", - ], - [ - "Project description: test description", - ], - [ - "Time Start", - "Time End", - "Duration", - "ID", - "Colour", - "Cue", - "Title", - "Note", - "Is Public? (x)", - "Skip?", - "lighting", - ], - [ - "00:00:00", - "00:00:00", - "...", - "", - "", - "", - "test title 1", - "", - "x", - "", - "", - ], -] -`; diff --git a/apps/client/src/views/cuesheet/__tests__/utils.test.js b/apps/client/src/views/cuesheet/__tests__/cuesheet.utils.test.ts similarity index 67% rename from apps/client/src/views/cuesheet/__tests__/utils.test.js rename to apps/client/src/views/cuesheet/__tests__/cuesheet.utils.test.ts index d62ed12e7..a7b162246 100644 --- a/apps/client/src/views/cuesheet/__tests__/utils.test.js +++ b/apps/client/src/views/cuesheet/__tests__/cuesheet.utils.test.ts @@ -1,4 +1,6 @@ -import { makeCSV, makeTable, parseField } from '../cuesheetUtils'; +import { ProjectData } from 'ontime-types'; + +import { makeCSV, makeTable, parseField } from '../cuesheet.utils'; describe('parseField()', () => { it('returns a string from given millis on timeStart, TimeEnd and duration', () => { @@ -27,6 +29,7 @@ describe('parseField()', () => { }); it('returns an empty string on undefined fields', () => { + // @ts-expect-error -- testing user data with missing fields expect(parseField('title')).toBe(''); }); @@ -51,6 +54,7 @@ describe('makeTable()', () => { const headerData = { title: 'test title', description: 'test description', + projectLogo: 'test logo', }; const tableData = [ { @@ -66,8 +70,48 @@ describe('makeTable()', () => { lighting: { label: 'test' }, }; - const table = makeTable(headerData, tableData, customFields); - expect(table).toMatchSnapshot(); + // @ts-expect-error -- testing user data with missing fields + const table = makeTable(headerData as ProjectData, tableData, customFields); + expect(table).not.toContain('test logo'); + expect(table).toMatchInlineSnapshot(` + [ + [ + "Ontime · Rundown export", + ], + [ + "Project title: test title", + ], + [ + "Project description: test description", + ], + [ + "Time Start", + "Time End", + "Duration", + "ID", + "Colour", + "Cue", + "Title", + "Note", + "Is Public? (x)", + "Skip?", + "lighting", + ], + [ + "00:00:00", + "00:00:00", + "...", + "", + "", + "", + "test title 1", + "", + "x", + "", + "", + ], + ] + `); }); }); diff --git a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx index 1966a0e52..94f65896c 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx @@ -6,7 +6,7 @@ import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon' import useProjectData from '../../../common/hooks-query/useProjectData'; import { cx, enDash } from '../../../common/utils/styleUtils'; import { tooltipDelayFast } from '../../../ontimeConfig'; -import { useCuesheetSettings } from '../store/CuesheetSettings'; +import { useCuesheetSettings } from '../store/cuesheetSettingsStore'; import CuesheetTableHeaderTimers from './CuesheetTableHeaderTimers'; diff --git a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx index a5990accb..290512c19 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx @@ -3,7 +3,7 @@ import { Button, Checkbox, Switch } from '@chakra-ui/react'; import { Column } from '@tanstack/react-table'; import { OntimeRundownEntry } from 'ontime-types'; -import { useCuesheetSettings } from '../store/CuesheetSettings'; +import { useCuesheetSettings } from '../store/cuesheetSettingsStore'; import style from './CuesheetTableSettings.module.scss'; diff --git a/apps/client/src/views/cuesheet/defaults.ts b/apps/client/src/views/cuesheet/cuesheet.options.ts similarity index 100% rename from apps/client/src/views/cuesheet/defaults.ts rename to apps/client/src/views/cuesheet/cuesheet.options.ts diff --git a/apps/client/src/views/cuesheet/cuesheetUtils.ts b/apps/client/src/views/cuesheet/cuesheet.utils.ts similarity index 100% rename from apps/client/src/views/cuesheet/cuesheetUtils.ts rename to apps/client/src/views/cuesheet/cuesheet.utils.ts diff --git a/apps/client/src/views/cuesheet/cuesheetCols.tsx b/apps/client/src/views/cuesheet/cuesheetCols.tsx index 24b9ab850..42b91ddc0 100644 --- a/apps/client/src/views/cuesheet/cuesheetCols.tsx +++ b/apps/client/src/views/cuesheet/cuesheetCols.tsx @@ -7,7 +7,7 @@ import DelayIndicator from '../../common/components/delay-indicator/DelayIndicat import RunningTime from '../../features/viewers/common/running-time/RunningTime'; import EditableCell from './cuesheet-table-elements/EditableCell'; -import { useCuesheetSettings } from './store/CuesheetSettings'; +import { useCuesheetSettings } from './store/cuesheetSettingsStore'; import style from './Cuesheet.module.scss'; diff --git a/apps/client/src/views/cuesheet/store/CuesheetSettings.tsx b/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx similarity index 96% rename from apps/client/src/views/cuesheet/store/CuesheetSettings.tsx rename to apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx index aacf0e256..f9eb5d0fb 100644 --- a/apps/client/src/views/cuesheet/store/CuesheetSettings.tsx +++ b/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx @@ -2,7 +2,7 @@ import { create } from 'zustand'; import { booleanFromLocalStorage } from '../../../common/utils/localStorage'; -interface CuesheetSettings { +interface CuesheetSettingsStore { showSettings: boolean; showIndexColumn: boolean; followSelected: boolean; @@ -36,7 +36,7 @@ enum CuesheetKeys { Seconds = 'ontime-cuesheet-hide-sceconds', } -export const useCuesheetSettings = create()((set) => ({ +export const useCuesheetSettings = create()((set) => ({ showSettings: false, showIndexColumn: booleanFromLocalStorage(CuesheetKeys.ColumnIndex, true), followSelected: booleanFromLocalStorage(CuesheetKeys.Follow, false), From 7915cc822da70763bd001397a18ef635577a286a Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Tue, 10 Dec 2024 23:27:51 +0100 Subject: [PATCH 24/47] Dockersafe rename (#1370) * add dockerSafeRename function * replace all rename functions * add explanation to function --- .../services/project-service/ProjectService.ts | 7 ++++--- .../project-service/projectServiceUtils.ts | 15 ++++++++++----- apps/server/src/utils/fileManagement.ts | 13 +++++++++++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/server/src/services/project-service/ProjectService.ts b/apps/server/src/services/project-service/ProjectService.ts index 2b50a0661..6cc13d947 100644 --- a/apps/server/src/services/project-service/ProjectService.ts +++ b/apps/server/src/services/project-service/ProjectService.ts @@ -1,12 +1,13 @@ import { DatabaseModel, LogOrigin, ProjectFileListResponse } from 'ontime-types'; import { getErrorMessage } from 'ontime-utils'; -import { copyFile, rename } from 'fs/promises'; +import { copyFile } from 'fs/promises'; import { logger } from '../../classes/Logger.js'; import { publicDir } from '../../setup/index.js'; import { appendToName, + dockerSafeRename, ensureDirectory, generateUniqueFileName, getFileNameFromPath, @@ -93,7 +94,7 @@ async function handleCorruptedFile(filePath: string, fileName: string): Promise< // and make a new file with the recovered data const newPath = appendToName(filePath, '(recovered)'); - await rename(filePath, newPath); + await dockerSafeRename(filePath, newPath); return getFileNameFromPath(newPath); } @@ -231,7 +232,7 @@ export async function renameProjectFile(originalFile: string, newFilename: strin } const pathToRenamed = getPathToProject(newFilename); - await rename(projectFilePath, pathToRenamed); + await dockerSafeRename(projectFilePath, pathToRenamed); // Update the last loaded project config if current loaded project is the one being renamed const isLoaded = await isLastLoadedProject(originalFile); diff --git a/apps/server/src/services/project-service/projectServiceUtils.ts b/apps/server/src/services/project-service/projectServiceUtils.ts index e28116586..1728c3d8d 100644 --- a/apps/server/src/services/project-service/projectServiceUtils.ts +++ b/apps/server/src/services/project-service/projectServiceUtils.ts @@ -1,11 +1,16 @@ import { DatabaseModel, MaybeString, ProjectFile } from 'ontime-types'; import { existsSync } from 'fs'; -import { copyFile, readFile, rename, stat } from 'fs/promises'; +import { copyFile, readFile, stat } from 'fs/promises'; import { extname, join } from 'path'; import { publicDir } from '../../setup/index.js'; -import { ensureDirectory, getFilesFromFolder, removeFileExtension } from '../../utils/fileManagement.js'; +import { + dockerSafeRename, + ensureDirectory, + getFilesFromFolder, + removeFileExtension, +} from '../../utils/fileManagement.js'; /** * Handles the upload of a new project file @@ -14,13 +19,13 @@ import { ensureDirectory, getFilesFromFolder, removeFileExtension } from '../../ */ export async function handleUploaded(filePath: string, name: string) { const newFilePath = join(publicDir.projectsDir, name); - await rename(filePath, newFilePath); + await dockerSafeRename(filePath, newFilePath); } export async function handleImageUpload(filePath: string, name: string): Promise { ensureDirectory(publicDir.logoDir); const newFilePath = join(publicDir.logoDir, name); - await rename(filePath, newFilePath); + await dockerSafeRename(filePath, newFilePath); return name; } @@ -86,7 +91,7 @@ export async function copyCorruptFile(filePath: string, name: string): Promise { const newPath = join(publicDir.corruptDir, name); - return rename(filePath, newPath); + return dockerSafeRename(filePath, newPath); } /** diff --git a/apps/server/src/utils/fileManagement.ts b/apps/server/src/utils/fileManagement.ts index 5a2d361dd..759a6ee29 100644 --- a/apps/server/src/utils/fileManagement.ts +++ b/apps/server/src/utils/fileManagement.ts @@ -1,5 +1,5 @@ -import { existsSync, mkdirSync } from 'fs'; -import { readdir, copyFile } from 'fs/promises'; +import { existsSync, mkdirSync, PathLike } from 'fs'; +import { readdir, copyFile, unlink } from 'fs/promises'; import { basename, extname, join, parse } from 'path'; /** @@ -105,3 +105,12 @@ export async function copyDirectory(src: string, dest: string) { } } } + +/** + * workaround avoids origin errors in docker deployments + * EXDEV cross-device link not permitted + */ +export async function dockerSafeRename(oldPath: PathLike, newPath: PathLike) { + await copyFile(oldPath, newPath); + await unlink(oldPath); +} From c1d53b0e55224186f45aff0742a1aec5250262be Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 13 Dec 2024 10:08:11 +0100 Subject: [PATCH 25/47] refactor: improve empty state for project info --- .../components/state/EmptyPage.module.scss | 20 +++++++++++++++++ .../src/common/components/state/EmptyPage.tsx | 20 +++++++++++++++++ .../src/views/project-info/ProjectInfo.tsx | 22 ++++++++++++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 apps/client/src/common/components/state/EmptyPage.module.scss create mode 100644 apps/client/src/common/components/state/EmptyPage.tsx diff --git a/apps/client/src/common/components/state/EmptyPage.module.scss b/apps/client/src/common/components/state/EmptyPage.module.scss new file mode 100644 index 000000000..b3dea3ab5 --- /dev/null +++ b/apps/client/src/common/components/state/EmptyPage.module.scss @@ -0,0 +1,20 @@ +@use '../../../theme/viewerDefs' as *; + +/* share the same style as a page layout */ +.page { + margin: 0; + box-sizing: border-box; /* reset */ + overflow: hidden; + width: 100%; /* restrict the page width to viewport */ + height: 100vh; + + font-family: var(--font-family-override, $viewer-font-family); + background: var(--background-color-override, $viewer-background-color); + color: var(--color-override, $viewer-color); + padding: min(2vh, 16px) clamp(16px, 10vw, 64px); + + display: flex; + flex-direction: column; + align-items: center; + padding-top: 5rem; +} diff --git a/apps/client/src/common/components/state/EmptyPage.tsx b/apps/client/src/common/components/state/EmptyPage.tsx new file mode 100644 index 000000000..4bfc3f37e --- /dev/null +++ b/apps/client/src/common/components/state/EmptyPage.tsx @@ -0,0 +1,20 @@ +import { CSSProperties } from 'react'; + +import Empty from './Empty'; + +import style from './EmptyPage.module.scss'; + +interface EmptyPageProps { + text?: string; + style?: CSSProperties; +} + +export default function EmptyPage(props: EmptyPageProps) { + const { text, ...rest } = props; + + return ( +
    + +
    + ); +} diff --git a/apps/client/src/views/project-info/ProjectInfo.tsx b/apps/client/src/views/project-info/ProjectInfo.tsx index b31b6c3ce..5f8f9e0cd 100644 --- a/apps/client/src/views/project-info/ProjectInfo.tsx +++ b/apps/client/src/views/project-info/ProjectInfo.tsx @@ -1,6 +1,7 @@ import { ProjectData } from 'ontime-types'; import Empty from '../../common/components/state/Empty'; +import EmptyPage from '../../common/components/state/EmptyPage'; import ViewLogo from '../../common/components/view-logo/ViewLogo'; import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor'; import { useWindowTitle } from '../../common/hooks/useWindowTitle'; @@ -16,7 +17,7 @@ interface ProjectInfoProps { isMirrored: boolean; } -export default function ProjectInfoProps(props: ProjectInfoProps) { +export default function ProjectInfo(props: ProjectInfoProps) { const { general, isMirrored } = props; useWindowTitle('Project info'); @@ -25,6 +26,25 @@ export default function ProjectInfoProps(props: ProjectInfoProps) { return ; } + if (!general) { + return ( + <> + + return ; + + ); + } + + const isEmpty = Object.values(general).every((value) => !value); + if (isEmpty) { + return ( + <> + + ; + + ); + } + return (
    From fb83f48752a7d5e190158079bd7fbebdd339c66c Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 12 Dec 2024 20:43:23 +0100 Subject: [PATCH 26/47] refactor: maintain an isOnline flag in client --- apps/client/src/common/stores/runtime.ts | 12 +++-- apps/client/src/common/utils/socket.ts | 57 +++++++++++++++--------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/apps/client/src/common/stores/runtime.ts b/apps/client/src/common/stores/runtime.ts index 6bbb68c0b..e8a291932 100644 --- a/apps/client/src/common/stores/runtime.ts +++ b/apps/client/src/common/stores/runtime.ts @@ -16,11 +16,17 @@ export const useRuntimeStore = (selector: (state: RuntimeStore) => T) => /** * Allows patching a property of the runtime store - * @param key - * @param value */ -export function patchRuntime(key: K, value: RuntimeStore[K]): void { +export function patchRuntimeProperty(key: K, value: RuntimeStore[K]) { const state = runtimeStore.getState(); state[key] = value; runtimeStore.setState({ ...state }); } + +/** + * Allows patching the entire runtime store + */ +export function patchRuntime(patch: Partial) { + const state = runtimeStore.getState(); + runtimeStore.setState({ ...state, ...patch }); +} diff --git a/apps/client/src/common/utils/socket.ts b/apps/client/src/common/utils/socket.ts index ff0013bd0..6b7f26c3b 100644 --- a/apps/client/src/common/utils/socket.ts +++ b/apps/client/src/common/utils/socket.ts @@ -14,7 +14,7 @@ import { } from '../stores/clientStore'; import { addDialog } from '../stores/dialogStore'; import { addLog } from '../stores/logger'; -import { patchRuntime, runtimeStore } from '../stores/runtime'; +import { patchRuntime, patchRuntimeProperty } from '../stores/runtime'; export let websocket: WebSocket | null = null; let reconnectTimeout: NodeJS.Timeout | null = null; @@ -39,12 +39,14 @@ export const connectSocket = () => { } socketSendJson('set-client-type', 'ontime'); - socketSendJson('set-client-path', location.pathname + location.search); + setOnlineStatus(true); }; websocket.onclose = () => { console.warn('WebSocket disconnected'); + setOnlineStatus(false); + if (shouldReconnect) { reconnectTimeout = setTimeout(() => { console.warn('WebSocket: attempting reconnect'); @@ -73,8 +75,8 @@ export const connectSocket = () => { switch (type) { case 'pong': { const offset = (new Date().getTime() - new Date(payload).getTime()) * 0.5; - patchRuntime('ping', offset); - updateDevTools({ ping: offset }, ['PING']); + patchRuntimeProperty('ping', offset); + updateDevTools({ ping: offset }); break; } case 'client-id': { @@ -131,64 +133,65 @@ export const connectSocket = () => { break; } case 'ontime': { - runtimeStore.setState(payload as RuntimeStore); - if (!isProduction) { - ontimeQueryClient.setQueryData(RUNTIME, data.payload); - } + // eslint-disable-next-line @typescript-eslint/no-unused-vars -- removing the key from the payload + const { ping, ...serverPayload } = payload as Partial; + + patchRuntime(serverPayload); + updateDevTools(serverPayload); break; } case 'ontime-clock': { - patchRuntime('clock', payload); + patchRuntimeProperty('clock', payload); updateDevTools({ clock: payload }); break; } case 'ontime-timer': { - patchRuntime('timer', payload); + patchRuntimeProperty('timer', payload); updateDevTools({ timer: payload }); break; } case 'ontime-onAir': { - patchRuntime('onAir', payload); + patchRuntimeProperty('onAir', payload); updateDevTools({ onAir: payload }); break; } case 'ontime-message': { - patchRuntime('message', payload); + patchRuntimeProperty('message', payload); updateDevTools({ message: payload }); break; } case 'ontime-runtime': { - patchRuntime('runtime', payload); + patchRuntimeProperty('runtime', payload); updateDevTools({ runtime: payload }); break; } case 'ontime-eventNow': { - patchRuntime('eventNow', payload); + patchRuntimeProperty('eventNow', payload); updateDevTools({ eventNow: payload }); break; } case 'ontime-currentBlock': { - patchRuntime('currentBlock', payload); + patchRuntimeProperty('currentBlock', payload); updateDevTools({ currentBlock: payload }); break; } case 'ontime-publicEventNow': { - patchRuntime('publicEventNow', payload); + patchRuntimeProperty('publicEventNow', payload); updateDevTools({ publicEventNow: payload }); break; } case 'ontime-eventNext': { - patchRuntime('eventNext', payload); + patchRuntimeProperty('eventNext', payload); updateDevTools({ eventNext: payload }); break; } case 'ontime-publicEventNext': { - patchRuntime('publicEventNext', payload); + patchRuntimeProperty('publicEventNext', payload); updateDevTools({ publicEventNext: payload }); break; } case 'ontime-auxtimer1': { - patchRuntime('auxtimer1', payload); + patchRuntimeProperty('auxtimer1', payload); updateDevTools({ auxtimer1: payload }); break; } @@ -232,11 +235,23 @@ export const socketSendJson = (type: string, payload?: unknown) => { ); }; -function updateDevTools(newData: Partial, store = RUNTIME) { +function updateDevTools(newData: Partial) { if (!isProduction) { - ontimeQueryClient.setQueryData(store, (oldData: RuntimeStore) => ({ + ontimeQueryClient.setQueryData(RUNTIME, (oldData: RuntimeStore) => ({ ...oldData, ...newData, })); } } + +/** + * Allows setting the status of the client + * We leverage the ping as an indication of the client's online status + * @example ping < 0 - client is offline + * @example ping > 0 -> client is online + */ +function setOnlineStatus(status: boolean) { + const derivedPing = status ? 1 : -1; + patchRuntimeProperty('ping', derivedPing); + updateDevTools({ ping: derivedPing }); +} From ef2ea9a1da37581a1407f18c8af49bc6084d1d73 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 12 Dec 2024 19:59:17 +0100 Subject: [PATCH 27/47] fix: recover edit menu and shortcuts --- apps/electron/src/menu/applicationMenu.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/electron/src/menu/applicationMenu.js b/apps/electron/src/menu/applicationMenu.js index a5d9f2682..85d04754f 100644 --- a/apps/electron/src/menu/applicationMenu.js +++ b/apps/electron/src/menu/applicationMenu.js @@ -29,6 +29,7 @@ function getApplicationMenu(askToQuit, clientUrl, serverUrl, redirectWindow, sho const template = [ ...(isMac ? [makeMacMenu(askToQuit)] : []), makeFileMenu(serverUrl, redirectWindow, showDialog, download), + makeEditMenu(), makeViewMenu(clientUrl), makeSettingsMenu(redirectWindow), makeHelpMenu(redirectWindow), @@ -61,6 +62,22 @@ function makeMacMenu(askToQuit) { }; } +/** + * Utility function generates the edit menu + * @returns {Object} + */ +function makeEditMenu() { + return { + label: 'Edit', + submenu: [ + { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' }, + { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' }, + { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' }, + { label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }, + ], + }; +} + /** * Utility function generates the file menu * @param {string} serverUrl - base url for the application @@ -253,7 +270,7 @@ function makeSettingsMenu(redirectWindow) { click: () => redirectWindow('/editor?settings=network__log'), }, { - label: 'Manage cleints', + label: 'Manage clients', click: () => redirectWindow('/editor?settings=network__clients'), }, ], From 466360f9d113d7db70280519f15469b55d4e182c Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 11 Dec 2024 21:25:59 +0100 Subject: [PATCH 28/47] chore: note service limitations --- .../app-settings/panel/integrations-panel/OscIntegrations.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/client/src/features/app-settings/panel/integrations-panel/OscIntegrations.tsx b/apps/client/src/features/app-settings/panel/integrations-panel/OscIntegrations.tsx index 1c604f31b..d124a2313 100644 --- a/apps/client/src/features/app-settings/panel/integrations-panel/OscIntegrations.tsx +++ b/apps/client/src/features/app-settings/panel/integrations-panel/OscIntegrations.tsx @@ -10,6 +10,7 @@ import { maybeAxiosError } from '../../../../common/api/utils'; import useOscSettings, { useOscSettingsMutation } from '../../../../common/hooks-query/useOscSettings'; import { isKeyEscape } from '../../../../common/utils/keyEvent'; import { isASCII, isASCIIorEmpty, isIPAddress, isOnlyNumbers, startsWithSlash } from '../../../../common/utils/regex'; +import { isOntimeCloud } from '../../../../externals'; import * as Panel from '../../panel-utils/PanelUtils'; import { cycles } from './integrationUtils'; @@ -106,6 +107,9 @@ export default function OscIntegrations() {
    + {isOntimeCloud && ( + For security reasons OSC integrations are not available in the cloud service. + )} From 5032cbf65a9175a0345f2bbefeb4ee8835ca6007 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 12 Dec 2024 19:58:27 +0100 Subject: [PATCH 29/47] refactor: prevent instantiating unavailable services --- apps/server/src/app.ts | 27 ++++++++++++++++----------- apps/server/src/externals.ts | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 6f6cf9ac5..576edb2d6 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -10,7 +10,7 @@ import { extname } from 'node:path'; // import utils import { publicDir, srcDir, srcFiles } from './setup/index.js'; -import { environment, isProduction, updateRouterPrefix } from './externals.js'; +import { environment, isOntimeCloud, isProduction, updateRouterPrefix } from './externals.js'; import { ONTIME_VERSION } from './ONTIME_VERSION.js'; import { consoleSuccess, consoleHighlight, consoleError } from './utils/console.js'; @@ -249,16 +249,6 @@ export const startIntegrations = async () => { // if a config is not provided, we use the persisted one const { osc, http } = getDataProvider().getData(); - if (osc) { - logger.info(LogOrigin.Tx, 'Initialising OSC Integration...'); - try { - oscIntegration.init(osc); - integrationService.register(oscIntegration); - } catch (error) { - logger.error(LogOrigin.Tx, 'OSC Integration initialisation failed'); - } - } - if (http) { logger.info(LogOrigin.Tx, 'Initialising HTTP Integration...'); try { @@ -268,6 +258,21 @@ export const startIntegrations = async () => { logger.error(LogOrigin.Tx, `HTTP Integration initialisation failed: ${error}`); } } + + if (isOntimeCloud) { + logger.info(LogOrigin.Tx, 'Skipping OSC in Cloud environment...'); + return; + } + + if (osc) { + logger.info(LogOrigin.Tx, 'Initialising OSC Integration...'); + try { + oscIntegration.init(osc); + integrationService.register(oscIntegration); + } catch (error) { + logger.error(LogOrigin.Tx, 'OSC Integration initialisation failed'); + } + } }; /** diff --git a/apps/server/src/externals.ts b/apps/server/src/externals.ts index 6bbbab2dd..13e886e41 100644 --- a/apps/server/src/externals.ts +++ b/apps/server/src/externals.ts @@ -14,7 +14,7 @@ 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); /** * Updates the router prefix in the index.html file * This is only needed in the cloud environment where the client is not at the root segment From b64b154330c0ab4450dffdc60cf64af429c54bfa Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 13 Dec 2024 09:50:32 +0100 Subject: [PATCH 30/47] refactor: disable shutdown --- .../panel/shutdown-panel/ShutdownPanel.tsx | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/client/src/features/app-settings/panel/shutdown-panel/ShutdownPanel.tsx b/apps/client/src/features/app-settings/panel/shutdown-panel/ShutdownPanel.tsx index 21f192df4..e6b203b54 100644 --- a/apps/client/src/features/app-settings/panel/shutdown-panel/ShutdownPanel.tsx +++ b/apps/client/src/features/app-settings/panel/shutdown-panel/ShutdownPanel.tsx @@ -11,7 +11,7 @@ import { } from '@chakra-ui/react'; import { useElectronEvent } from '../../../../common/hooks/useElectronEvent'; -import { isLocalhost } from '../../../../externals'; +import { isLocalhost, isOntimeCloud } from '../../../../externals'; import * as Panel from '../../panel-utils/PanelUtils'; export default function ShutdownPanel() { @@ -24,18 +24,28 @@ export default function ShutdownPanel() { onClose(); }; + const canShutdown = isElectron || isLocalhost; + return ( <> Shutdown Ontime - - This will shutdown the Ontime server.
    - The runtime state will be lost, but your project is kept for next time. -
    + {isOntimeCloud ? ( + + For security reasons, shutting down the server must be done from the Ontime Cloud dashboard. + + ) : ( + + This will shutdown the Ontime server.
    + The runtime state will be lost, but your project is kept for next time. +
    + )} - Note: Ontime can only be shutdown from the machine it is running in. + {!canShutdown && ( + Note: Ontime can only be shutdown from the machine it is running in. + )} @@ -49,7 +59,7 @@ export default function ShutdownPanel() { - From a1fb64244117f0d6a809817371826fe7cfabc416 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 13 Dec 2024 09:53:23 +0100 Subject: [PATCH 31/47] bump version to 3.9.5 --- apps/cli/package.json | 2 +- apps/client/package.json | 2 +- apps/electron/package.json | 2 +- apps/server/package.json | 2 +- package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index b09f1f881..d73c63baf 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@getontime/cli", - "version": "3.9.4", + "version": "3.9.5", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/client/package.json b/apps/client/package.json index 55625a0ae..2b3a49cc1 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "ontime-ui", - "version": "3.9.4", + "version": "3.9.5", "private": true, "type": "module", "dependencies": { diff --git a/apps/electron/package.json b/apps/electron/package.json index 1cdd1a8a7..7b11aff71 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.4", + "version": "3.9.5", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/apps/server/package.json b/apps/server/package.json index 468d168ec..325cb79c8 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "ontime-server", "type": "module", "main": "src/index.ts", - "version": "3.9.4", + "version": "3.9.5", "exports": "./src/index.js", "dependencies": { "@googleapis/sheets": "^5.0.5", diff --git a/package.json b/package.json index d5073a6cd..c5dd11bc4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "3.9.4", + "version": "3.9.5", "description": "Time keeping for live events", "keywords": [ "ontime", From 26a24449de55d6243372e70a3c4028db93c3317e Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 13 Dec 2024 10:11:56 +0100 Subject: [PATCH 32/47] refactor: prevent modal close on click outside --- apps/client/src/features/editors/welcome/Welcome.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/features/editors/welcome/Welcome.tsx b/apps/client/src/features/editors/welcome/Welcome.tsx index 1090b67da..ca8299f4f 100644 --- a/apps/client/src/features/editors/welcome/Welcome.tsx +++ b/apps/client/src/features/editors/welcome/Welcome.tsx @@ -53,7 +53,7 @@ export default function Welcome(props: WelcomeProps) { }; return ( - + From 4c6acc40134def3aa85a214d5c86196119c7c38b Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 13 Dec 2024 11:13:26 +0100 Subject: [PATCH 33/47] refactor: improve active styles for navigation buttons --- .../common/components/navigation-menu/NavigationMenu.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx b/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx index 97371d8e9..e695c5b76 100644 --- a/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx +++ b/apps/client/src/common/components/navigation-menu/NavigationMenu.tsx @@ -45,7 +45,7 @@ function NavigationMenu(props: NavigationMenuProps) { const { isOpen: isOpenRename, onOpen: onRenameOpen, onClose: onCloseRename } = useDisclosure(); const { fullscreen, toggle } = useFullscreen(); - const { toggleMirror } = useViewOptionsStore(); + const { mirror, toggleMirror } = useViewOptionsStore(); const location = useLocation(); const menuRef = useRef(null); @@ -65,7 +65,7 @@ function NavigationMenu(props: NavigationMenuProps) {
    : }
    toggleMirror()} From d46dfcf82e5fe77b9d18b4a3732cd564e1f853b2 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Fri, 13 Dec 2024 11:02:07 +0100 Subject: [PATCH 34/47] refactor: improve redirect --- apps/client/src/common/hooks/useClientPath.ts | 15 +++++++++++---- apps/client/src/common/hooks/useSocket.ts | 9 +++++++++ apps/client/src/common/utils/socket.ts | 1 - 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/client/src/common/hooks/useClientPath.ts b/apps/client/src/common/hooks/useClientPath.ts index 4c0d7b866..917b3de72 100644 --- a/apps/client/src/common/hooks/useClientPath.ts +++ b/apps/client/src/common/hooks/useClientPath.ts @@ -4,16 +4,23 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { useClientStore } from '../stores/clientStore'; import { socketSendJson } from '../utils/socket'; +import { useIsOnline } from './useSocket'; + export const useClientPath = () => { const navigate = useNavigate(); const { pathname, search } = useLocation(); - const redirect = useClientStore((store) => store.redirect); - const setRedirect = useClientStore((store) => store.setRedirect); + const { redirect, setRedirect } = useClientStore((store) => ({ + redirect: store.redirect, + setRedirect: store.setRedirect, + })); + const isOnline = useIsOnline(); // notify of client path changes useEffect(() => { + if (!isOnline) return; + socketSendJson('set-client-path', pathname + search); - }, [pathname, search]); + }, [pathname, search, isOnline]); // navigate to new path when received from server useEffect(() => { @@ -26,7 +33,7 @@ export const useClientPath = () => { // navigate if there is a path change if (redirect !== pathname + search) { - navigate(redirect); + navigate(redirect, { replace: true }); } }, [navigate, pathname, redirect, search, setRedirect]); }; diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index a990bacc9..ee56a8b5a 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -238,3 +238,12 @@ export const usePing = () => { return useRuntimeStore(featureSelector); }; + +/** convert ping into a derived value which changes less often */ +export const useIsOnline = () => { + const featureSelector = (state: RuntimeStore) => ({ + isOnline: state.ping > 0, + }); + + return useRuntimeStore(featureSelector); +}; diff --git a/apps/client/src/common/utils/socket.ts b/apps/client/src/common/utils/socket.ts index 6b7f26c3b..4af7af816 100644 --- a/apps/client/src/common/utils/socket.ts +++ b/apps/client/src/common/utils/socket.ts @@ -39,7 +39,6 @@ export const connectSocket = () => { } socketSendJson('set-client-type', 'ontime'); - socketSendJson('set-client-path', location.pathname + location.search); setOnlineStatus(true); }; From 6c5afcb8d9c1a4ab60af57f1648c33ef28c11bf2 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sat, 14 Dec 2024 11:48:08 +0100 Subject: [PATCH 35/47] refactor: improve empty state for pages --- apps/client/src/features/operator/Operator.tsx | 4 ++-- apps/client/src/views/cuesheet/CuesheetPage.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/client/src/features/operator/Operator.tsx b/apps/client/src/features/operator/Operator.tsx index ea9c07a96..ef13e3652 100644 --- a/apps/client/src/features/operator/Operator.tsx +++ b/apps/client/src/features/operator/Operator.tsx @@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom'; import { isOntimeEvent, OntimeEvent, SupportedEvent } from 'ontime-types'; import { getFirstEventNormal, getLastEventNormal } from 'ontime-utils'; -import Empty from '../../common/components/state/Empty'; +import EmptyPage from '../../common/components/state/EmptyPage'; import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor'; import useFollowComponent from '../../common/hooks/useFollowComponent'; import { useOperator } from '../../common/hooks/useSocket'; @@ -108,7 +108,7 @@ export default function Operator() { const isLoading = status === 'pending' || customFieldStatus === 'pending' || projectDataStatus === 'pending'; if (missingData || isLoading) { - return ; + return ; } // get fields which the user subscribed to diff --git a/apps/client/src/views/cuesheet/CuesheetPage.tsx b/apps/client/src/views/cuesheet/CuesheetPage.tsx index a404aa48b..585304429 100644 --- a/apps/client/src/views/cuesheet/CuesheetPage.tsx +++ b/apps/client/src/views/cuesheet/CuesheetPage.tsx @@ -5,7 +5,7 @@ import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline' import { CustomFieldLabel, isOntimeEvent } from 'ontime-types'; import ProductionNavigationMenu from '../../common/components/navigation-menu/ProductionNavigationMenu'; -import Empty from '../../common/components/state/Empty'; +import EmptyPage from '../../common/components/state/EmptyPage'; import { useEventAction } from '../../common/hooks/useEventAction'; import { useCuesheet } from '../../common/hooks/useSocket'; import { useWindowTitle } from '../../common/hooks/useWindowTitle'; @@ -79,7 +79,7 @@ export default function CuesheetPage() { ); if (!customFields || !flatRundown || rundownStatus !== 'success') { - return ; + return ; } return ( From acc6ba63bad1834a4d4932fa3d69ec268d4d2e1b Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 10:52:38 +0100 Subject: [PATCH 36/47] refactor: keep drawer open on submit --- .../common/components/view-params-editor/ViewParamsEditor.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx index 25c04b998..d7e0bac5b 100644 --- a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx +++ b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx @@ -115,8 +115,6 @@ export default function ViewParamsEditor({ viewOptions }: EditFormDrawerProps) { const newParamsObject = Object.fromEntries(new FormData(formEvent.currentTarget)); const newSearchParams = getURLSearchParamsFromObj(newParamsObject, viewOptions); setSearchParams(newSearchParams); - - onClose(); }; return ( From 3701ba51746baa3d7635aab9b60005d56064932c Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 10:53:22 +0100 Subject: [PATCH 37/47] refactor: handle missing data --- apps/client/src/features/overview/Overview.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/client/src/features/overview/Overview.tsx b/apps/client/src/features/overview/Overview.tsx index 162e3e75a..3a86e8764 100644 --- a/apps/client/src/features/overview/Overview.tsx +++ b/apps/client/src/features/overview/Overview.tsx @@ -87,6 +87,10 @@ function _CuesheetOverview({ children }: { children: React.ReactNode }) { function TitlesOverview() { const { data } = useProjectData(); + if (!data.title && !data.description) { + return null; + } + return (
    {data.title}
    From 976dc9cbdeb77cac715d754353d7aee945df97c1 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 10:54:18 +0100 Subject: [PATCH 38/47] refactor: tweak header style --- apps/client/src/views/cuesheet/Cuesheet.module.scss | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/client/src/views/cuesheet/Cuesheet.module.scss b/apps/client/src/views/cuesheet/Cuesheet.module.scss index 1fccb55a6..a5064eb87 100644 --- a/apps/client/src/views/cuesheet/Cuesheet.module.scss +++ b/apps/client/src/views/cuesheet/Cuesheet.module.scss @@ -45,12 +45,11 @@ $table-header-font-size: calc(1rem - 3px); .tableHeader { position: sticky; - top: -1px; + top: 0px; z-index: 10; - + background-color: $ui-black; font-size: $table-header-font-size; - color: $gray-700; -} + color: $label-gray;} th { background-color: $gray-1300; From 89e68c3b0ef0e0b5069c9227e025192e28fdbe9e Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 10:55:29 +0100 Subject: [PATCH 39/47] fix: correct aria label --- apps/client/src/views/cuesheet/CuesheetPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/client/src/views/cuesheet/CuesheetPage.tsx b/apps/client/src/views/cuesheet/CuesheetPage.tsx index 585304429..df49c8499 100644 --- a/apps/client/src/views/cuesheet/CuesheetPage.tsx +++ b/apps/client/src/views/cuesheet/CuesheetPage.tsx @@ -87,14 +87,14 @@ export default function CuesheetPage() { } onClick={onOpen} /> } From 4a70bcfe64f1996e419941313c5fe2e356e40b18 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 10:55:59 +0100 Subject: [PATCH 40/47] chore: remove unused --- .../CuesheetTableHeader.module.scss | 120 ------------------ .../CuesheetTableHeader.tsx | 70 ---------- .../CuesheetTableHeaderTimers.tsx | 23 ---- 3 files changed, 213 deletions(-) delete mode 100644 apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss delete mode 100644 apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx delete mode 100644 apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx diff --git a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss deleted file mode 100644 index 944dbcc3b..000000000 --- a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.module.scss +++ /dev/null @@ -1,120 +0,0 @@ -$label-colour: $gray-700; -$active-colour: $gray-500; - -@mixin label { - font-size: $inner-section-text-size; - color: $label-colour; - text-align: center; - align-self: end; -} - -@mixin time { - font-family: 'Open Sans Light', $ontime-font-family; - font-size: 2rem; - text-align: center; -} - -.header { - grid-area: header; - display: grid; - width: 100%; - padding: 0.25rem 1rem; - height: max-content; - column-gap: 2rem; - - grid-template-areas: 'event playback timer clock actions'; - grid-template-columns: 1fr auto auto auto auto; - align-items: center; - justify-items: center; -} - -.event { - grid-area: event; - justify-self: start; - - .title { - font-size: 1.75rem; - } - - .eventNow { - justify-self: start; - font-size: 1.5rem; - } -} - -.playback { - grid-area: playback; - display: flex; - flex-direction: column; - justify-items: center; - align-items: center; - - .playbackLabel { - @include label; - } - - svg { - font-size: 2rem; - height: 3rem; - color: $label-colour; - } -} - -.timer { - grid-area: timer; - - .timerLabel { - @include label; - } - - .value { - @include time; - } -} - -.clock { - grid-area: clock; - - .clockLabel { - @include label; - } - - .value { - grid-area: clock; - @include time; - } -} - -.headerActions { - grid-area: actions; - display: flex; - align-items: center; - gap: 0.5rem; - color: $label-colour; - height: 100%; - font-size: 1rem; - - .actionIcon, - .actionText { - cursor: pointer; - - &.enabled { - color: $active-indicator; - } - - &:hover { - color: $active-colour; - } - } - - .actionIcon { - font-size: 1.25rem; - } -} - -@media (min-width: 1200px) { - // in large screens we want to space the buttons - .headerActions { - padding-left: 10vw; - } -} diff --git a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx deleted file mode 100644 index 94f65896c..000000000 --- a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeader.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Tooltip } from '@chakra-ui/react'; -import { IoLocate } from '@react-icons/all-files/io5/IoLocate'; -import { Playback, ProjectData } from 'ontime-types'; - -import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon'; -import useProjectData from '../../../common/hooks-query/useProjectData'; -import { cx, enDash } from '../../../common/utils/styleUtils'; -import { tooltipDelayFast } from '../../../ontimeConfig'; -import { useCuesheetSettings } from '../store/cuesheetSettingsStore'; - -import CuesheetTableHeaderTimers from './CuesheetTableHeaderTimers'; - -import style from './CuesheetTableHeader.module.scss'; - -interface CuesheetTableHeaderProps { - handleExport: (headerData: ProjectData) => void; - featureData: { - playback: Playback; - selectedEventIndex: number | null; - numEvents: number; - titleNow: string | null; - }; -} - -export default function CuesheetTableHeader({ handleExport, featureData }: CuesheetTableHeaderProps) { - const followSelected = useCuesheetSettings((state) => state.followSelected); - const toggleFollow = useCuesheetSettings((state) => state.toggleFollow); - const { data: project } = useProjectData(); - - const exportProject = () => { - if (project) { - handleExport(project); - } - }; - - const selected = !featureData.numEvents - ? 'No events' - : `Event ${featureData.selectedEventIndex != null ? featureData.selectedEventIndex + 1 : enDash}/${ - featureData.numEvents ? featureData.numEvents : enDash - }`; - - return ( -
    -
    -
    {project?.title || enDash}
    -
    {featureData?.titleNow || enDash}
    -
    -
    -
    {selected}
    - -
    - -
    - - toggleFollow()} - className={cx([style.actionIcon, followSelected ? style.enabled : null])} - > - - - - - - Export CSV - - -
    -
    - ); -} diff --git a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx b/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx deleted file mode 100644 index fdd6e032c..000000000 --- a/apps/client/src/views/cuesheet/cuesheet-table-header/CuesheetTableHeaderTimers.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { useClock, useTimer } from '../../../common/hooks/useSocket'; -import ClockTime from '../../../features/viewers/common/clock-time/ClockTime'; -import RunningTime from '../../../features/viewers/common/running-time/RunningTime'; - -import style from './CuesheetTableHeader.module.scss'; - -export default function CuesheetTableHeaderTimers() { - const { current } = useTimer(); - const { clock } = useClock(); - - return ( - <> -
    -
    Running Timer
    - -
    -
    -
    Time Now
    - -
    - - ); -} From ed65a4db678a56093c3884f1a3525a4a7795992d Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 10:57:11 +0100 Subject: [PATCH 41/47] refactor: smaller settings --- apps/client/src/theme/_ontimeStyles.scss | 1 + .../CuesheetTableSettings.module.scss | 26 ++---- .../CuesheetTableSettings.tsx | 79 +++++-------------- 3 files changed, 27 insertions(+), 79 deletions(-) diff --git a/apps/client/src/theme/_ontimeStyles.scss b/apps/client/src/theme/_ontimeStyles.scss index 5877af849..6af795b74 100644 --- a/apps/client/src/theme/_ontimeStyles.scss +++ b/apps/client/src/theme/_ontimeStyles.scss @@ -57,6 +57,7 @@ $text-body-size: calc(1rem - 1px); // media queries $min-tablet: 500px; +$small-screen: 800px; .blink { animation: blink 1s step-start infinite; diff --git a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss index 1946fd5a4..4afcee79e 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss +++ b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss @@ -1,24 +1,20 @@ .tableSettings { grid-area: settings; - padding: 1rem; - background-color: $ui-black; + padding: 0.5rem 1rem; display: flex; + gap: 5rem; font-size: $inner-section-text-size; -} -.leftPanel { - display: flex; - flex-direction: column; - width: 100%; - gap: 0.5rem; + @media (max-width: $small-screen) { + gap: 1rem; + } } .sectionTitle { - color: $gray-700; text-transform: uppercase; } -.options { +.row { display: flex; flex-wrap: wrap; column-gap: 1rem; @@ -30,12 +26,4 @@ display: flex; align-items: center; gap: 0.5rem; -} - -.rightPanel { - display: flex; - flex-direction: column; - gap: 0.5rem; - - padding-left: 2rem; -} +} \ No newline at end of file diff --git a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx index 290512c19..fd7c04424 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.tsx @@ -1,15 +1,15 @@ import { memo, ReactNode } from 'react'; -import { Button, Checkbox, Switch } from '@chakra-ui/react'; +import { Button, Checkbox } from '@chakra-ui/react'; import { Column } from '@tanstack/react-table'; import { OntimeRundownEntry } from 'ontime-types'; -import { useCuesheetSettings } from '../store/cuesheetSettingsStore'; +import * as Editor from '../../../features/editors/editor-utils/EditorUtils'; import style from './CuesheetTableSettings.module.scss'; // reusable button styles const buttonProps = { - size: 'sm', + size: 'xs', variant: 'ontime-subtle', }; @@ -22,26 +22,12 @@ interface CuesheetTableSettingsProps { function CuesheetTableSettings(props: CuesheetTableSettingsProps) { const { columns, handleResetResizing, handleResetReordering, handleClearToggles } = props; - const { - followSelected, - showIndexColumn, - toggleFollow, - showPrevious, - togglePreviousVisibility, - showDelayBlock, - hideSeconds, - showDelayedTimes, - toggleIndexColumn, - toggleDelayedTimes, - toggleDelayVisibility, - toggleSecondsVisibility, - } = useCuesheetSettings(); return (
    -
    -
    Toggle column visibility
    -
    +
    + Toggle column visibility +
    {columns.map((column) => { const columnHeader = column.columnDef.header; const visible = column.getIsVisible(); @@ -57,47 +43,20 @@ function CuesheetTableSettings(props: CuesheetTableSettingsProps) { ); })}
    -
    Table Options
    -
    - - - -
    -
    Delay Flow
    -
    - - - -
    -
    - - - +
    + Reset Options +
    + + + +
    ); From d8f7d4bba67d333aac5f3804844a6666d2430236 Mon Sep 17 00:00:00 2001 From: asharonbaltazar <58940073+asharonbaltazar@users.noreply.github.com> Date: Sun, 15 Dec 2024 10:40:27 -0500 Subject: [PATCH 42/47] feat(ui): add warning in view params when styles are overriden (#1384) * feat: add warning in view params when styles are overriden * refactor: style tweaks --------- Co-authored-by: Carlos Valente --- .../ViewParamsEditor.module.scss | 19 ++++++++++++++++++- .../view-params-editor/ViewParamsEditor.tsx | 11 +++++++++++ apps/client/src/theme/_ontimeStyles.scss | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.module.scss b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.module.scss index efe885c52..6de2400e0 100644 --- a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.module.scss +++ b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.module.scss @@ -1,6 +1,6 @@ .drawerFooter { display: flex; - justify-content: end; + justify-content: end; gap: $section-spacing; button { @@ -8,6 +8,23 @@ } } +.infoLabel { + display: flex; + align-items: center; + gap: $element-spacing; + padding: 1rem; + margin-bottom: 1rem; + + background-color: $gray-1100; + border-radius: 2px; + font-size: $inner-section-text-size; + + svg { + font-size: 1.5rem; + color: $info-blue; + } +} + .label { font-size: $inner-section-text-size; color: $label-gray; diff --git a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx index d7e0bac5b..65363e08c 100644 --- a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx +++ b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx @@ -11,6 +11,9 @@ import { DrawerOverlay, useDisclosure, } from '@chakra-ui/react'; +import { IoAlertCircle } from '@react-icons/all-files/io5/IoAlertCircle'; + +import useViewSettings from '../../../common/hooks-query/useViewSettings'; import ParamInput from './ParamInput'; import { isSection, ViewOption } from './types'; @@ -87,6 +90,8 @@ interface EditFormDrawerProps { // TODO: this is a good candidate for memoisation, but needs the paramFields to be stable export default function ViewParamsEditor({ viewOptions }: EditFormDrawerProps) { const [searchParams, setSearchParams] = useSearchParams(); + const { data: viewSettings } = useViewSettings(); + const { isOpen, onClose, onOpen } = useDisclosure(); useEffect(() => { @@ -127,6 +132,12 @@ export default function ViewParamsEditor({ viewOptions }: EditFormDrawerProps) { + {viewSettings.overrideStyles && ( +
    + + This view style is being modified by a custom CSS file.
    +
    + )}
    {viewOptions.map((option) => { if (isSection(option)) { diff --git a/apps/client/src/theme/_ontimeStyles.scss b/apps/client/src/theme/_ontimeStyles.scss index 6af795b74..46cb5962b 100644 --- a/apps/client/src/theme/_ontimeStyles.scss +++ b/apps/client/src/theme/_ontimeStyles.scss @@ -12,6 +12,7 @@ $action-text-color: $blue-400; $ontime-color: #ff7597; $error-red: $red-500; $warning-orange: $orange-500; +$info-blue: $blue-500; $opacity-disabled: 0.4; $active-red: $red-700; From b048d0f88d1f4a2b5f16b0665c78049361476719 Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Mon, 16 Dec 2024 14:27:25 +0100 Subject: [PATCH 43/47] Edit in cuesheet (#1372) * pass on all event edits * MakePublic * trim value in cell * edit notes * title * add key check * don't log error Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> * checkbox * refactor * remove log * fix test * use row number to test value --------- Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> --- apps/client/src/theme/ontimeTextInputs.ts | 10 +++ apps/client/src/theme/theme.ts | 2 + apps/client/src/views/cuesheet/Cuesheet.tsx | 22 +++++- .../src/views/cuesheet/CuesheetPage.tsx | 60 ++++++++------ .../cuesheet-table-elements/EditableCell.tsx | 55 ------------- .../cuesheet-table-elements/MultiLineCell.tsx | 37 +++++++++ .../SingleLineCell.tsx | 35 ++++++++ .../src/views/cuesheet/cuesheetCols.tsx | 79 ++++++++++++++++--- e2e/tests/features/202-cuesheet.spec.ts | 21 +++-- 9 files changed, 223 insertions(+), 98 deletions(-) delete mode 100644 apps/client/src/views/cuesheet/cuesheet-table-elements/EditableCell.tsx create mode 100644 apps/client/src/views/cuesheet/cuesheet-table-elements/MultiLineCell.tsx create mode 100644 apps/client/src/views/cuesheet/cuesheet-table-elements/SingleLineCell.tsx diff --git a/apps/client/src/theme/ontimeTextInputs.ts b/apps/client/src/theme/ontimeTextInputs.ts index 0547b58db..ec96e7fba 100644 --- a/apps/client/src/theme/ontimeTextInputs.ts +++ b/apps/client/src/theme/ontimeTextInputs.ts @@ -38,6 +38,16 @@ export const ontimeInputGhosted = { }, }; +export const ontimeInputTransparent = { + field: { + ...commonStyles, + backgroundColor: 'transparent', + _hover: { + backgroundColor: 'rgba(255, 255, 255, 0.10)', // $white-10 + }, + }, +}; + export const ontimeTextAreaFilled = { ...commonStyles, }; diff --git a/apps/client/src/theme/theme.ts b/apps/client/src/theme/theme.ts index ee6b00e46..ff68d5177 100644 --- a/apps/client/src/theme/theme.ts +++ b/apps/client/src/theme/theme.ts @@ -21,6 +21,7 @@ import { ontimeTab } from './ontimeTab'; import { ontimeInputFilled, ontimeInputGhosted, + ontimeInputTransparent, ontimeTextAreaFilled, ontimeTextAreaTransparent, } from './ontimeTextInputs'; @@ -78,6 +79,7 @@ const theme = extendTheme({ variants: { 'ontime-filled': { ...ontimeInputFilled }, 'ontime-ghosted': { ...ontimeInputGhosted }, + 'ontime-transparent': { ...ontimeInputTransparent }, }, }, Kbd: { diff --git a/apps/client/src/views/cuesheet/Cuesheet.tsx b/apps/client/src/views/cuesheet/Cuesheet.tsx index 7c4eb412e..a77c36da3 100644 --- a/apps/client/src/views/cuesheet/Cuesheet.tsx +++ b/apps/client/src/views/cuesheet/Cuesheet.tsx @@ -1,7 +1,14 @@ import { useCallback, useRef } from 'react'; import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import Color from 'color'; -import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types'; +import { + CustomFieldLabel, + isOntimeBlock, + isOntimeDelay, + isOntimeEvent, + OntimeRundown, + OntimeRundownEntry, +} from 'ontime-types'; import useFollowComponent from '../../common/hooks/useFollowComponent'; import { getAccessibleColour } from '../../common/utils/styleUtils'; @@ -19,12 +26,20 @@ import style from './Cuesheet.module.scss'; interface CuesheetProps { data: OntimeRundown; columns: ColumnDef[]; - handleUpdate: (rowIndex: number, accessor: keyof OntimeRundownEntry, payload: unknown) => void; + handleUpdate: (rowIndex: number, accessor: keyof OntimeRundownEntry, payload: string) => void; + handleUpdateCustom: (rowIndex: number, accessor: CustomFieldLabel, payload: string) => void; selectedId: string | null; currentBlockId: string | null; } -export default function Cuesheet({ data, columns, handleUpdate, selectedId, currentBlockId }: CuesheetProps) { +export default function Cuesheet({ + data, + columns, + handleUpdate, + handleUpdateCustom, + selectedId, + currentBlockId, +}: CuesheetProps) { const { followSelected, showSettings, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings(); const { columnVisibility, @@ -51,6 +66,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId, curr }, meta: { handleUpdate, + handleUpdateCustom, }, onColumnVisibilityChange: setColumnVisibility, onColumnSizingChange: setColumnSizing, diff --git a/apps/client/src/views/cuesheet/CuesheetPage.tsx b/apps/client/src/views/cuesheet/CuesheetPage.tsx index df49c8499..2ab1ccff6 100644 --- a/apps/client/src/views/cuesheet/CuesheetPage.tsx +++ b/apps/client/src/views/cuesheet/CuesheetPage.tsx @@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react'; import { IconButton, useDisclosure } from '@chakra-ui/react'; import { IoApps } from '@react-icons/all-files/io5/IoApps'; import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline'; -import { CustomFieldLabel, isOntimeEvent } from 'ontime-types'; +import { CustomFieldLabel, isOntimeEvent, OntimeEvent } from 'ontime-types'; import ProductionNavigationMenu from '../../common/components/navigation-menu/ProductionNavigationMenu'; import EmptyPage from '../../common/components/state/EmptyPage'; @@ -26,7 +26,7 @@ export default function CuesheetPage() { const { data: customFields } = useCustomFields(); const { isOpen: isMenuOpen, onOpen, onClose } = useDisclosure(); - const { updateCustomField } = useEventAction(); + const { updateCustomField, updateEvent } = useEventAction(); const featureData = useCuesheet(); const columns = useMemo(() => makeCuesheetColumns(customFields), [customFields]); const toggleSettings = useCuesheetSettings((state) => state.toggleSettings); @@ -34,11 +34,10 @@ export default function CuesheetPage() { useWindowTitle('Cuesheet'); /** - * Handles updating a field - * Currently, only custom fields can be updated from the cuesheet + * Handles updating a custom field */ - const handleUpdate = useCallback( - async (rowIndex: number, accessor: CustomFieldLabel, payload: unknown) => { + const handleUpdateCustom = useCallback( + async (rowIndex: number, accessor: CustomFieldLabel, payload: string) => { if (!flatRundown || rundownStatus !== 'success') { return; } @@ -53,29 +52,44 @@ export default function CuesheetPage() { return; } + // skip if there is no value change const previousValue = event.custom[accessor]; + if (previousValue === payload) { + return; + } + updateCustomField(event.id, accessor, payload); + }, + [flatRundown, rundownStatus, updateCustomField], + ); + /** + * Handles updating all other string fields + */ + const handleUpdate = useCallback( + async (rowIndex: number, accessor: keyof OntimeEvent, payload: string) => { + if (!flatRundown || rundownStatus !== 'success') { + return; + } + + if (rowIndex == null || accessor == null || payload == null) { + return; + } + + // check if value is the same + const event = flatRundown[rowIndex]; + if (!event || !isOntimeEvent(event)) { + return; + } + + // skip if there is no value change + const previousValue = event[accessor]; if (previousValue === payload) { return; } - // check if value is valid - // in anticipation to different types of event here - if (typeof payload !== 'string') { - return; - } - - // cleanup - const cleanVal = payload.trim(); - - // submit - try { - await updateCustomField(event.id, accessor, cleanVal); - } catch (error) { - console.error(error); - } + updateEvent({ id: event.id, [accessor]: payload }); }, - [flatRundown, rundownStatus, updateCustomField], + [flatRundown, rundownStatus, updateEvent], ); if (!customFields || !flatRundown || rundownStatus !== 'success') { @@ -106,6 +120,8 @@ export default function CuesheetPage() { data={flatRundown} columns={columns} handleUpdate={handleUpdate} + handleUpdateCustom={handleUpdateCustom} + //TODO: stabilizer selectedEventId and currentBlockId selectedId={featureData.selectedEventId} currentBlockId={featureData.currentBlockId} /> diff --git a/apps/client/src/views/cuesheet/cuesheet-table-elements/EditableCell.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/EditableCell.tsx deleted file mode 100644 index 301b60f4b..000000000 --- a/apps/client/src/views/cuesheet/cuesheet-table-elements/EditableCell.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { ChangeEvent, memo, useCallback, useEffect, useRef, useState } from 'react'; -import { getHotkeyHandler } from '@mantine/hooks'; - -import { AutoTextArea } from '../../../common/components/input/auto-text-area/AutoTextArea'; - -interface EditableCellProps { - value: string; - handleUpdate: (newValue: string) => void; -} - -const EditableCell = (props: EditableCellProps) => { - const { value: initialValue, handleUpdate } = props; - - // We need to keep and update the state of the cell normally - const [value, setValue] = useState(initialValue); - const ref = useRef(); - const onChange = useCallback((event: ChangeEvent) => setValue(event.target.value), []); - - // We'll only update the external data when the input is blurred - const onBlur = useCallback(() => handleUpdate(value), [handleUpdate, value]); - - //TODO: maybe we can unify this with `useReactiveTextInput` - const onKeyDown = getHotkeyHandler([ - ['mod + Enter', () => ref.current?.blur()], - [ - 'Escape', - () => { - setValue(initialValue); - setTimeout(() => ref.current?.blur()); - }, - ], - ]); - - // If the initialValue is changed external, sync it up with our state - useEffect(() => { - setValue(initialValue); - }, [initialValue]); - - return ( - - ); -}; - -export default memo(EditableCell); diff --git a/apps/client/src/views/cuesheet/cuesheet-table-elements/MultiLineCell.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/MultiLineCell.tsx new file mode 100644 index 000000000..9fa159863 --- /dev/null +++ b/apps/client/src/views/cuesheet/cuesheet-table-elements/MultiLineCell.tsx @@ -0,0 +1,37 @@ +import { memo, useCallback, useRef } from 'react'; + +import { AutoTextArea } from '../../../common/components/input/auto-text-area/AutoTextArea'; +import useReactiveTextInput from '../../../common/components/input/text-input/useReactiveTextInput'; + +interface MultiLineCellProps { + initialValue: string; + handleUpdate: (newValue: string) => void; +} + +const MultiLineCell = (props: MultiLineCellProps) => { + const { initialValue, handleUpdate } = props; + const ref = useRef(null); + const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]); + + const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, { + submitOnCtrlEnter: true, + }); + + return ( + + ); +}; + +export default memo(MultiLineCell); diff --git a/apps/client/src/views/cuesheet/cuesheet-table-elements/SingleLineCell.tsx b/apps/client/src/views/cuesheet/cuesheet-table-elements/SingleLineCell.tsx new file mode 100644 index 000000000..329d8a4f9 --- /dev/null +++ b/apps/client/src/views/cuesheet/cuesheet-table-elements/SingleLineCell.tsx @@ -0,0 +1,35 @@ +import { memo, useCallback, useRef } from 'react'; +import { Input } from '@chakra-ui/react'; + +import useReactiveTextInput from '../../../common/components/input/text-input/useReactiveTextInput'; + +interface SingleLineCellProps { + initialValue: string; + handleUpdate: (newValue: string) => void; +} + +const SingleLineCell = (props: SingleLineCellProps) => { + const { initialValue, handleUpdate } = props; + const ref = useRef(null); + const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]); + + const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, { + submitOnCtrlEnter: true, + }); + + return ( + + ); +}; + +export default memo(SingleLineCell); diff --git a/apps/client/src/views/cuesheet/cuesheetCols.tsx b/apps/client/src/views/cuesheet/cuesheetCols.tsx index 42b91ddc0..460d7061d 100644 --- a/apps/client/src/views/cuesheet/cuesheetCols.tsx +++ b/apps/client/src/views/cuesheet/cuesheetCols.tsx @@ -1,19 +1,37 @@ import { useCallback } from 'react'; -import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark'; +import { Checkbox } from '@chakra-ui/react'; import { CellContext, ColumnDef } from '@tanstack/react-table'; import { CustomFields, isOntimeEvent, OntimeEvent, OntimeRundownEntry } from 'ontime-types'; import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator'; import RunningTime from '../../features/viewers/common/running-time/RunningTime'; -import EditableCell from './cuesheet-table-elements/EditableCell'; +import MultiLineCell from './cuesheet-table-elements/MultiLineCell'; +import SingleLineCell from './cuesheet-table-elements/SingleLineCell'; import { useCuesheetSettings } from './store/cuesheetSettingsStore'; import style from './Cuesheet.module.scss'; -function makePublic(row: CellContext) { - const cellValue = row.getValue(); - return cellValue ? : ''; +function MakePublic({ row, column, table }: CellContext) { + const update = useCallback( + (event: React.ChangeEvent) => { + // @ts-expect-error -- we inject this into react-table + table.options.meta?.handleUpdate(row.index, column.id, event.target.checked); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable + [column.id, row.index], + ); + + const event = row.original; + if (!isOntimeEvent(event)) { + return null; + } + + const isChecked = event.isPublic; + + return ( + + ); } function MakeTimer({ getValue, row: { original } }: CellContext) { @@ -40,7 +58,7 @@ function MakeDuration({ getValue }: CellContext) { return ; } -function MakeCustomField({ row, column, table }: CellContext) { +function MakeMultiLineField({ row, column, table }: CellContext) { const update = useCallback( (newValue: string) => { // @ts-expect-error -- we inject this into react-table @@ -55,10 +73,49 @@ function MakeCustomField({ row, column, table }: CellContext; +} + +function MakeSingleLineField({ row, column, table }: CellContext) { + const update = useCallback( + (newValue: string) => { + // @ts-expect-error -- we inject this into react-table + table.options.meta?.handleUpdate(row.index, column.id, newValue); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable + [column.id, row.index], + ); + + const event = row.original; + if (!isOntimeEvent(event)) { + return null; + } + + const initialValue = event[column.id as keyof OntimeRundownEntry] ?? ''; + + return ; +} + +function MakeCustomField({ row, column, table }: CellContext) { + const update = useCallback( + (newValue: string) => { + // @ts-expect-error -- we inject this into react-table + table.options.meta?.handleUpdateCustom(row.index, column.id, newValue); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- we skip table.options.meta since the reference seems unstable + [column.id, row.index], + ); + + const event = row.original; + if (!isOntimeEvent(event)) { + return null; + } + const initialValue = event.custom[column.id] ?? ''; - return ; + return ; } export function makeCuesheetColumns(customFields: CustomFields): ColumnDef[] { @@ -83,7 +140,7 @@ export function makeCuesheetColumns(customFields: CustomFields): ColumnDef row.getValue(), + cell: MakeSingleLineField, size: 250, }, { accessorKey: 'note', id: 'note', header: 'Note', - cell: (row) => row.getValue(), + cell: MakeMultiLineField, size: 250, }, ...dynamicCustomFields, diff --git a/e2e/tests/features/202-cuesheet.spec.ts b/e2e/tests/features/202-cuesheet.spec.ts index c4f23e4f9..df98815e7 100644 --- a/e2e/tests/features/202-cuesheet.spec.ts +++ b/e2e/tests/features/202-cuesheet.spec.ts @@ -1,11 +1,18 @@ -import { test } from '@playwright/test'; +import { expect, test } from '@playwright/test'; -test('cuesheet displays events and exports csv', async ({ page }) => { +test('cuesheet displays events', async ({ page }) => { // same elements in cuesheet await page.goto('http://localhost:4001/cuesheet'); - await page.getByText('Eurovision Song Contest').click(); - await page.getByRole('cell', { name: 'Lunch break' }).click(); - await page.getByRole('cell', { name: 'Albania' }).click(); - await page.getByRole('cell', { name: 'Latvia' }).click(); - await page.getByRole('cell', { name: 'Lithuania' }).click(); + await expect(page.getByText('Eurovision Song Contest')).toBeVisible(); + await expect(page.getByRole('row', { name: 'Lunch break' })).toBeVisible(); + + await expect(page.locator('tr:nth-child(1) > td:nth-child(7)').first().getByRole('textbox').first()).toHaveValue( + 'Albania', + ); + await expect(page.locator('tr:nth-child(2) > td:nth-child(7)').first().getByRole('textbox').first()).toHaveValue( + 'Latvia', + ); + await expect(page.locator('tr:nth-child(3) > td:nth-child(7)').first().getByRole('textbox').first()).toHaveValue( + 'Lithuania', + ); }); From 97208c052a7f2406905c9c198a50cf08dde95367 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 11:05:57 +0100 Subject: [PATCH 44/47] chore: upgrade dependencies --- apps/client/package.json | 10 +-- pnpm-lock.yaml | 167 ++++++++++++++++----------------------- 2 files changed, 74 insertions(+), 103 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index 2b3a49cc1..f982ecb37 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -13,10 +13,10 @@ "@fontsource/open-sans": "^5.0.28", "@mantine/hooks": "^7.13.3", "@react-icons/all-files": "^4.1.0", - "@sentry/react": "^8.19.0", - "@tanstack/react-query": "^5.17.9", - "@tanstack/react-query-devtools": "^5.17.9", - "@tanstack/react-table": "^8.11.3", + "@sentry/react": "^8.43.0", + "@tanstack/react-query": "^5.62.7", + "@tanstack/react-query-devtools": "^5.62.7", + "@tanstack/react-table": "^8.20.5", "autosize": "^6.0.1", "axios": "^1.2.0", "color": "^4.2.3", @@ -92,4 +92,4 @@ "vite-tsconfig-paths": "^4.3.1", "vitest": "catalog:" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c02c776de..f63ea2b2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,17 +114,17 @@ importers: specifier: ^4.1.0 version: 4.1.0(react@18.3.1) '@sentry/react': - specifier: ^8.19.0 - version: 8.19.0(react@18.3.1) + specifier: ^8.43.0 + version: 8.45.0(react@18.3.1) '@tanstack/react-query': - specifier: ^5.17.9 - version: 5.17.9(react@18.3.1) + specifier: ^5.62.7 + version: 5.62.7(react@18.3.1) '@tanstack/react-query-devtools': - specifier: ^5.17.9 - version: 5.17.9(@tanstack/react-query@5.17.9(react@18.3.1))(react@18.3.1) + specifier: ^5.62.7 + version: 5.62.7(@tanstack/react-query@5.62.7(react@18.3.1))(react@18.3.1) '@tanstack/react-table': - specifier: ^8.11.3 - version: 8.11.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^8.20.5 + version: 8.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) autosize: specifier: ^6.0.1 version: 6.0.1 @@ -1815,28 +1815,28 @@ packages: cpu: [x64] os: [win32] - '@sentry-internal/browser-utils@8.19.0': - resolution: {integrity: sha512-kM/2KlikKuBR63nFi2q7MGS3V9K9hakjvUknhr/jHZqDVfEuBKmp1ZlHFAdJtglKHHJy07gPj/XqDH7BbYh5yg==} + '@sentry-internal/browser-utils@8.45.0': + resolution: {integrity: sha512-MX/E/C+W5I9jkGD1PsbZ2hpCc7YuizNKmEbuGPxQPfUSIPrdE2wpo6ZfIhEbxq9m/trl1oRCN4PXi3BB7dlYYg==} engines: {node: '>=14.18'} - '@sentry-internal/feedback@8.19.0': - resolution: {integrity: sha512-Jc77H8fEaGcBhERc2U/o7Q8CZHvlZLT9vAlzq0ZZR20v/1vwYcJW1ysKfTuvmw22hCR6ukhFNl6pqJocXFVhvA==} + '@sentry-internal/feedback@8.45.0': + resolution: {integrity: sha512-WerpfkKrKPAlnQuqjEgKXZtrx68cla7GyOkNOeL40JQbY4/By4Qjx1atUOmgk/FdjrCLPw+jQQY9pXRpMRqqRw==} engines: {node: '>=14.18'} - '@sentry-internal/replay-canvas@8.19.0': - resolution: {integrity: sha512-l4pKJDHrXEctxrK7Xme/+fKToXpGwr/G2t77BzeE1WEw9LwSwADz/hi8HoMdZzuKWriM2BNbz20tpVS84sODxA==} + '@sentry-internal/replay-canvas@8.45.0': + resolution: {integrity: sha512-LZ8kBuzO5gutDiWnCyYEzBMDLq9PIllcsWsXRpKoau0Zqs3DbyRolI11dNnxmUSh7UW21FksxBpqn5yPmUMbag==} engines: {node: '>=14.18'} - '@sentry-internal/replay@8.19.0': - resolution: {integrity: sha512-EW9e1J6XbqXUXQST1AfSIzT9O8OwPyeFOkhkn9/gqOQv08TJvQEIBtWJEoJS+XFMEUuB8IqIzVWNVko/DnGt9A==} + '@sentry-internal/replay@8.45.0': + resolution: {integrity: sha512-SOFwFpzx0B6lxhLl2hBnxvybo7gdB5TMY8dOHMwXgk5A2+BXvSpvWXnr33yqUlBmC8R3LeFTB3C0plzM5lhkJg==} engines: {node: '>=14.18'} '@sentry/babel-plugin-component-annotate@2.16.1': resolution: {integrity: sha512-pJka66URsqQbk6hTs9H1XFpUeI0xxuqLYf9Dy5pRGNHSJMtfv91U+CaYSWt03aRRMGDXMduh62zAAY7Wf0HO+A==} engines: {node: '>= 14'} - '@sentry/browser@8.19.0': - resolution: {integrity: sha512-ZC1HxIFm4TIGONyy9MkPG6Dw8IAhzq43t5mq9PqrB1ehuWj8GX6Vk3E26kuc2sydAm4AXbj0562OmvZHsAJpUA==} + '@sentry/browser@8.45.0': + resolution: {integrity: sha512-Y+BcfpXY1eEkOYOzgLGkx1YH940uMAymYOxfSZSvC+Vx6xHuaGT05mIFef/aeZbyu2AUs6JjdvD1BRBZlHg78w==} engines: {node: '>=14.18'} '@sentry/bundler-plugin-core@2.16.1': @@ -1889,24 +1889,16 @@ packages: engines: {node: '>= 10'} hasBin: true - '@sentry/core@8.19.0': - resolution: {integrity: sha512-MrgjsZCEjOJgQjIznnDSrLEy7qL+4LVpNieAvr49cV1rzBNSwGmWRnt/puVaPsLyCUgupVx/43BPUHB/HtKNUw==} + '@sentry/core@8.45.0': + resolution: {integrity: sha512-4YTuBipWSh4JrtSYS5GxUQBAcAgOIkEoFfFbwVcr3ivijOacJLRXTBn3rpcy1CKjBq0PHDGR+2RGRYC+bNAMxg==} engines: {node: '>=14.18'} - '@sentry/react@8.19.0': - resolution: {integrity: sha512-MzuMy4AEdSuIrBEyp3W7c4+v215+2MiU9ba7Y0KBKcC/Nrf1cGfRFRbjl9OYm/JIuxkaop7kgYs6sPMrVJVlrQ==} + '@sentry/react@8.45.0': + resolution: {integrity: sha512-xuJBDATJKAHOxpR5IBfGFWJxXb05GMPGGpk8UoWai1Mh50laAQ0/WW+5sDAKrCjXoA+JZ6fb3DP8EE2X93n1nw==} engines: {node: '>=14.18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - '@sentry/types@8.19.0': - resolution: {integrity: sha512-52C8X5V7mK2KIxMJt8MV5TxXAFHqrQR1RKm1oPTwKVWm8hKr1ZYJXINymNrWvpAc3oVIKLC/sa9WFYgXQh+YlA==} - engines: {node: '>=14.18'} - - '@sentry/utils@8.19.0': - resolution: {integrity: sha512-8dWJJKaUN6Hf92Oxw2TBmHchGua2W3ZmonrZTTwLvl06jcAigbiQD0MGuF5ytZP8PHx860orV+SbTGKFzfU3Pg==} - engines: {node: '>=14.18'} - '@sentry/vite-plugin@2.16.1': resolution: {integrity: sha512-RSIyeqFG3PR5iJsZnagQxzOhM22z1Kh9DG+HQQsfVrxokzrWKRu/G17O2MIDh2I5iYEaL0Fkd/9RAXE4/b0aVg==} engines: {node: '>= 14'} @@ -2012,32 +2004,32 @@ packages: peerDependencies: eslint: ^8.0.0 - '@tanstack/query-core@5.17.9': - resolution: {integrity: sha512-8xcvpWIPaRMDNLMvG9ugcUJMgFK316ZsqkPPbsI+TMZsb10N9jk0B6XgPk4/kgWC2ziHyWR7n7wUhxmD0pChQw==} + '@tanstack/query-core@5.62.7': + resolution: {integrity: sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==} - '@tanstack/query-devtools@5.17.7': - resolution: {integrity: sha512-TfgvOqza5K7Sk6slxqkRIvXlEJoUoPSsGGwpuYSrpqgSwLSSvPPpZhq7hv7hcY5IvRoTNGoq6+MT01C/jILqoQ==} + '@tanstack/query-devtools@5.61.4': + resolution: {integrity: sha512-21Tw+u8E3IJJj4A/Bct4H0uBaDTEu7zBrR79FeSyY+mS2gx5/m316oDtJiKkILc819VSTYt+sFzODoJNcpPqZQ==} - '@tanstack/react-query-devtools@5.17.9': - resolution: {integrity: sha512-1viWP/jlO0LaeCdtTFqtF1k2RfM3KVpvwVffWv+PMNkS2u4s8YGUM17r3p82udbF9BY1mE7aHqQ3MM1errF5lQ==} + '@tanstack/react-query-devtools@5.62.7': + resolution: {integrity: sha512-wxXsdTZJRs//hMtJMU5aNlUaTclRFPqLvDNeWbRj8YpGD3aoo4zyu53W55W2DY16+ycg3fti21uCW4N9oyj91w==} peerDependencies: - '@tanstack/react-query': ^5.17.9 - react: ^18.0.0 + '@tanstack/react-query': ^5.62.7 + react: ^18 || ^19 - '@tanstack/react-query@5.17.9': - resolution: {integrity: sha512-M5E9gwUq1Stby/pdlYjBlL24euIVuGbWKIFCbtnQxSdXI4PgzjTSdXdV3QE6fc+itF+TUvX/JPTKIwq8yuBXcg==} + '@tanstack/react-query@5.62.7': + resolution: {integrity: sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==} peerDependencies: - react: ^18.0.0 + react: ^18 || ^19 - '@tanstack/react-table@8.11.3': - resolution: {integrity: sha512-Gwwm7po1MaObBguw69L+UiACkaj+eOtThQEArj/3fmUwMPiWaJcXvNG2X5Te5z2hg0HMx8h0T0Q7p5YmQlTUfw==} + '@tanstack/react-table@8.20.6': + resolution: {integrity: sha512-w0jluT718MrOKthRcr2xsjqzx+oEM7B7s/XXyfs19ll++hlId3fjTm+B2zrR3ijpANpkzBAr15j1XGVOMxpggQ==} engines: {node: '>=12'} peerDependencies: - react: '>=16' - react-dom: '>=16' + react: '>=16.8' + react-dom: '>=16.8' - '@tanstack/table-core@8.11.3': - resolution: {integrity: sha512-nkcFIL696wTf1QMvhGR7dEg60OIRwEZm1OqFTYYDTRc4JOWspgrsJO3IennsOJ7ptumHWLDjV8e5BjPkZcSZAQ==} + '@tanstack/table-core@8.20.5': + resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==} engines: {node: '>=12'} '@testing-library/dom@10.1.0': @@ -6830,43 +6822,33 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.17.2': optional: true - '@sentry-internal/browser-utils@8.19.0': + '@sentry-internal/browser-utils@8.45.0': dependencies: - '@sentry/core': 8.19.0 - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry/core': 8.45.0 - '@sentry-internal/feedback@8.19.0': + '@sentry-internal/feedback@8.45.0': dependencies: - '@sentry/core': 8.19.0 - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry/core': 8.45.0 - '@sentry-internal/replay-canvas@8.19.0': + '@sentry-internal/replay-canvas@8.45.0': dependencies: - '@sentry-internal/replay': 8.19.0 - '@sentry/core': 8.19.0 - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry-internal/replay': 8.45.0 + '@sentry/core': 8.45.0 - '@sentry-internal/replay@8.19.0': + '@sentry-internal/replay@8.45.0': dependencies: - '@sentry-internal/browser-utils': 8.19.0 - '@sentry/core': 8.19.0 - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry-internal/browser-utils': 8.45.0 + '@sentry/core': 8.45.0 '@sentry/babel-plugin-component-annotate@2.16.1': {} - '@sentry/browser@8.19.0': + '@sentry/browser@8.45.0': dependencies: - '@sentry-internal/browser-utils': 8.19.0 - '@sentry-internal/feedback': 8.19.0 - '@sentry-internal/replay': 8.19.0 - '@sentry-internal/replay-canvas': 8.19.0 - '@sentry/core': 8.19.0 - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry-internal/browser-utils': 8.45.0 + '@sentry-internal/feedback': 8.45.0 + '@sentry-internal/replay': 8.45.0 + '@sentry-internal/replay-canvas': 8.45.0 + '@sentry/core': 8.45.0 '@sentry/bundler-plugin-core@2.16.1': dependencies: @@ -6922,26 +6904,15 @@ snapshots: - encoding - supports-color - '@sentry/core@8.19.0': - dependencies: - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry/core@8.45.0': {} - '@sentry/react@8.19.0(react@18.3.1)': + '@sentry/react@8.45.0(react@18.3.1)': dependencies: - '@sentry/browser': 8.19.0 - '@sentry/core': 8.19.0 - '@sentry/types': 8.19.0 - '@sentry/utils': 8.19.0 + '@sentry/browser': 8.45.0 + '@sentry/core': 8.45.0 hoist-non-react-statics: 3.3.2 react: 18.3.1 - '@sentry/types@8.19.0': {} - - '@sentry/utils@8.19.0': - dependencies: - '@sentry/types': 8.19.0 - '@sentry/vite-plugin@2.16.1': dependencies: '@sentry/bundler-plugin-core': 2.16.1 @@ -7050,28 +7021,28 @@ snapshots: - supports-color - typescript - '@tanstack/query-core@5.17.9': {} + '@tanstack/query-core@5.62.7': {} - '@tanstack/query-devtools@5.17.7': {} + '@tanstack/query-devtools@5.61.4': {} - '@tanstack/react-query-devtools@5.17.9(@tanstack/react-query@5.17.9(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query-devtools@5.62.7(@tanstack/react-query@5.62.7(react@18.3.1))(react@18.3.1)': dependencies: - '@tanstack/query-devtools': 5.17.7 - '@tanstack/react-query': 5.17.9(react@18.3.1) + '@tanstack/query-devtools': 5.61.4 + '@tanstack/react-query': 5.62.7(react@18.3.1) react: 18.3.1 - '@tanstack/react-query@5.17.9(react@18.3.1)': + '@tanstack/react-query@5.62.7(react@18.3.1)': dependencies: - '@tanstack/query-core': 5.17.9 + '@tanstack/query-core': 5.62.7 react: 18.3.1 - '@tanstack/react-table@8.11.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-table@8.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tanstack/table-core': 8.11.3 + '@tanstack/table-core': 8.20.5 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@tanstack/table-core@8.11.3': {} + '@tanstack/table-core@8.20.5': {} '@testing-library/dom@10.1.0': dependencies: From bedab221d939d4971173f5429bb01b58143cca1a Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 11:09:44 +0100 Subject: [PATCH 45/47] chore: dedupe lock file --- pnpm-lock.yaml | 659 +++++++------------------------------------------ 1 file changed, 84 insertions(+), 575 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f63ea2b2c..4d5abd9b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,7 +130,7 @@ importers: version: 6.0.1 axios: specifier: ^1.2.0 - version: 1.2.2 + version: 1.7.2 color: specifier: ^4.2.3 version: 4.2.3 @@ -293,7 +293,7 @@ importers: version: 2.8.5 dotenv: specifier: ^16.0.1 - version: 16.0.3 + version: 16.3.1 express: specifier: ^4.18.2 version: 4.18.2 @@ -469,14 +469,6 @@ packages: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} - '@babel/code-frame@7.18.6': - resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} - engines: {node: '>=6.9.0'} - - '@babel/code-frame@7.23.5': - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.24.2': resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} engines: {node: '>=6.9.0'} @@ -509,10 +501,6 @@ packages: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.18.6': - resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.22.15': resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} @@ -539,10 +527,6 @@ packages: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.20': - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.5': resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} engines: {node: '>=6.9.0'} @@ -555,10 +539,6 @@ packages: resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.23.4': - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.5': resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} engines: {node: '>=6.9.0'} @@ -580,18 +560,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.20.7': - resolution: {integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==} - engines: {node: '>=6.9.0'} - - '@babel/runtime@7.21.0': - resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==} - engines: {node: '>=6.9.0'} - - '@babel/runtime@7.22.5': - resolution: {integrity: sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.24.5': resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} engines: {node: '>=6.9.0'} @@ -1671,9 +1639,6 @@ packages: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -2061,9 +2026,6 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@types/aria-query@5.0.1': - resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==} - '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -2235,18 +2197,10 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@5.48.1': - resolution: {integrity: sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@5.62.0': resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@6.21.0': - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} - engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.16.1': resolution: {integrity: sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2261,31 +2215,14 @@ packages: typescript: optional: true - '@typescript-eslint/types@5.48.1': - resolution: {integrity: sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@5.62.0': resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@6.21.0': - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} - engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.16.1': resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/typescript-estree@5.48.1': - resolution: {integrity: sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/typescript-estree@5.62.0': resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2295,15 +2232,6 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@6.21.0': - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/typescript-estree@7.16.1': resolution: {integrity: sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2313,42 +2241,22 @@ packages: typescript: optional: true - '@typescript-eslint/utils@5.48.1': - resolution: {integrity: sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@5.62.0': resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@6.21.0': - resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@7.16.1': resolution: {integrity: sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/visitor-keys@5.48.1': - resolution: {integrity: sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@5.62.0': resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@6.21.0': - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} - engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@7.16.1': resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2498,9 +2406,6 @@ packages: resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} engines: {node: '>=10'} - aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} - aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -2555,9 +2460,6 @@ packages: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - axios@1.2.2: - resolution: {integrity: sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==} - axios@1.7.2: resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==} @@ -2596,6 +2498,7 @@ packages: boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -2712,10 +2615,6 @@ packages: chromium-pickle-js@0.2.0: resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} - ci-info@3.7.1: - resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==} - engines: {node: '>=8'} - ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -2791,10 +2690,6 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} - content-type@1.0.4: - resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} - engines: {node: '>= 0.6'} - content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -2875,9 +2770,6 @@ packages: resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} engines: {node: '>=8'} - csstype@3.1.1: - resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} - csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -2896,15 +2788,6 @@ packages: supports-color: optional: true - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -2925,9 +2808,6 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deep-equal@2.2.0: - resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -2943,10 +2823,6 @@ packages: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} engines: {node: '>= 0.4'} - define-properties@1.1.4: - resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} - engines: {node: '>= 0.4'} - define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -3001,9 +2877,6 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - dom-accessibility-api@0.5.15: - resolution: {integrity: sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw==} - dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -3018,10 +2891,6 @@ packages: dotenv-expand@5.1.0: resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} - dotenv@16.0.3: - resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} - engines: {node: '>=12'} - dotenv@16.3.1: resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} engines: {node: '>=12'} @@ -3088,9 +2957,6 @@ packages: resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} engines: {node: '>= 0.4'} - es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - es-module-lexer@1.5.4: resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} @@ -3221,16 +3087,6 @@ packages: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-utils@3.0.0: - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - - eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3238,6 +3094,7 @@ packages: eslint@8.56.0: resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -3369,15 +3226,6 @@ packages: resolution: {integrity: sha512-KSuV3ur4gf2KqMNoZx3nXNVhqCkn42GuTYCX4tXPEwf0MjpFQmNMiN6m7dXaUXgIoivL6/65agoUMg4RLS0Vbg==} engines: {node: '>=10'} - follow-redirects@1.15.2: - resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} @@ -3482,9 +3330,6 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-intrinsic@1.1.3: - resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} - get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} @@ -3688,6 +3533,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3707,10 +3553,6 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} - engines: {node: '>= 0.4'} - is-array-buffer@3.0.1: resolution: {integrity: sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==} @@ -3758,9 +3600,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} - is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -3784,9 +3623,6 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} - is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} - is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} @@ -3806,21 +3642,12 @@ packages: resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} engines: {node: '>= 0.4'} - is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} - is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isbinaryfile@4.0.10: resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} engines: {node: '>= 8.0.0'} @@ -4002,10 +3829,6 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - lz-string@1.4.4: - resolution: {integrity: sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==} - hasBin: true - lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -4085,17 +3908,10 @@ packages: resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.4: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.7: - resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4131,9 +3947,6 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -4202,10 +4015,6 @@ packages: object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - object-is@1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} - engines: {node: '>= 0.4'} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -4319,9 +4128,6 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} @@ -4368,10 +4174,6 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-format@29.3.1: - resolution: {integrity: sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4542,9 +4344,6 @@ packages: resolution: {integrity: sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==} engines: {node: '>=12.0.0'} - readable-stream@2.3.7: - resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -4567,9 +4366,6 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -4619,6 +4415,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true roarr@2.15.4: @@ -4669,19 +4466,10 @@ packages: semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.2: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} @@ -4795,10 +4583,6 @@ packages: resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==} engines: {node: '>=18'} - stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} - streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -4964,9 +4748,6 @@ packages: tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - tslib@2.5.0: - resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} - tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -5262,9 +5043,6 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} - which-typed-array@1.1.9: resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} engines: {node: '>= 0.4'} @@ -5391,15 +5169,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 - '@babel/code-frame@7.18.6': - dependencies: - '@babel/highlight': 7.23.4 - - '@babel/code-frame@7.23.5': - dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 - '@babel/code-frame@7.24.2': dependencies: '@babel/highlight': 7.24.5 @@ -5410,7 +5179,7 @@ snapshots: '@babel/core@7.23.6': dependencies: '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.2 '@babel/generator': 7.23.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.6) @@ -5420,7 +5189,7 @@ snapshots: '@babel/traverse': 7.23.6 '@babel/types': 7.23.6 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -5453,10 +5222,6 @@ snapshots: dependencies: '@babel/types': 7.23.6 - '@babel/helper-module-imports@7.18.6': - dependencies: - '@babel/types': 7.23.6 - '@babel/helper-module-imports@7.22.15': dependencies: '@babel/types': 7.23.6 @@ -5468,7 +5233,7 @@ snapshots: '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.5 '@babel/helper-plugin-utils@7.22.5': {} @@ -5482,8 +5247,6 @@ snapshots: '@babel/helper-string-parser@7.23.4': {} - '@babel/helper-validator-identifier@7.22.20': {} - '@babel/helper-validator-identifier@7.24.5': {} '@babel/helper-validator-option@7.23.5': {} @@ -5496,12 +5259,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/highlight@7.23.4': - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - '@babel/highlight@7.24.5': dependencies: '@babel/helper-validator-identifier': 7.24.5 @@ -5523,31 +5280,19 @@ snapshots: '@babel/core': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 - '@babel/runtime@7.20.7': - dependencies: - regenerator-runtime: 0.13.11 - - '@babel/runtime@7.21.0': - dependencies: - regenerator-runtime: 0.13.11 - - '@babel/runtime@7.22.5': - dependencies: - regenerator-runtime: 0.13.11 - '@babel/runtime@7.24.5': dependencies: regenerator-runtime: 0.14.1 '@babel/template@7.22.15': dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.2 '@babel/parser': 7.23.6 '@babel/types': 7.23.6 '@babel/traverse@7.23.6': dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.2 '@babel/generator': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 @@ -5555,7 +5300,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.6 '@babel/types': 7.23.6 - debug: 4.3.4 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -5563,7 +5308,7 @@ snapshots: '@babel/types@7.23.6': dependencies: '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.5 to-fast-properties: 2.0.0 '@chakra-ui/accordion@2.2.0(@chakra-ui/system@2.5.8(@emotion/react@11.10.6(@types/react@18.0.26)(react@18.3.1))(@emotion/styled@11.10.6(@emotion/react@11.10.6(@types/react@18.0.26)(react@18.3.1))(@types/react@18.0.26)(react@18.3.1))(react@18.3.1))(framer-motion@10.11.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': @@ -6299,7 +6044,7 @@ snapshots: '@electron/get@2.0.3': dependencies: - debug: 4.3.4 + debug: 4.3.7 env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -6313,7 +6058,7 @@ snapshots: '@electron/notarize@2.2.1': dependencies: - debug: 4.3.4 + debug: 4.3.7 fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: @@ -6322,7 +6067,7 @@ snapshots: '@electron/osx-sign@1.0.5': dependencies: compare-version: 0.1.2 - debug: 4.3.4 + debug: 4.3.7 fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -6334,7 +6079,7 @@ snapshots: dependencies: '@electron/asar': 3.2.8 '@malept/cross-spawn-promise': 1.1.1 - debug: 4.3.4 + debug: 4.3.7 dir-compare: 3.3.0 fs-extra: 9.1.0 minimatch: 3.1.2 @@ -6344,8 +6089,8 @@ snapshots: '@emotion/babel-plugin@11.10.6': dependencies: - '@babel/helper-module-imports': 7.18.6 - '@babel/runtime': 7.21.0 + '@babel/helper-module-imports': 7.22.15 + '@babel/runtime': 7.24.5 '@emotion/hash': 0.9.0 '@emotion/memoize': 0.8.0 '@emotion/serialize': 1.1.1 @@ -6382,7 +6127,7 @@ snapshots: '@emotion/react@11.10.6(@types/react@18.0.26)(react@18.3.1)': dependencies: - '@babel/runtime': 7.21.0 + '@babel/runtime': 7.24.5 '@emotion/babel-plugin': 11.10.6 '@emotion/cache': 11.10.5 '@emotion/serialize': 1.1.1 @@ -6400,13 +6145,13 @@ snapshots: '@emotion/memoize': 0.8.0 '@emotion/unitless': 0.8.0 '@emotion/utils': 1.2.0 - csstype: 3.1.1 + csstype: 3.1.2 '@emotion/sheet@1.2.1': {} '@emotion/styled@11.10.6(@emotion/react@11.10.6(@types/react@18.0.26)(react@18.3.1))(@types/react@18.0.26)(react@18.3.1)': dependencies: - '@babel/runtime': 7.21.0 + '@babel/runtime': 7.24.5 '@emotion/babel-plugin': 11.10.6 '@emotion/is-prop-valid': 1.2.0 '@emotion/react': 11.10.6(@types/react@18.0.26)(react@18.3.1) @@ -6647,7 +6392,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.7 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -6678,7 +6423,7 @@ snapshots: '@humanwhocodes/config-array@0.11.13': dependencies: '@humanwhocodes/object-schema': 2.0.1 - debug: 4.3.4 + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -6707,21 +6452,19 @@ snapshots: '@jridgewell/gen-mapping@0.3.3': dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.20 '@jridgewell/resolve-uri@3.1.1': {} '@jridgewell/set-array@1.1.2': {} - '@jridgewell/sourcemap-codec@1.4.15': {} - '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.20': dependencies: '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@malept/cross-spawn-promise@1.1.1': dependencies: @@ -6729,7 +6472,7 @@ snapshots: '@malept/flatpak-bundler@0.4.0': dependencies: - debug: 4.3.4 + debug: 4.3.7 fs-extra: 9.1.0 lodash: 4.17.21 tmp-promise: 3.0.3 @@ -7057,30 +6800,30 @@ snapshots: '@testing-library/dom@8.19.1': dependencies: - '@babel/code-frame': 7.18.6 - '@babel/runtime': 7.20.7 - '@types/aria-query': 5.0.1 - aria-query: 5.1.3 + '@babel/code-frame': 7.24.2 + '@babel/runtime': 7.24.5 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 chalk: 4.1.2 - dom-accessibility-api: 0.5.15 - lz-string: 1.4.4 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 pretty-format: 27.5.1 '@testing-library/jest-dom@5.16.5': dependencies: '@adobe/css-tools': 4.0.2 - '@babel/runtime': 7.20.7 + '@babel/runtime': 7.24.5 '@types/testing-library__jest-dom': 5.14.5 - aria-query: 5.1.3 + aria-query: 5.3.0 chalk: 3.0.0 css.escape: 1.5.1 - dom-accessibility-api: 0.5.15 + dom-accessibility-api: 0.5.16 lodash: 4.17.21 redent: 3.0.0 '@testing-library/react@13.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.20.7 + '@babel/runtime': 7.24.5 '@testing-library/dom': 8.19.1 '@types/react-dom': 18.0.10 react: 18.3.1 @@ -7092,8 +6835,6 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@types/aria-query@5.0.1': {} - '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -7185,7 +6926,7 @@ snapshots: '@types/jest@29.2.5': dependencies: expect: 29.3.1 - pretty-format: 29.3.1 + pretty-format: 29.7.0 '@types/json-schema@7.0.15': {} @@ -7237,7 +6978,7 @@ snapshots: dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 - csstype: 3.1.1 + csstype: 3.1.2 '@types/responselike@1.0.3': dependencies: @@ -7304,28 +7045,18 @@ snapshots: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3) '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.4 + debug: 4.3.7 eslint: 8.56.0 optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@5.48.1': - dependencies: - '@typescript-eslint/types': 5.48.1 - '@typescript-eslint/visitor-keys': 5.48.1 - '@typescript-eslint/scope-manager@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@6.21.0': - dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/scope-manager@7.16.1': dependencies: '@typescript-eslint/types': 7.16.1 @@ -7335,7 +7066,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3) '@typescript-eslint/utils': 7.16.1(eslint@8.56.0)(typescript@5.5.3) - debug: 4.3.4 + debug: 4.3.7 eslint: 8.56.0 ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: @@ -7343,52 +7074,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@5.48.1': {} - '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/types@7.16.1': {} - '@typescript-eslint/typescript-estree@5.48.1(typescript@5.5.3)': - dependencies: - '@typescript-eslint/types': 5.48.1 - '@typescript-eslint/visitor-keys': 5.48.1 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.5.3) - optionalDependencies: - typescript: 5.5.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.5.3)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.5.3) - optionalDependencies: - typescript: 5.5.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.3)': - dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.5.3) + tsutils: 3.21.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: @@ -7398,7 +7096,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.4 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -7409,21 +7107,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.48.1(eslint@8.56.0)(typescript@5.5.3)': - dependencies: - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.5 - '@typescript-eslint/scope-manager': 5.48.1 - '@typescript-eslint/types': 5.48.1 - '@typescript-eslint/typescript-estree': 5.48.1(typescript@5.5.3) - eslint: 8.56.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.56.0) - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - - typescript - '@typescript-eslint/utils@5.62.0(eslint@8.56.0)(typescript@5.5.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) @@ -7434,20 +7117,6 @@ snapshots: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.5.3) eslint: 8.56.0 eslint-scope: 5.1.1 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/utils@6.21.0(eslint@8.56.0)(typescript@5.5.3)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.5 - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.3) - eslint: 8.56.0 semver: 7.6.2 transitivePeerDependencies: - supports-color @@ -7464,21 +7133,11 @@ snapshots: - supports-color - typescript - '@typescript-eslint/visitor-keys@5.48.1': - dependencies: - '@typescript-eslint/types': 5.48.1 - eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@6.21.0': - dependencies: - '@typescript-eslint/types': 6.21.0 - eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.16.1': dependencies: '@typescript-eslint/types': 7.16.1 @@ -7567,13 +7226,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color agent-base@7.1.0: dependencies: - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -7620,7 +7279,7 @@ snapshots: builder-util: 24.13.1 builder-util-runtime: 9.2.4 chromium-pickle-js: 0.2.0 - debug: 4.3.4 + debug: 4.3.7 dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3) ejs: 3.1.9 electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3) @@ -7635,7 +7294,7 @@ snapshots: minimatch: 5.1.6 read-config-file: 6.3.2 sanitize-filename: 1.6.3 - semver: 7.5.4 + semver: 7.6.2 tar: 6.2.0 temp-file: 3.4.0 transitivePeerDependencies: @@ -7685,10 +7344,6 @@ snapshots: dependencies: tslib: 2.6.2 - aria-query@5.1.3: - dependencies: - deep-equal: 2.2.0 - aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -7698,9 +7353,9 @@ snapshots: array-includes@3.1.6: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.2 is-string: 1.0.7 array-union@2.1.0: {} @@ -7708,17 +7363,17 @@ snapshots: array.prototype.flatmap@1.3.1: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 es-shim-unscopables: 1.0.0 array.prototype.tosorted@1.1.1: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 es-shim-unscopables: 1.0.0 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.2 assert-plus@1.0.0: optional: true @@ -7740,14 +7395,6 @@ snapshots: available-typed-arrays@1.0.5: {} - axios@1.2.2: - dependencies: - follow-redirects: 1.15.2 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - axios@1.7.2: dependencies: follow-redirects: 1.15.6 @@ -7758,7 +7405,7 @@ snapshots: babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.21.0 + '@babel/runtime': 7.24.5 cosmiconfig: 7.1.0 resolve: 1.22.1 @@ -7839,7 +7486,7 @@ snapshots: builder-util-runtime@9.2.4: dependencies: - debug: 4.3.4 + debug: 4.3.7 sax: 1.3.0 transitivePeerDependencies: - supports-color @@ -7853,7 +7500,7 @@ snapshots: builder-util-runtime: 9.2.4 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.7 fs-extra: 10.1.0 http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 @@ -7955,8 +7602,6 @@ snapshots: chromium-pickle-js@0.2.0: {} - ci-info@3.7.1: {} - ci-info@3.9.0: {} cli-truncate@2.1.0: @@ -8024,7 +7669,7 @@ snapshots: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 - readable-stream: 2.3.7 + readable-stream: 2.3.8 typedarray: 0.0.6 config-file-ts@0.2.4: @@ -8036,8 +7681,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - content-type@1.0.4: {} - content-type@1.0.5: {} convert-source-map@1.9.0: {} @@ -8115,8 +7758,6 @@ snapshots: dependencies: cssom: 0.3.8 - csstype@3.1.1: {} - csstype@3.1.2: {} csv-stringify@6.4.5: {} @@ -8131,10 +7772,6 @@ snapshots: dependencies: ms: 2.0.0 - debug@4.3.4: - dependencies: - ms: 2.1.2 - debug@4.3.7: dependencies: ms: 2.1.3 @@ -8147,26 +7784,6 @@ snapshots: deep-eql@5.0.2: {} - deep-equal@2.2.0: - dependencies: - call-bind: 1.0.2 - es-get-iterator: 1.1.3 - get-intrinsic: 1.2.2 - is-arguments: 1.1.1 - is-array-buffer: 3.0.1 - is-date-object: 1.0.5 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - isarray: 2.0.5 - object-is: 1.1.5 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 - side-channel: 1.0.4 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.9 - deep-is@0.1.4: {} deepmerge-ts@7.0.3: {} @@ -8179,11 +7796,6 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.1 - define-properties@1.1.4: - dependencies: - has-property-descriptors: 1.0.1 - object-keys: 1.1.1 - define-properties@1.2.1: dependencies: define-data-property: 1.1.1 @@ -8248,8 +7860,6 @@ snapshots: dependencies: esutils: 2.0.3 - dom-accessibility-api@0.5.15: {} - dom-accessibility-api@0.5.16: {} domexception@4.0.0: @@ -8263,8 +7873,6 @@ snapshots: dotenv-expand@5.1.0: {} - dotenv@16.0.3: {} - dotenv@16.3.1: {} dotenv@9.0.2: {} @@ -8382,18 +7990,6 @@ snapshots: unbox-primitive: 1.0.2 which-typed-array: 1.1.9 - es-get-iterator@1.1.3: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.2 - has-symbols: 1.0.3 - is-arguments: 1.1.1 - is-map: 2.0.2 - is-set: 2.0.2 - is-string: 1.0.7 - isarray: 2.0.5 - stop-iteration-iterator: 1.0.0 - es-module-lexer@1.5.4: {} es-set-tostringtag@2.0.1: @@ -8519,7 +8115,7 @@ snapshots: eslint-plugin-jest@28.6.0(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3): dependencies: - '@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.16.1(eslint@8.56.0)(typescript@5.5.3) eslint: 8.56.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3) @@ -8563,7 +8159,7 @@ snapshots: object.values: 1.1.6 prop-types: 15.8.1 resolve: 2.0.0-next.4 - semver: 6.3.0 + semver: 6.3.1 string.prototype.matchall: 4.0.8 eslint-plugin-simple-import-sort@8.0.0(eslint@8.56.0): @@ -8572,7 +8168,7 @@ snapshots: eslint-plugin-testing-library@5.9.1(eslint@8.56.0)(typescript@5.5.3): dependencies: - '@typescript-eslint/utils': 5.48.1(eslint@8.56.0)(typescript@5.5.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.5.3) eslint: 8.56.0 transitivePeerDependencies: - supports-color @@ -8588,13 +8184,6 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-utils@3.0.0(eslint@8.56.0): - dependencies: - eslint: 8.56.0 - eslint-visitor-keys: 2.1.0 - - eslint-visitor-keys@2.1.0: {} - eslint-visitor-keys@3.4.3: {} eslint@8.56.0: @@ -8610,7 +8199,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.7 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -8697,7 +8286,7 @@ snapshots: array-flatten: 1.1.1 body-parser: 1.20.1 content-disposition: 0.5.4 - content-type: 1.0.4 + content-type: 1.0.5 cookie: 0.5.0 cookie-signature: 1.0.6 debug: 2.6.9 @@ -8731,7 +8320,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4 + debug: 4.3.7 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -8811,8 +8400,6 @@ snapshots: dependencies: tslib: 2.6.2 - follow-redirects@1.15.2: {} - follow-redirects@1.15.6: {} for-each@0.3.3: @@ -8833,7 +8420,7 @@ snapshots: framer-motion@10.11.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - tslib: 2.5.0 + tslib: 2.6.2 optionalDependencies: '@emotion/is-prop-valid': 0.8.8 react: 18.3.1 @@ -8911,12 +8498,6 @@ snapshots: get-caller-file@2.0.5: {} - get-intrinsic@1.1.3: - dependencies: - function-bind: 1.1.2 - has: 1.0.3 - has-symbols: 1.0.3 - get-intrinsic@1.2.2: dependencies: function-bind: 1.1.2 @@ -9118,7 +8699,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -9135,14 +8716,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -9196,11 +8777,6 @@ snapshots: ipaddr.js@1.9.1: {} - is-arguments@1.1.1: - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - is-array-buffer@3.0.1: dependencies: call-bind: 1.0.2 @@ -9246,8 +8822,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-map@2.0.2: {} - is-negative-zero@2.0.2: {} is-number-object@1.0.7: @@ -9265,8 +8839,6 @@ snapshots: call-bind: 1.0.2 has-tostringtag: 1.0.0 - is-set@2.0.2: {} - is-shared-array-buffer@1.0.2: dependencies: call-bind: 1.0.2 @@ -9289,21 +8861,12 @@ snapshots: gopd: 1.0.1 has-tostringtag: 1.0.0 - is-weakmap@2.0.1: {} - is-weakref@1.0.2: dependencies: call-bind: 1.0.2 - is-weakset@2.0.2: - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.2 - isarray@1.0.0: {} - isarray@2.0.5: {} - isbinaryfile@4.0.10: {} isbinaryfile@5.0.0: {} @@ -9335,7 +8898,7 @@ snapshots: jest-message-util@29.3.1: dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.2 '@jest/types': 29.3.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 @@ -9350,7 +8913,7 @@ snapshots: '@jest/types': 29.3.1 '@types/node': 20.14.10 chalk: 4.1.2 - ci-info: 3.7.1 + ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 @@ -9516,8 +9079,6 @@ snapshots: dependencies: yallist: 4.0.0 - lz-string@1.4.4: {} - lz-string@1.5.0: {} magic-string@0.30.14: @@ -9526,7 +9087,7 @@ snapshots: magic-string@0.30.8: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 matcher@3.0.0: dependencies: @@ -9576,16 +9137,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@9.0.3: - dependencies: - brace-expansion: 2.0.1 - minimatch@9.0.4: dependencies: brace-expansion: 2.0.1 - minimist@1.2.7: {} - minimist@1.2.8: {} minipass@3.3.6: @@ -9611,8 +9166,6 @@ snapshots: ms@2.0.0: {} - ms@2.1.2: {} - ms@2.1.3: {} multer@1.4.5-lts.1: @@ -9663,11 +9216,6 @@ snapshots: object-inspect@1.12.3: {} - object-is@1.1.5: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.1 - object-keys@1.1.1: {} object.assign@4.1.4: @@ -9680,24 +9228,24 @@ snapshots: object.entries@1.1.6: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 object.fromentries@2.0.6: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 object.hasown@1.1.2: dependencies: - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 object.values@1.1.6: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 on-finished@2.4.1: @@ -9750,7 +9298,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -9784,8 +9332,6 @@ snapshots: pend@1.2.0: {} - picocolors@1.0.0: {} - picocolors@1.0.1: {} picomatch@2.3.1: {} @@ -9807,7 +9353,7 @@ snapshots: postcss@8.4.38: dependencies: nanoid: 3.3.7 - picocolors: 1.0.0 + picocolors: 1.0.1 source-map-js: 1.2.0 prelude-ls@1.1.2: {} @@ -9826,12 +9372,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - pretty-format@29.3.1: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.2.0 - pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 @@ -9912,7 +9452,7 @@ snapshots: react-focus-lock@2.9.4(@types/react@18.0.26)(react@18.3.1): dependencies: - '@babel/runtime': 7.22.5 + '@babel/runtime': 7.24.5 focus-lock: 0.11.6 prop-types: 15.8.1 react: 18.3.1 @@ -9993,16 +9533,6 @@ snapshots: json5: 2.2.3 lazy-val: 1.0.5 - readable-stream@2.3.7: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -10036,8 +9566,6 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - regenerator-runtime@0.13.11: {} - regenerator-runtime@0.14.1: {} regexp.prototype.flags@1.4.3: @@ -10159,14 +9687,8 @@ snapshots: semver-compare@1.0.0: optional: true - semver@6.3.0: {} - semver@6.3.1: {} - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 - semver@7.6.2: {} send@0.18.0: @@ -10222,7 +9744,7 @@ snapshots: shx@0.3.4: dependencies: - minimist: 1.2.7 + minimist: 1.2.8 shelljs: 0.8.5 side-channel@1.0.4: @@ -10239,7 +9761,7 @@ snapshots: simple-update-notifier@2.0.0: dependencies: - semver: 7.5.4 + semver: 7.6.2 slash@3.0.0: {} @@ -10290,10 +9812,6 @@ snapshots: steno@4.0.2: {} - stop-iteration-iterator@1.0.0: - dependencies: - internal-slot: 1.0.4 - streamsearch@1.1.0: {} string-width@4.2.3: @@ -10305,9 +9823,9 @@ snapshots: string.prototype.matchall@4.0.8: dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 es-abstract: 1.21.1 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.2 has-symbols: 1.0.3 internal-slot: 1.0.4 regexp.prototype.flags: 1.4.3 @@ -10343,7 +9861,7 @@ snapshots: sumchecker@3.0.1: dependencies: - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -10455,8 +9973,6 @@ snapshots: tslib@2.4.0: {} - tslib@2.5.0: {} - tslib@2.6.2: {} tsutils@3.21.0(typescript@5.5.3): @@ -10556,7 +10072,7 @@ snapshots: dependencies: browserslist: 4.22.2 escalade: 3.1.1 - picocolors: 1.0.0 + picocolors: 1.0.1 uri-js@4.4.1: dependencies: @@ -10645,7 +10161,7 @@ snapshots: vite-tsconfig-paths@4.3.1(typescript@5.5.3)(vite@5.2.11(@types/node@20.14.10)(sass@1.57.1)): dependencies: - debug: 4.3.4 + debug: 4.3.7 globrex: 0.1.2 tsconfck: 3.0.2(typescript@5.5.3) optionalDependencies: @@ -10747,13 +10263,6 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 - which-collection@1.0.1: - dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 - which-typed-array@1.1.9: dependencies: available-typed-arrays: 1.0.5 From e91d5f5cd903d598c04a39f924cb70fceb9e0c0c Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 11:14:26 +0100 Subject: [PATCH 46/47] refactor: always show settings --- apps/client/src/views/cuesheet/Cuesheet.tsx | 16 +++++++--------- .../src/views/cuesheet/CuesheetPage.module.scss | 3 ++- .../CuesheetProgress.module.scss | 3 ++- .../CuesheetTableSettings.module.scss | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/client/src/views/cuesheet/Cuesheet.tsx b/apps/client/src/views/cuesheet/Cuesheet.tsx index a77c36da3..cba648790 100644 --- a/apps/client/src/views/cuesheet/Cuesheet.tsx +++ b/apps/client/src/views/cuesheet/Cuesheet.tsx @@ -40,7 +40,7 @@ export default function Cuesheet({ selectedId, currentBlockId, }: CuesheetProps) { - const { followSelected, showSettings, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings(); + const { followSelected, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings(); const { columnVisibility, columnOrder, @@ -110,14 +110,12 @@ export default function Cuesheet({ return ( <> - {showSettings && ( - - )} +
    diff --git a/apps/client/src/views/cuesheet/CuesheetPage.module.scss b/apps/client/src/views/cuesheet/CuesheetPage.module.scss index b179cf178..80ef47ba7 100644 --- a/apps/client/src/views/cuesheet/CuesheetPage.module.scss +++ b/apps/client/src/views/cuesheet/CuesheetPage.module.scss @@ -5,9 +5,10 @@ padding: 1rem 0.5rem; display: grid; - grid-template-rows: 3rem auto 1fr; + grid-template-rows: 3rem auto auto 1fr; grid-template-areas: 'overview' + 'progress' 'settings' 'table'; gap: 1rem; diff --git a/apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.module.scss b/apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.module.scss index b82de38a8..44a571809 100644 --- a/apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.module.scss +++ b/apps/client/src/views/cuesheet/cuesheet-progress/CuesheetProgress.module.scss @@ -1,3 +1,4 @@ .progressOverride { - height: 1rem; + height: 1rem; + grid-area: progress; } diff --git a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss index 4afcee79e..a036cda7c 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss +++ b/apps/client/src/views/cuesheet/cuesheet-table-settings/CuesheetTableSettings.module.scss @@ -1,6 +1,6 @@ .tableSettings { grid-area: settings; - padding: 0.5rem 1rem; + padding-inline: 0.5rem; display: flex; gap: 5rem; font-size: $inner-section-text-size; From 41fe213ebbb9c5a36199cd39e7bf8a73b62e75b9 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sun, 15 Dec 2024 12:02:04 +0100 Subject: [PATCH 47/47] refactor: settings in params --- .../src/features/viewers/common/viewUtils.ts | 4 + apps/client/src/views/cuesheet/Cuesheet.tsx | 16 ++-- .../src/views/cuesheet/CuesheetPage.tsx | 15 ++- .../src/views/cuesheet/cuesheet.options.ts | 95 ++++++++++++++++--- .../src/views/cuesheet/cuesheetCols.tsx | 13 ++- .../cuesheet/store/cuesheetSettingsStore.tsx | 85 ----------------- 6 files changed, 113 insertions(+), 115 deletions(-) delete mode 100644 apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx diff --git a/apps/client/src/features/viewers/common/viewUtils.ts b/apps/client/src/features/viewers/common/viewUtils.ts index 32158f01c..bfc2e3046 100644 --- a/apps/client/src/features/viewers/common/viewUtils.ts +++ b/apps/client/src/features/viewers/common/viewUtils.ts @@ -32,6 +32,10 @@ export function getTimerByType(freezeEnd: boolean, timerObject?: TimerTypeParams } } +/** + * Parses a string to semantically verify if it represents a true value + * Used in the context of parsing search params and local storage items which can be strings or null + */ export function isStringBoolean(text: string | null) { if (text === null) { return false; diff --git a/apps/client/src/views/cuesheet/Cuesheet.tsx b/apps/client/src/views/cuesheet/Cuesheet.tsx index cba648790..d205da34b 100644 --- a/apps/client/src/views/cuesheet/Cuesheet.tsx +++ b/apps/client/src/views/cuesheet/Cuesheet.tsx @@ -18,7 +18,7 @@ import CuesheetHeader from './cuesheet-table-elements/CuesheetHeader'; import DelayRow from './cuesheet-table-elements/DelayRow'; import EventRow from './cuesheet-table-elements/EventRow'; import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings'; -import { useCuesheetSettings } from './store/cuesheetSettingsStore'; +import { useCuesheetOptions } from './cuesheet.options'; import useColumnManager from './useColumnManager'; import style from './Cuesheet.module.scss'; @@ -40,7 +40,7 @@ export default function Cuesheet({ selectedId, currentBlockId, }: CuesheetProps) { - const { followSelected, showDelayBlock, showPrevious, showIndexColumn } = useCuesheetSettings(); + const { followSelected, hideDelays, hidePast, hideIndexColumn } = useCuesheetOptions(); const { columnVisibility, columnOrder, @@ -118,7 +118,7 @@ export default function Cuesheet({ />
    - + {rowModel.rows.map((row) => { const key = row.original.id; @@ -128,17 +128,17 @@ export default function Cuesheet({ } if (isOntimeBlock(row.original)) { - if (isPast && !showPrevious && key !== currentBlockId) { + if (isPast && hidePast && key !== currentBlockId) { return null; } return ; } if (isOntimeDelay(row.original)) { - if (isPast && !showPrevious) { + if (isPast && hidePast) { return null; } const delayVal = row.original.duration; - if (!showDelayBlock || delayVal === 0) { + if (hideDelays || delayVal === 0) { return null; } @@ -148,7 +148,7 @@ export default function Cuesheet({ eventIndex++; const isSelected = key === selectedId; - if (isPast && !showPrevious) { + if (isPast && hidePast) { return null; } @@ -173,7 +173,7 @@ export default function Cuesheet({ selectedRef={isSelected ? selectedRef : undefined} skip={row.original.skip} colour={row.original.colour} - showIndexColumn={showIndexColumn} + showIndexColumn={!hideIndexColumn} > {row.getVisibleCells().map((cell) => { return ( diff --git a/apps/client/src/views/cuesheet/CuesheetPage.tsx b/apps/client/src/views/cuesheet/CuesheetPage.tsx index 2ab1ccff6..e59184527 100644 --- a/apps/client/src/views/cuesheet/CuesheetPage.tsx +++ b/apps/client/src/views/cuesheet/CuesheetPage.tsx @@ -1,4 +1,5 @@ import { useCallback, useMemo } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { IconButton, useDisclosure } from '@chakra-ui/react'; import { IoApps } from '@react-icons/all-files/io5/IoApps'; import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline'; @@ -6,6 +7,7 @@ import { CustomFieldLabel, isOntimeEvent, OntimeEvent } from 'ontime-types'; import ProductionNavigationMenu from '../../common/components/navigation-menu/ProductionNavigationMenu'; import EmptyPage from '../../common/components/state/EmptyPage'; +import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor'; import { useEventAction } from '../../common/hooks/useEventAction'; import { useCuesheet } from '../../common/hooks/useSocket'; import { useWindowTitle } from '../../common/hooks/useWindowTitle'; @@ -14,8 +16,8 @@ import { useFlatRundown } from '../../common/hooks-query/useRundown'; import { CuesheetOverview } from '../../features/overview/Overview'; import CuesheetProgress from './cuesheet-progress/CuesheetProgress'; -import { useCuesheetSettings } from './store/cuesheetSettingsStore'; import Cuesheet from './Cuesheet'; +import { cuesheetOptions } from './cuesheet.options'; import { makeCuesheetColumns } from './cuesheetCols'; import styles from './CuesheetPage.module.scss'; @@ -24,15 +26,21 @@ export default function CuesheetPage() { // TODO: can we use the normalised rundown for the table? const { data: flatRundown, status: rundownStatus } = useFlatRundown(); const { data: customFields } = useCustomFields(); + const [searchParams, setSearchParams] = useSearchParams(); const { isOpen: isMenuOpen, onOpen, onClose } = useDisclosure(); const { updateCustomField, updateEvent } = useEventAction(); const featureData = useCuesheet(); const columns = useMemo(() => makeCuesheetColumns(customFields), [customFields]); - const toggleSettings = useCuesheetSettings((state) => state.toggleSettings); useWindowTitle('Cuesheet'); + /** Handles showing the view params edit drawer */ + const showEditFormDrawer = useCallback(() => { + searchParams.set('edit', 'true'); + setSearchParams(searchParams); + }, [searchParams, setSearchParams]); + /** * Handles updating a custom field */ @@ -99,6 +107,7 @@ export default function CuesheetPage() { return (
    + } - onClick={() => toggleSettings()} + onClick={showEditFormDrawer} /> diff --git a/apps/client/src/views/cuesheet/cuesheet.options.ts b/apps/client/src/views/cuesheet/cuesheet.options.ts index c57bc6e2a..82568c5d4 100644 --- a/apps/client/src/views/cuesheet/cuesheet.options.ts +++ b/apps/client/src/views/cuesheet/cuesheet.options.ts @@ -1,19 +1,90 @@ -import { OntimeEntryCommonKeys, OntimeEvent } from 'ontime-types'; +import { useMemo } from 'react'; +import { useSearchParams } from 'react-router-dom'; + +import { ViewOption } from '../../common/components/view-params-editor/types'; +import { isStringBoolean } from '../../features/viewers/common/viewUtils'; /** - * @description set default column order + * In the specific case of the cuesheet options + * we save the user preferences in the local storage */ -export const defaultColumnOrder: OntimeEntryCommonKeys[] = [ - 'isPublic', - 'cue', - 'timeStart', - 'timeEnd', - 'duration', - 'title', - 'note', +export const cuesheetOptions: ViewOption[] = [ + { section: 'Table options' }, + { + id: 'hideTableSeconds', + title: 'Hide seconds in table', + description: 'Whether to hide seconds in the time fields displayed in the table', + type: 'boolean', + defaultValue: false, + }, + { + id: 'followSelected', + title: 'Follow selected event', + description: 'Whether the view should automatically scroll to the selected event', + type: 'boolean', + defaultValue: false, + }, + { + id: 'hidePast', + title: 'Hide Past Events', + description: 'Whether to hide events that have passed', + type: 'boolean', + defaultValue: false, + }, + { + id: 'hideIndexColumn', + title: 'Hide index column', + description: 'Whether the hide the event indexes in the table', + type: 'boolean', + defaultValue: false, + }, + { section: 'Delay flow' }, + { + id: 'showDelayedTimes', + title: 'Show delayed times', + description: 'Whether the time fields should include delays', + type: 'boolean', + defaultValue: false, + }, + { + id: 'hideDelays', + title: 'Hide delays', + description: 'Whether to hide the rows containing scheduled delays', + type: 'boolean', + defaultValue: false, + }, ]; +type CuesheetOptions = { + hideTableSeconds: boolean; + followSelected: boolean; + hidePast: boolean; + hideIndexColumn: boolean; + showDelayedTimes: boolean; + hideDelays: boolean; +}; + /** - * @description set default hidden columns + * Utility extract the view options from URL Params + * the names and fallbacks are manually matched with cuesheetOptions */ -export const defaultHiddenColumns: (keyof OntimeEvent)[] = []; +export function getOptionsFromParams(searchParams: URLSearchParams): CuesheetOptions { + // we manually make an object that matches the key above + return { + hideTableSeconds: isStringBoolean(searchParams.get('hideTableSeconds')), + followSelected: isStringBoolean(searchParams.get('followSelected')), + hidePast: isStringBoolean(searchParams.get('hidePast')), + hideIndexColumn: isStringBoolean(searchParams.get('hideIndexColumn')), + showDelayedTimes: isStringBoolean(searchParams.get('showDelayedTimes')), + hideDelays: isStringBoolean(searchParams.get('hideDelays')), + }; +} + +/** + * Hook exposes the cuesheet view options + */ +export function useCuesheetOptions(): CuesheetOptions { + const [searchParams] = useSearchParams(); + const options = useMemo(() => getOptionsFromParams(searchParams), [searchParams]); + return options; +} diff --git a/apps/client/src/views/cuesheet/cuesheetCols.tsx b/apps/client/src/views/cuesheet/cuesheetCols.tsx index 460d7061d..f82a55561 100644 --- a/apps/client/src/views/cuesheet/cuesheetCols.tsx +++ b/apps/client/src/views/cuesheet/cuesheetCols.tsx @@ -8,7 +8,7 @@ import RunningTime from '../../features/viewers/common/running-time/RunningTime' import MultiLineCell from './cuesheet-table-elements/MultiLineCell'; import SingleLineCell from './cuesheet-table-elements/SingleLineCell'; -import { useCuesheetSettings } from './store/cuesheetSettingsStore'; +import { useCuesheetOptions } from './cuesheet.options'; import style from './Cuesheet.module.scss'; @@ -35,27 +35,26 @@ function MakePublic({ row, column, table }: CellContext) { - const showDelayedTimes = useCuesheetSettings((state) => state.showDelayedTimes); - const hideSeconds = useCuesheetSettings((state) => state.hideSeconds); + const { showDelayedTimes, hideTableSeconds } = useCuesheetOptions(); const cellValue = (getValue() as number | null) ?? 0; const delayValue = (original as OntimeEvent)?.delay ?? 0; return ( - + {delayValue !== 0 && showDelayedTimes && ( - + )} ); } function MakeDuration({ getValue }: CellContext) { - const hideSeconds = useCuesheetSettings((state) => state.hideSeconds); + const { hideTableSeconds } = useCuesheetOptions(); const cellValue = (getValue() as number | null) ?? 0; - return ; + return ; } function MakeMultiLineField({ row, column, table }: CellContext) { diff --git a/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx b/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx deleted file mode 100644 index f9eb5d0fb..000000000 --- a/apps/client/src/views/cuesheet/store/cuesheetSettingsStore.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { create } from 'zustand'; - -import { booleanFromLocalStorage } from '../../../common/utils/localStorage'; - -interface CuesheetSettingsStore { - showSettings: boolean; - showIndexColumn: boolean; - followSelected: boolean; - showPrevious: boolean; - showDelayBlock: boolean; - showDelayedTimes: boolean; - hideSeconds: boolean; - - toggleSettings: (newValue?: boolean) => void; - toggleFollow: (newValue?: boolean) => void; - togglePreviousVisibility: (newValue?: boolean) => void; - toggleIndexColumn: (newValue?: boolean) => void; - toggleDelayVisibility: (newValue?: boolean) => void; - toggleDelayedTimes: (newValue?: boolean) => void; - toggleSecondsVisibility: (newValue?: boolean) => void; -} - -function toggle(oldValue: boolean, value?: boolean) { - if (typeof value === 'undefined') { - return !oldValue; - } - return value; -} - -enum CuesheetKeys { - Follow = 'ontime-cuesheet-follow-selected', - DelayVisibility = 'ontime-cuesheet-show-delay', - PreviousVisibility = 'ontime-cuesheet-show-previous', - ColumnIndex = 'ontime-cuesheet-show-index-column', - DelayedTimes = 'ontime-cuesheet-show-delayed', - Seconds = 'ontime-cuesheet-hide-sceconds', -} - -export const useCuesheetSettings = create()((set) => ({ - showSettings: false, - showIndexColumn: booleanFromLocalStorage(CuesheetKeys.ColumnIndex, true), - followSelected: booleanFromLocalStorage(CuesheetKeys.Follow, false), - showPrevious: booleanFromLocalStorage(CuesheetKeys.PreviousVisibility, true), - showDelayBlock: booleanFromLocalStorage(CuesheetKeys.DelayVisibility, true), - showDelayedTimes: booleanFromLocalStorage(CuesheetKeys.DelayedTimes, false), - hideSeconds: booleanFromLocalStorage(CuesheetKeys.Seconds, false), - - toggleSettings: (newValue?: boolean) => set((state) => ({ showSettings: toggle(state.showSettings, newValue) })), - toggleFollow: (newValue?: boolean) => - set((state) => { - const followSelected = toggle(state.followSelected, newValue); - localStorage.setItem(CuesheetKeys.Follow, String(followSelected)); - return { followSelected }; - }), - toggleIndexColumn: (newValue?: boolean) => - set((state) => { - const showIndexColumn = toggle(state.showIndexColumn, newValue); - localStorage.setItem(CuesheetKeys.ColumnIndex, String(showIndexColumn)); - return { showIndexColumn }; - }), - togglePreviousVisibility: (newValue?: boolean) => - set((state) => { - const showPrevious = toggle(state.showPrevious, newValue); - localStorage.setItem(CuesheetKeys.PreviousVisibility, String(showPrevious)); - return { showPrevious }; - }), - toggleDelayVisibility: (newValue?: boolean) => - set((state) => { - const showDelayBlock = toggle(state.showDelayBlock, newValue); - localStorage.setItem(CuesheetKeys.DelayVisibility, String(showDelayBlock)); - return { showDelayBlock }; - }), - toggleDelayedTimes: (newValue?: boolean) => - set((state) => { - const showDelayedTimes = toggle(state.showDelayedTimes, newValue); - localStorage.setItem(CuesheetKeys.DelayedTimes, String(showDelayedTimes)); - return { showDelayedTimes }; - }), - toggleSecondsVisibility: (newValue?: boolean) => - set((state) => { - const hideSeconds = toggle(state.hideSeconds, newValue); - localStorage.setItem(CuesheetKeys.Seconds, String(hideSeconds)); - return { hideSeconds }; - }), -}));