From c8e979bc9af967b13c91b2022241c999614876ba Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Thu, 18 May 2023 14:02:22 +0200 Subject: [PATCH] v2 (#386) * Refactor/ts sockets (#210) * refactor(ts): create socket subscription service * refactor(ts-sockets): useSubscription hook * refactor(ts-sockets): extract colour selection to utility * Refactor/socket controller (#212) * refactor(socket): dictionary cleanup * refactor(socket): detangle socket from EventTimer * refactor(socket): poll object * refactor(socket): wip, extract data responsibilities to provider * fix: issue with onAir * refactor: create data provider and validation utils * refactor: remove deprecated endpoint * refactor: detangle and validate ontime controller * refactor: detangle and validate events controller * refactor: validate routers * refactor: handle post failure in modals * chore: upgrade electron (#215) * Fix: issue with text colour (#214) * fix: adjust text colour from context * fix: issue with wrong proptype * chore: upgrade electron * chore: declare node version * chore: upgrade node actions * Feat/55 v2 (#225) * chore: upgrade relevant libraries * feat(skip): add skip styling to paginated items * chore: upgrade relevant libraries * Fix: issue with text colour (#214) * fix: adjust text colour from context * fix: issue with wrong proptype * fix issue with vite migration (#217) * hotfix: 1.8.2 issues vite migration * fix: file import options * feat(55): styling * refactor: remove onhover option for entry block * refactor: relocate logging provider * refactor: convert to typescript * feat(55): add event editor * refactor: extract event actions * fix: bad import * feat(55): redesign components * fix: issues with not awaiting async * refactor: replace socket with subscription * refactor: remove unused * style: small tweaks * refactor: extract event actions * refactor: cleanup debug * refactor: chakra imports * fix: optimistic mutations * refactor: handle promise rejections * refactor: validation * fix: rq optimistic mutations * feat: add playback feedback to block * refactor: no optimistic adding of events * refactor: simplify cursor state * styles: cleanup editor style * refactor: cleanup duration update * fix: revert package upgrade (issues with vitest) * fix: prevent cyclic imports * refactor: extract data fetcher * refactor: typescript migration * chore: update tests * fix: remove problematic (#228) * styles: v2 (#229) * style: revise selected style * style: revise editor styles * style: revise viewer styles * chore: update tests * v2:feat (#231) * style: element relationship * feat: utility to add first element * refactor: organise dir * ux: deleting element closes drawer * fix: issue with escaped characters * fix: issue with overflow in events list * fix: prevent event timer from receiving non event * style: prevent small shift on class change * style: visually detach event editor * fix: entry block knows last event * fix: skip event timer updates on non events * fix: prevent electron OPENGL error * style: cleanup text styles * style: unify input styles * refactor: simplify style and composition * refactor: tweaks on style + ts * refactor: add validation to events post * fix: handle non events in event timer * refactor: cleanup unused * V2 styles part2 (#233) * style: create tag to display network messages * style: create button style for playback * style: review style for QuickEntry * style: review style for Info panel * style: review style for Event blocks * style: review style for Message control panel * style: review style for Playback control * style: review application styles * style: review block styles * refactor: TapButton has active state * style: small style tweaks * refactor: type checks * V2 message manager (#234) * refactor: server run script * refactor: extract message control feature * refactor: socket usage for message control feature * refactor: migrate e2e testing to playwright * chore: add feature tests * refactor: add validation on socket controller * chore: jest tests server logic * chore: update tests * chore: run playwright tests on pull_requests * V2 rundown manager (#237) * refactor: migrate eventlist > rundown * hotfix: fix object naming error on excel import (#252) * feat: V2 ontime menu (#259) * V2 socket store (#254) * refactor: create socket utility * refactor: ensure a single subscription to topics * refactor: replace usages of socket object with subscription store handler * refactor: v2 event loader (#260) * refactor: extract jest config * refactor: rename params in reoder endpoint * refactor: avoid app exports * refactor: small code smells * refactor: run development server * refactor: extract rundown service and event loader logic * refactor: rename events > rundown * refactor: code style * fix: handle external change of title * refactor: cleanup dictionary * refactor: rename MessageService * refactor: use eventID for operations * refactor: migrate OSC controller to service * refactor: migrate Socket controller to service * refactor: migrate HTTP controller to service * refactor: extract logic into discrete services * refactor: remove rundown from event timer * refactor: remove duplicate * refactor: remove unused * chore: update tests * refactor: run test CI on master or manual run * lint: reorder imports * refactor: ensure consistent routing * V2 event block (#261) * feat: implement progress bar on running event * refactor: use event action hook * refactor: align backend data * v2 styling (#263) * feat: implement progress bar on running event * refactor: use event action hook * refactor: align backend data * style: v2 style tweaks * style: v2 style tweaks + ts * fix: fix delay increment calls * style: v2 style tweaks + ts * style: v2 style tweaks + ts * style: v2 style tweaks + ts * fix: naming issue with message control socket endpoint * chore: upgrade style dependencies * style: v2 style tweaks + ts * style: v2 style tweaks + ts * style: v2 style tweaks + ts * fix: add selected and next information to EventTimer * style: v2 style tweaks + ts * style: v2 style tweaks + ts * style: v2 style tweaks + ts * style: v2 style tweaks + ts * refactor: extract logic * chore: upgrade build dependencies * chore: folder structure refactor * fix: issue with dependency path in electron * chore: update version in demo db * v2: refactor (#264) * chore: upgrade dependencies * chore: remove unused * fix: issue with missing index data * fix: discrepancy on counting events * fix: swapped classes * fix: prevent attempting load in empty list * chore: cleanup completed * chore: remove unused * refactor: convert to typescript * refactor: migrate to new endpoints * refactor: convert to typescript * fix: prevent issue with undefined process * fix: small code smells * fix: issue with missing version variable on build * refactor: configure retries on data fetching * style: design review * fix: prevent cursor out of range * lint: react query linting * style: checkbox styles * v2 event editor (#265) * style: add cursor indicator in all blocks * style: prevent reflows on width * style: harmonise white range * ux: focus elements on cursor nav * ux: prevent focus on indicators * refactor: convert to typescript * fix: missing dependency * chore: add linter rules for dependency arrays * style: style editable component * style: tweak input styles * style: tweak switch styles * style: style tweaks * V2 sentry (#267) * chore: add sentry to frontend * chore: add sentry to server * chore: report only in production * chore: add sentry source maps * v2 alpha 3 (#272) * style: correct background colours * chore: add folder resolutions to vite * refactor: add auto refetch to HTTP APIs * fix: view settings override endpoint * refactor: memoize callbacks * fix: reorder reaching wrong data adapter * refactor: memoize callbacks * style: presentation cleanup * fix(delete): prevent flow with deleted event in playback * refactor: convert to typescript * refactor: small fixes and typescript conversion * ux: improve feedback on local changes * refactor: cleanup props * v2 event timer (#274) * lint: cleanup unused * refactor: rename component to avoid conflict * style: gap in element row * refactor: rename playstate -> playback * refactor: cleanup usages of timer and prepare integration manager * style: re-arrange button order * refactor: improve event loading * feat(timer-service): hot reload * fix: issue with duration input * chore: cleanup debug * refactor: resolve poll from runtime store * refactor: cleanup merge * refactor: small improvements in timer hot-reload * v2: views (#278) * config(sentry): instrumentation only in production * chore: upgrade deps * refactor: simplify and convert to ts * refactor: composition and styles * chore: remove deprecated deps * ux: close menu on click outside * style: small tweaks and clarifications * refactor: retire PiP view * ux: small tweaks * style: cleanup deprecated styles * chore: remove unused * refactor: remove usages of deprecated fields and improve null timer presentation * refactor: improve composition of countdown * style: cleanup overridable styles * ux: show event overtime status * style: correct logic in paused timers * v2: roll (#280) * ux: delete flow * style: small tweaks in interface * refactor: gracefully quit on error * fix: logic around updating events * chore: cleanup dictionary * refactor: improve DX on creating aux files * fix: safe destructure function return * refactor: safe handling of falsy timer values * fix: improve ux on stopping roll mode * chore: upgrade deps * feat: roll mode * refactor: remove unused * V2 monorepo (#285) * refactor(project structure): UI * refactor(project structure): extract utilities * refactor(project structure): remove unused * refactor(project structure): electron * refactor(project structure): server refactor: migrate to vitest refactor: monorepo config * refactor: extract application menu * refactor: exit process * refactor: extract tray menu * chore: electron build * Added Seconds in studio clock #282 --------- Co-authored-by: Fabian Posenau --------- Co-authored-by: Fabian Posenau Co-authored-by: Fabian Posenau * Fix: #279 End Message in Minimal Timer (#286) * fix: Minimal View #279 end message --------- Co-authored-by: Fabian Posenau * hotfix: resolve data directory (#288) * Feature/#276/qrcodes (#289) * bugfix: wrong format when on 12h format * update: website link in placeholder --------- Co-authored-by: Fabian Posenau Co-authored-by: cv <34649812+cpvalente@users.noreply.github.com> * V2 types (#291) * V2 integration (#293) * feat: integrations and lifecycles * refactor: prevent issues with start order * V2 fix offline (#294) * fix: resolve path to UI build in dev * fix: configure offline fetching * V2 fix socket (#296) * refactor: rename timer endpoint * refactor: typescript * refactor: rename eventData and viewSettings * refactor: message manager uses event store * style: alpha4 style tweaks (#299) * fix: backgroundcolor for .blockNotes (#300) Co-authored-by: Fabian Posenau * Feat/countdown style (#290) * feat: Countdown Style --------- Co-authored-by: Fabian Posenau Co-authored-by: cv <34649812+cpvalente@users.noreply.github.com> Co-authored-by: Fabian Posenau <19673098+kellhogs@users.noreply.github.com> * fix: wrong parameter (#302) Co-authored-by: Fabian Posenau * V2 fix timer (#304) * Feat/update check (#303) * feat: show latest version in settings modal --------- Co-authored-by: Fabian Posenau * improve time input (#307) * add the ability to parse time like 2h20m --------- Co-authored-by: Fabian Posenau * V2 ws store (#310) * Update TimerService.ts * refactor: message service publishes to store * refactor: several type improvements * V2 ws store wss (#309) * refactor: shared logging types * refactor: simplify message service consumption * refactor: create discrete logging system * refactor: move socket.io > websocket * Feat/end action (#308) * feat: end action --------- Co-authored-by: Fabian Posenau Co-authored-by: cv <34649812+cpvalente@users.noreply.github.com> Co-authored-by: Fabian Posenau <19673098+kellhogs@users.noreply.github.com> * V2 osc (#313) * chore: upgrade relevant deps * fix: electron app to tray * chore: cleanup dictionary * feat: handle several messages in a event * ux: disable irrelevant buttons in browser * feat: parse and validate subscriptions * feat: create UI for OSC Integration * fix: cleanup logger behaviour * feat: allow OSC settings to be changed at runtime * v2 alpha5 (#315) * fix: fetch in offline environments (#295) * add arm platforms to docker build --------- Co-authored-by: Fabian Posenau * fix: docker build (#298) Co-authored-by: Fabian Posenau * Timer: fix too many renders error when using ?progress (#305) * ux: remove duplicate showing of selected event * several small fixes and UX improvements --------- Co-authored-by: Fabian Posenau Co-authored-by: Fabian Posenau Co-authored-by: Marks Polakovs * V2 docker (#312) * Create docker-ci.yml * docker build * add build app * path changes * delete double workflow * update docker run template * cleanup * resolve wierd path issue * wrong path * again wrong path * rename docker releases * move styles population and change to function call * re-add old build pipeline * rename buld file * feractor init function * refactor: startDb to initAssets * refactor: startDB to initAssets * fix: docker.cjs building whole app * fix: docker environment * update docker paths * update: build command * cleanup * cleanup: commented code --------- Co-authored-by: Fabian Posenau * v2 lazy rundown (#317) * chore: update related deps * refactor: memoise entrypoints * refactor: store selectors * refactor: improve component performance * chore: remove unused dependencies * refactor: improve component dnd * V2 build (#319) * chore: build pipeline for v2 * chore: run unit tests * chore: configure sentry build * Update test_v2.yml * Update test_v2.yml * V2 e2e (#320) * chore: cleanup handling of a bad read * chore: configure e2e testing * chore: version bump * V2 align (#321) * fix: fetch in offline environments (#295) * Add arm platforms to docker build (#297) * add arm platforms to docker build --------- Co-authored-by: Fabian Posenau * fix: docker build (#298) Co-authored-by: Fabian Posenau * Timer: fix too many renders error when using ?progress (#305) * Timer: fix too many renders error when using ?progress * version bump (#314) * style: small tweaks * fix: prevent actions in roll mode * chore: update external assets * style: show shortcuts in quick blocks * refactor: revert optimisations on callbacks * fun: industry dictionary * style: indicators for event features --------- Co-authored-by: Fabian Posenau Co-authored-by: Fabian Posenau Co-authored-by: Marks Polakovs * refactor: ensure start order (#322) * Update build_docker_v2.yml * V2 fix roll (#323) * chore: profile node * fix: always roll * Add translations for views (#325) (#328) * Add translations for views (#325) --------- Co-authored-by: Kevin <60135953+kev-ac@users.noreply.github.com> * feat: notify ws clients on rundown changes (#327) * V2 beta1 (#326) * style: labels on added time * style: remove mentions of PiP * refactor: unify usage of ms for timers * refactor: create events with 0 duration * style: several small tweaks * refactor: keep block when applying delays * feat: blocks have titles * style: improvements in time entry warnings * style: override progress bar styles * style: prevent overflow * feat: show character count in editor * refactor: provide initial payload * refactor: lower test boundary * refactor: get colour from swatches * style: rename title block * chore: version bump * style: fix info scroll * refactor: performance tweaks to event editor * chore: upgrade deps * refactor: prevent iterating on undefined * style: small style tweaks * fix: close editor on event delete * refactor: improve performance on EventBlock * style: small tweaks on blocks * chore: upgrade deps * chore: upgrade deps * style: ensure events are always visible * Fix/events enpoint (#329) * fix: sentry hangs node process * add onClick handler (#335) Co-authored-by: Fabian Posenau * fix docker on different port (#337) Co-authored-by: Fabian Posenau * V2 beta3 (#338) * chore: upgrade local build documentation * style: keep scrolling event in screen * feat: delay is time entry * refactor: remove unused * refactor: remove unused * refactor: batch store updates * refactor: virtually remove cap on events * refactor: style and behaviour tweaks to event block * style: tweaks on schedules * chore: remove sentry from server * style: reorder menu * chore: update docs * fix: resolve to static port in dev mode * V2 fix delay (#340) * fix: avoid modifying original objects * refactor: serve react as compressed br (#339) * refactor: changes in time input * V2 e2e playwright (#343) * test: create utility for uploading test-db * chore: upgrade deps * refactor: remove unused functions * chore: create testing boilerplate * test: upload showfile * refactor: parse time input (#351) * chore: vite upgrade (#354) * chore: upgrade vite * feat: edit mode (#344) * style: add mode selection to menu * style: rename rundown functions * feat: edit mode * fix: osc modal (#352) * refactor: parse time input * fix: form dirty flag on dynamic elements * style: cuesheet block (#355) * style: cuesheet show block title * style: cuesheet show full delay string * v2 about (#362) * chore: remove unused assets * feat: about ontime * refactor: cleanup unused * v2 beta 4 (#361) * ux: rename end action * chore: update demo db * style: tweaks on extracted rundown * chore: prevent console logs in production code * feat: go mode * style: remove window size limits * style: rename delete action * style: small tweaks on icons * fix: style override on params * chore: update test db * refactor: small code quality improvements * refactor: prevent circular imports * fix v2 roll timer (#363) * fix: roll update skips elapsed time * refactor: remove unused data * style: fix style in roll state * ux: content aware playback (#364) * v2 beta 4 bump (#367) * chore: update links to documentation * chore: version bump * Feature: quick start (#369) * feat: quick start modal * refactor: end message is part of view settings * refactor: small tweaks and type improvements * Feat/timer/stylechange (#341) * feat: multi color progress bar * add color support to minimal timer Co-Authored-By: Fabian Posenau <19673098+kellhogs@users.noreply.github.com> --------- Co-authored-by: Fabian Posenau Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Co-authored-by: Fabian Posenau <19673098+kellhogs@users.noreply.github.com> * v2 beta5 modals (#377) * refactor: folder structure * style: modal wrapper * feat: add nordic translations * v2 beta 5 (#375) * chore: update documentation links * fix: sentry has no access to error context * style: clarify event history * fix: issue with clipboard write in safari * style: clarify event history * refactor: improvements to follow logic in rundown * refactor: improvements in go mode * several style tweaks and small improvements * Ux language (#378) * ux: language from menu * feat: add extra support for languages german portuguese spanish * refactor: type improvements * v2 beta6 (#379) * feat: operator key * chore: update demo * chore: version bump * fix: prevent stale keys * refactor: add new fields to validation * style: tweaks to modal arrangement * refactor: prevent parsing http * ux: click anywhere in event to edit * refactor: performance improvements to time input * refactor: performance improvements menu * V2 beta 6 (#381) * fix: fetch in offline environments (#295) * Add arm platforms to docker build (#297) * add arm platforms to docker build --------- Co-authored-by: Fabian Posenau * fix: docker build (#298) Co-authored-by: Fabian Posenau * Timer: fix too many renders error when using ?progress (#305) * Timer: fix too many renders error when using ?progress * version bump (#314) * chore: remove unused assets * refactor: improve rundown loading time * style: rename project file * chore: update demo files * refactor: improve loading time * chore: upgrade upload packages * refactor: modal redesign and ux improvements * refactor: type and ux improvements on translations * refactor: prevent flash on suspense * refactor: remove unnecessary import * chore: update tests * refactor: cleanup imports * fix: prevent flash on suspense --------- Co-authored-by: Fabian Posenau Co-authored-by: Fabian Posenau Co-authored-by: Marks Polakovs * style views (#390) * style: animate transition from left side * refactor: improve schedule relationship * refactor: prevent passing unhandled value * style: remove inner radius in borders --------- Co-authored-by: Fabian Posenau Co-authored-by: Fabian Posenau Co-authored-by: Fabian Posenau <19673098+kellhogs@users.noreply.github.com> Co-authored-by: Marks Polakovs Co-authored-by: Kevin <60135953+kev-ac@users.noreply.github.com> --- .deepsource.toml | 1 - .eslintrc | 32 +- .github/{ => aux-images}/02_screentypes.png | Bin .github/{ => aux-images}/app.jpg | Bin .github/{ => aux-images}/dockerhub.png | Bin .github/{ => aux-images}/linux-download.png | Bin .github/{ => aux-images}/mac-download.png | Bin .github/{ => aux-images}/social-preview.png | Bin .github/{ => aux-images}/win-download.png | Bin .github/workflows/build.yml | 58 +- .github/workflows/build_docker_v2.yml | 56 + .github/workflows/build_v2.yml | 106 + .github/workflows/codeql-analysis.yml | 70 - .github/workflows/ontime_cy.yml | 34 +- .github/workflows/test_v2.yml | 76 + .gitignore | 50 +- .nvmrc | Bin 0 -> 22 bytes .prettierrc | 6 +- DEVELOPMENT.md | 69 + Dockerfile | 31 +- README.md | 152 +- {client => apps/client}/.eslintignore | 0 {client => apps/client}/.eslintrc | 18 +- apps/client/.prettierrc | 8 + {client => apps/client}/.stylelintrc | 0 {client => apps/client}/index.html | 2 +- apps/client/package.json | 99 + .../client}/public/android-chrome-192x192.png | Bin .../client}/public/android-chrome-512x512.png | Bin .../client}/public/apple-touch-icon.png | Bin .../client}/public/favicon-16x16.png | Bin .../client}/public/favicon-32x32.png | Bin {client => apps/client}/public/favicon.ico | Bin {client => apps/client}/public/logo192.png | Bin {client => apps/client}/public/logo512.png | Bin {client => apps/client}/public/manifest.json | 0 {client => apps/client}/public/robots.txt | 0 .../client}/public/site.webmanifest | 0 client/src/App.jsx => apps/client/src/App.tsx | 52 +- apps/client/src/AppRouter.tsx | 121 + .../client}/src/__mocks__/QueryClient.mock.js | 0 apps/client/src/appConstants.ts | 22 + .../src/assets/fonts/digital-7.monoitalic.ttf | Bin .../client}/src/assets/images/empty.svg | 0 apps/client/src/assets/images/ontime-logo.svg | 21 + apps/client/src/common/api/apiConstants.ts | 24 + .../client/src/common/api/eventDataApi.ts | 9 +- apps/client/src/common/api/eventsApi.ts | 75 + apps/client/src/common/api/ontimeApi.ts | 175 + .../common/components/buttons/EnableBtn.jsx | 2 +- .../components/buttons/PauseIconBtn.tsx | 20 +- .../components/buttons/PublicIconBtn.jsx | 3 +- .../common/components/buttons/QuitIconBtn.tsx | 69 +- .../common/components/buttons/RollIconBtn.jsx | 7 +- .../components/buttons/StartIconBtn.jsx | 3 +- .../components/buttons/TooltipActionBtn.tsx | 16 +- .../components/buttons/TransportIconBtn.jsx | 3 +- .../components/buttons/UnloadIconBtn.jsx | 3 +- .../collapse-bar/CollapseBar.module.scss | 24 + .../components/collapse-bar/CollapseBar.tsx | 20 + .../common/components/copy-tag/CopyTag.tsx | 32 + .../error-boundary}/ErrorBoundary.jsx | 39 +- .../error-boundary}/ErrorBoundary.module.scss | 8 +- .../input/auto-text-area/AutoTextArea.tsx | 33 + .../components/input/colour-input/Swatch.tsx | 26 + .../colour-input/SwatchSelect.module.scss | 24 + .../input/colour-input/SwatchSelect.tsx | 50 + .../input/delay-input/DelayInput.module.scss | 24 + .../input/delay-input/DelayInput.tsx | 134 + .../popover-picker/PopoverPicker.module.scss | 19 + .../input/popover-picker/PopoverPicker.tsx | 35 + .../components/input/text-input/TextInput.tsx | 56 + .../input/text-input/useReactiveTextInput.tsx | 86 + .../input/time-input/TimeInput.module.scss | 37 + .../components/input/time-input/TimeInput.tsx | 206 + .../MultiPartProgressBar.scss | 50 + .../MultiPartProgressBar.tsx | 33 + .../NavigationMenu.module.scss | 93 + .../navigation-menu/NavigationMenu.tsx | 111 + .../components/progress-bar/ProgressBar.scss | 22 + .../components/progress-bar/ProgressBar.tsx | 22 + .../components/protect-route/PinPage.tsx | 64 + .../protect-route}/ProtectRoute.module.scss | 14 +- .../components/protect-route/ProtectRoute.tsx | 38 + .../common/components/schedule/Schedule.scss | 71 + .../common/components/schedule/Schedule.tsx | 48 + .../components/schedule/ScheduleContext.tsx | 84 + .../components/schedule/ScheduleItem.tsx | 45 + .../components/schedule/ScheduleNav.tsx | 24 + .../common/components/state/Empty.module.scss | 17 + .../src/common/components/state/Empty.tsx | 19 + .../timer-display/TimerDisplay.scss | 15 + .../components/timer-display/TimerDisplay.tsx | 34 + .../components/title-card/TitleCard.scss | 36 + .../components/title-card/TitleCard.tsx | 28 + apps/client/src/common/context/AppContext.tsx | 81 + .../common/context/TableSettingsContext.jsx | 0 .../src/common/hooks-query/useAliases.ts | 19 + .../src/common/hooks-query/useEventData.ts | 20 + apps/client/src/common/hooks-query/useInfo.ts | 20 + .../src/common/hooks-query/useOscSettings.ts | 31 + .../src/common/hooks-query/useRundown.ts | 19 + .../src/common/hooks-query/useSettings.ts | 20 + .../src/common/hooks-query/useUserFields.ts | 20 + .../src/common/hooks-query/useViewSettings.ts | 20 + .../hooks/__tests__/useClickOutside.test.ts | 46 + .../src/common/hooks/useClickOutside.ts | 26 + .../src/common/hooks/useElectronEvent.ts | 3 +- .../client/src/common/hooks/useEventAction.ts | 346 + .../client}/src/common/hooks/useFitText.ts | 0 .../client}/src/common/hooks/useFullscreen.js | 20 +- .../client}/src/common/hooks/useInterval.js | 0 apps/client/src/common/hooks/useKeyDown.ts | 18 + .../src/common/hooks/useLocalStorage.ts | 53 + .../src/common/hooks/useRuntimeStylesheet.js | 4 +- apps/client/src/common/hooks/useSocket.ts | 105 + apps/client/src/common/models/Alias.ts | 7 + apps/client/src/common/models/EventData.ts | 9 + apps/client/src/common/models/Http.ts | 26 + apps/client/src/common/models/Info.ts | 19 + .../src/common/models/OntimeSettings.ts | 11 + apps/client/src/common/models/OntimeVars.ts | 30 + apps/client/src/common/models/OscSettings.ts | 23 + .../src/common/models/TimeManager.type.ts | 18 + apps/client/src/common/models/UserFields.ts | 14 + apps/client/src/common/models/Util.type.ts | 1 + .../client/src/common/models/View.types.ts | 5 +- .../src/common/models/ViewSettings.type.ts | 11 + apps/client/src/common/queryClient.ts | 9 + apps/client/src/common/stores/appModeStore.ts | 70 + apps/client/src/common/stores/localEvent.ts | 57 + apps/client/src/common/stores/logger.ts | 84 + apps/client/src/common/stores/runtime.ts | 74 + apps/client/src/common/stores/viewOptions.ts | 22 + .../__snapshots__/styleUtils.test.ts.snap | 5 + .../common/utils/__tests__/aliases.test.js | 14 +- .../common/utils/__tests__/dateConfig.test.js | 510 + .../utils/__tests__/eventsManager.test.js | 536 + .../common/utils/__tests__/getDelayTo.test.js | 0 .../src/common/utils/__tests__/math.test.js | 6 +- .../src/common/utils/__tests__/regex.test.ts | 27 + .../utils/__tests__/styleUtils.module.scss | 2 + .../common/utils/__tests__/styleUtils.test.ts | 15 + .../src/common/utils/__tests__/time.test.js | 6 +- .../utils/__tests__/timesManager.test.ts | 27 + .../client/src/common/utils/aliases.ts | 2 +- apps/client/src/common/utils/dateConfig.ts | 242 + .../client/src/common/utils/entryValidator.ts | 0 apps/client/src/common/utils/eventsManager.ts | 165 + .../client}/src/common/utils/getDelayTo.js | 0 .../client}/src/common/utils/linkUtils.js | 0 apps/client/src/common/utils/localStorage.ts | 9 + .../client/src/common/utils/math.ts | 2 +- apps/client/src/common/utils/regex.ts | 2 + apps/client/src/common/utils/socket.ts | 138 + apps/client/src/common/utils/styleUtils.ts | 29 + apps/client/src/common/utils/time.ts | 56 + .../client}/src/common/utils/timeConstants.js | 0 apps/client/src/common/utils/timesManager.ts | 55 + apps/client/src/common/utils/viewUtils.ts | 6 + apps/client/src/declarations/declaration.d.ts | 21 + apps/client/src/declarations/test.d.ts | 11 + apps/client/src/externals.ts | 4 + .../src/features/EditorFeatureWrapper.tsx | 13 + .../src/features/FeatureWrapper.module.scss | 8 + .../control/message/InputRow.module.scss | 17 + .../src/features/control/message/InputRow.tsx | 49 + .../message/MessageControl.module.scss | 23 + .../control/message/MessageControl.tsx | 53 + .../control/message/MessageControlExport.jsx | 24 + .../playback/PlaybackControl.module.scss | 4 + .../control/playback/PlaybackControl.tsx | 23 + .../control/playback/TimerControlExport.tsx | 24 + .../PlaybackButtons.module.scss | 43 + .../playback-buttons/PlaybackButtons.tsx | 106 + .../playback-timer/PlaybackTimer.module.scss | 65 +- .../playback/playback-timer/PlaybackTimer.tsx | 111 + .../playback/tap-button/TapButton.module.scss | 93 + .../control/playback/tap-button/TapButton.tsx | 31 + .../src/features/editors/Editor.module.scss | 92 +- apps/client/src/features/editors/Editor.tsx | 72 + .../src/features/editors/ProtectedEditor.tsx | 4 +- .../event-editor/EventEditor.module.scss | 117 + .../src/features/event-editor/EventEditor.tsx | 70 + .../event-editor/EventEditorExport.tsx | 42 + .../composite/CountedTextArea.tsx | 43 + .../composite/CountedTextInput.tsx | 43 + .../composite/EventEditorTimes.tsx | 149 + .../composite/EventEditorTitles.tsx | 50 + .../src/features/info/CollapsableInfo.tsx | 19 + .../client/src/features/info/Info.module.scss | 47 + apps/client/src/features/info/Info.tsx | 53 + apps/client/src/features/info/InfoExport.tsx | 24 + .../src/features/info/InfoLogger.module.scss | 54 + apps/client/src/features/info/InfoLogger.tsx | 130 + apps/client/src/features/info/InfoNif.tsx | 26 + apps/client/src/features/info/InfoTitles.tsx | 36 + .../src/features/menu/MenuBar.module.scss | 9 + apps/client/src/features/menu/MenuBar.tsx | 180 + .../src/features/menu/RundownMenu.module.scss | 4 + apps/client/src/features/menu/RundownMenu.tsx | 64 + .../src/features/modals/Modal.module.scss | 165 + .../client/src/features/modals/ModalInput.tsx | 29 + .../src/features/modals/ModalLink.module.scss | 20 + apps/client/src/features/modals/ModalLink.tsx | 29 + .../src/features/modals/ModalSplitInput.tsx | 29 + .../src/features/modals/ModalWrapper.tsx | 33 + .../src/features/modals/OntimeModalFooter.tsx | 37 + .../modals/about-modal/AboutModal.tsx | 68 + .../modals/about-modal/UpdateChecker.tsx | 72 + .../integration-modal/IntegrationModal.tsx | 46 + .../integration-modal/OscIntegration.tsx | 133 + .../modals/integration-modal/OscSettings.tsx | 166 + .../integration-modal/OscSubscriptionRow.tsx | 75 + .../src/features/modals/modalHelper.js | 3 +- .../modals/quick-start/QuickStart.tsx | 150 + .../modals/settings-modal/AliasesForm.tsx | 152 + .../modals/settings-modal/AppSettings.tsx | 123 + .../settings-modal/CuesheetSettings.tsx | 169 + .../modals/settings-modal/EditorSettings.tsx | 44 + .../modals/settings-modal/EventDataForm.tsx | 110 + .../settings-modal/InputMillisWithString.tsx | 35 + .../modals/settings-modal/ModalPinInput.tsx | 35 + .../settings-modal/SettingsModal.module.scss | 21 + .../modals/settings-modal/SettingsModal.tsx | 55 + .../settings-modal/ViewSettingsForm.tsx | 126 + .../upload-modal/UploadModal.module.scss | 91 + .../modals/upload-modal/UploadModal.tsx | 168 + .../features/modals}/upload-modal/utils.ts | 2 +- .../src/features/rundown/Rundown.module.scss | 21 +- apps/client/src/features/rundown/Rundown.tsx | 276 + .../src/features/rundown/RundownEmpty.tsx | 23 + .../src/features/rundown/RundownEntry.tsx | 190 + .../src/features/rundown/RundownExport.tsx | 22 + .../src/features/rundown/RundownWrapper.tsx | 20 + .../src/features/rundown/_blockMixins.scss | 44 + .../block-block/BlockBlock.module.scss | 26 + .../rundown/block-block/BlockBlock.tsx | 65 + .../rundown/common/EditableBlockTitle.tsx | 53 + .../rundown/common/TitleEditor.module.scss | 16 + .../delay-block/DelayBlock.module.scss | 24 + .../rundown/delay-block/DelayBlock.tsx | 86 + .../event-block/EventBlock.module.scss | 200 + .../rundown/event-block/EventBlock.tsx | 177 + .../rundown/event-block/EventBlockInner.tsx | 197 + .../event-block/composite/BlockActionMenu.tsx | 67 + .../composite/EventBlockPlayback.tsx | 125 + .../EventBlockProgressBar.module.scss | 26 + .../composite/EventBlockProgressBar.tsx | 26 + .../composite/EventBlockTimers.tsx | 114 + .../quick-add-block/QuickAddBlock.module.scss | 35 + .../rundown/quick-add-block/QuickAddBlock.tsx | 122 + .../src/features/table/OntimeTable.jsx | 11 +- .../src/features/table/ProtectedTable.tsx | 6 +- .../src/features/table/Table.module.scss | 70 +- .../src/features/table/TableHeader.jsx | 24 +- .../src/features/table/TableWrapper.jsx | 60 +- .../__snapshots__/utils.test.js.snap | 53 + .../features/table/__tests__/utils.test.js | 2 +- .../client}/src/features/table/columns.jsx | 9 +- .../client}/src/features/table/defaults.js | 0 .../table/tableElements/EditableCell.jsx | 7 +- .../table/tableElements/PlaybackIcon.tsx | 22 +- .../table/tableElements/SortableCell.jsx | 15 +- .../table/tableElements/TableSettings.jsx | 2 +- .../src/features/table/tableRows/BlockRow.jsx | 2 +- .../src/features/table/tableRows/DelayRow.jsx | 8 +- .../src/features/table/tableRows/EventRow.jsx | 33 +- .../client/src/features/table/tableUtils.js | 13 +- .../src/features/viewers/ViewWrapper.tsx | 114 + .../features/viewers/backstage/Backstage.scss | 151 + .../features/viewers/backstage/Backstage.tsx | 166 + .../src/features/viewers/clock/Clock.scss | 22 + .../src/features/viewers/clock/Clock.tsx | 26 +- .../src/features/viewers/common/animation.js | 0 .../features/viewers/common/viewerUtils.ts | 43 + .../features/viewers/countdown/Countdown.scss | 146 + .../features/viewers/countdown/Countdown.tsx | 143 + .../viewers/countdown/CountdownSelect.tsx | 47 + .../countdown/__tests__/Countdown.test.js | 47 +- .../viewers/countdown/countdown.helpers.ts | 67 + .../viewers/lower-thirds/LowerClean.jsx | 4 +- .../viewers/lower-thirds/LowerClean.scss | 7 +- .../viewers/lower-thirds/LowerLines.jsx | 4 +- .../viewers/lower-thirds/LowerLines.scss | 7 +- .../viewers/lower-thirds/LowerWrapper.jsx | 4 +- .../viewers/minimal-timer/MinimalTimer.scss | 43 +- .../viewers/minimal-timer/MinimalTimer.tsx | 104 +- .../src/features/viewers/public/Public.scss | 119 + .../src/features/viewers/public/Public.tsx | 125 + .../features/viewers/studio/StudioClock.jsx | 81 +- .../features/viewers/studio/StudioClock.scss | 19 +- .../src/features/viewers/timer/Timer.scss | 161 + .../src/features/viewers/timer/Timer.tsx | 169 + {client => apps/client}/src/index.scss | 24 +- apps/client/src/index.tsx | 26 + apps/client/src/ontimeConfig.ts | 6 + apps/client/src/setupTests.js | 3 + apps/client/src/theme/OntimeAlert.ts | 11 + {client => apps/client}/src/theme/_main.scss | 54 +- apps/client/src/theme/_mixins.scss | 34 + apps/client/src/theme/_ontimeColours.scss | 112 + apps/client/src/theme/_v2Styles.scss | 53 + .../client}/src/theme/_viewerCommon.scss | 0 apps/client/src/theme/_viewerDefs.scss | 28 + apps/client/src/theme/ontimeButton.ts | 86 + apps/client/src/theme/ontimeCheckbox.ts | 21 + apps/client/src/theme/ontimeEditable.ts | 14 + apps/client/src/theme/ontimeMenu.ts | 19 + apps/client/src/theme/ontimeModal.ts | 36 + apps/client/src/theme/ontimeRadio.ts | 27 + apps/client/src/theme/ontimeSelect.ts | 20 + apps/client/src/theme/ontimeSwitch.ts | 25 + apps/client/src/theme/ontimeTab.ts | 19 + apps/client/src/theme/ontimeTextInputs.ts | 54 + apps/client/src/theme/ontimeTooltip.ts | 12 + apps/client/src/theme/theme.ts | 117 + .../src/translation/Translation.types.ts | 0 .../src/translation/TranslationProvider.tsx | 54 + apps/client/src/translation/languages/de.ts | 18 + apps/client/src/translation/languages/en.ts | 16 + apps/client/src/translation/languages/es.ts | 18 + apps/client/src/translation/languages/no.ts | 18 + apps/client/src/translation/languages/pt.ts | 18 + apps/client/src/translation/languages/sv.ts | 18 + .../client/src/viewerConfig.ts | 5 +- {client => apps/client}/tsconfig.json | 14 +- apps/client/vite-env.d.ts | 1 + apps/client/vite.config.js | 47 + apps/electron/.eslintignore | 3 + apps/electron/.eslintrc | 13 + .../electron}/assets/background.png | Bin .../electron}/assets/background@2x.png | Bin {server => apps/electron}/assets/icon.icns | Bin {server => apps/electron}/assets/icon.ico | Bin {server => apps/electron}/assets/icon.png | Bin {server => apps/electron}/assets/logo.png | Bin .../electron}/assets/ontime-install.bmp | Bin .../electron}/assets/ontime-uninstall.bmp | Bin {server => apps/electron}/electron.config.js | 9 +- apps/electron/main.js | 246 + {server => apps/electron}/package.json | 75 +- apps/electron/src/menu/applicationMenu.js | 164 + apps/electron/src/menu/trayMenu.js | 19 + .../electron => apps/electron/src}/preload.js | 0 .../electron/src}/splash/splash.html | 0 apps/server/.eslintrc | 24 + apps/server/.prettierrc | 7 + apps/server/nodemon.json | 3 + apps/server/package.json | 59 + apps/server/src/adapters/IAdapter.ts | 3 + apps/server/src/adapters/OscAdapter.ts | 54 + apps/server/src/adapters/WebsocketAdapter.ts | 128 + apps/server/src/adapters/websocketAux.ts | 12 + apps/server/src/app.ts | 229 + apps/server/src/classes/Logger.ts | 104 + .../src/classes/data-provider/DataProvider.ts | 177 + .../data-provider/DataProvider.utils.ts | 37 + .../__test__/DataProvider.test.ts | 241 + .../src/classes/event-loader/EventLoader.ts | 434 + apps/server/src/config/config.js | 12 + .../src/controllers/eventDataController.ts | 30 + .../eventDataController.validate.ts | 15 + .../src/controllers/integrationController.ts | 193 + .../src/controllers/ontimeController.ts | 319 + .../controllers/ontimeController.validate.js | 90 + .../src/controllers/playbackController.js | 98 + .../src/controllers/rundownController.js | 99 + .../controllers/rundownController.validate.js | 39 + apps/server/src/external/styles/override.css | 17 + apps/server/src/index.ts | 20 + .../server}/src/models/aliasDefinition.js | 0 apps/server/src/models/dataModel.ts | 58 + apps/server/src/models/eventsDefinition.ts | 39 + apps/server/src/modules/loadDb.ts | 80 + apps/server/src/modules/loadStyles.ts | 23 + apps/server/src/preloaded-db/.keep | 0 apps/server/src/routes/eventDataRouter.js | 12 + .../server}/src/routes/ontimeRouter.js | 27 +- .../server}/src/routes/playbackRouter.js | 26 +- apps/server/src/routes/rundownRouter.js | 43 + apps/server/src/services/Clock.ts | 57 + apps/server/src/services/PlaybackService.ts | 227 + apps/server/src/services/RundownService.ts | 274 + apps/server/src/services/TimerService.ts | 374 + .../src/services/__tests__/rollUtils.test.js | 310 +- .../src/services/__tests__/timerUtils.test.ts | 143 + .../integration-service/IIntegration.ts | 24 + .../integration-service/IntegrationService.ts | 34 + .../integration-service/OscIntegration.ts | 130 + .../integrationUtils.test.ts | 96 + .../integration-service/integrationUtils.ts | 37 + .../message-service/MessageService.ts | 119 + apps/server/src/services/rollUtils.ts | 205 + apps/server/src/services/timerUtils.ts | 48 + apps/server/src/settings.ts | 1 + apps/server/src/setup.ts | 87 + apps/server/src/stores/EventStore.ts | 73 + .../src/utils/__tests__/eventUtils.test.js | 0 .../src/utils/__tests__/getRandomName.test.js | 6 +- .../src/utils/__tests__/parser.tests.js | 158 +- .../utils/__tests__/parserFunctions.test.js | 91 + .../src/utils/__tests__/parserUtils.tests.js | 92 + .../server}/src/utils/__tests__/time.test.js | 0 .../server}/src/utils/__tests__/url.test.js | 9 +- .../src/utils/__tests__/varUtils.test.ts | 11 + .../server}/src/utils/eventUtils.js | 0 apps/server/src/utils/fileManagement.js | 15 + apps/server/src/utils/getRandomName.js | 156 + .../server/src/utils/parser.ts | 172 +- apps/server/src/utils/parserFunctions.ts | 282 + .../server}/src/utils/parserUtils.js | 36 + apps/server/src/utils/routerUtils.js | 39 + {server => apps/server}/src/utils/time.js | 92 +- {server => apps/server}/src/utils/upload.js | 4 +- {server => apps/server}/src/utils/url.js | 0 apps/server/src/utils/varUtils.ts | 3 + apps/server/test-db/db.json | 280 + apps/server/tsconfig.json | 17 + apps/server/vite.config.ts | 7 + apps/test-db/db.json | 155 + client/package.json | 84 - client/src/AppRouter.jsx | 125 - client/src/appConstants.js | 18 - client/src/assets/images/logos/LOGO-120.png | Bin 6063 -> 0 bytes client/src/assets/images/logos/LOGO-128.png | Bin 6543 -> 0 bytes client/src/assets/images/logos/LOGO-144.png | Bin 7637 -> 0 bytes client/src/assets/images/logos/LOGO-152.png | Bin 8287 -> 0 bytes client/src/assets/images/logos/LOGO-180.png | Bin 10263 -> 0 bytes client/src/assets/images/logos/LOGO-192.png | Bin 11285 -> 0 bytes client/src/assets/images/logos/LOGO-384.png | Bin 30705 -> 0 bytes client/src/assets/images/logos/LOGO-512.png | Bin 48091 -> 0 bytes client/src/assets/images/logos/LOGO-72.png | Bin 3312 -> 0 bytes client/src/assets/images/logos/LOGO-96.png | Bin 4625 -> 0 bytes .../src/assets/images/logosbwa/LOGO-120.png | Bin 3457 -> 0 bytes .../src/assets/images/logosbwa/LOGO-128.png | Bin 3773 -> 0 bytes .../src/assets/images/logosbwa/LOGO-144.png | Bin 4445 -> 0 bytes .../src/assets/images/logosbwa/LOGO-152.png | Bin 4787 -> 0 bytes .../src/assets/images/logosbwa/LOGO-180.png | Bin 5750 -> 0 bytes .../src/assets/images/logosbwa/LOGO-192.png | Bin 6359 -> 0 bytes .../src/assets/images/logosbwa/LOGO-384.png | Bin 17686 -> 0 bytes .../src/assets/images/logosbwa/LOGO-512.png | Bin 28402 -> 0 bytes client/src/assets/images/logosbwa/LOGO-72.png | Bin 1930 -> 0 bytes client/src/assets/images/logosbwa/LOGO-96.png | Bin 2663 -> 0 bytes client/src/common/api/apiConstants.js | 33 - client/src/common/api/eventsApi.js | 54 - client/src/common/api/ontimeApi.js | 289 - client/src/common/api/playbackApi.js | 45 - client/src/common/atoms/LocalEventSettings.js | 20 - client/src/common/atoms/ViewerSettings.ts | 3 - .../components/buttons/ActionButtons.jsx | 58 - .../buttons/TooltipLoadingActionBtn.jsx | 36 - .../components/collapseBar/CollapseBar.jsx | 26 - .../collapseBar/CollapseBar.module.scss | 34 - .../components/countdown/TimerDisplay.jsx | 26 - .../components/countdown/TimerDisplay.scss | 22 - .../components/eventTimes/EventTimes.jsx | 70 - .../eventTimes/EventTimesVertical.jsx | 73 - .../common/components/eventTimes/Times.jsx | 50 - .../components/eventTimes/Times.module.scss | 6 - .../components/eventTimes/TimesDelayed.jsx | 59 - .../common/components/input/AutoTextArea.jsx | 27 - .../common/components/input/DelayInput.jsx | 62 - .../common/components/input/EditableText.jsx | 56 - .../components/input/EditableText.module.scss | 28 - .../common/components/input/EditableTimer.jsx | 97 - .../input/EditableTimer.module.scss | 17 - .../components/input/TimeInput.module.css | 9 - .../myProgressBar/MyProgressBar.jsx | 31 - .../myProgressBar/MyProgressBar.module.scss | 24 - client/src/common/components/nav/NavLogo.jsx | 119 - .../common/components/nav/NavLogo.module.scss | 41 - .../common/components/paginator/Paginator.jsx | 101 - .../components/paginator/Paginator.scss | 62 - .../common/components/paginator/TodayItem.jsx | 39 - .../components/protectRoute/ProtectRoute.jsx | 92 - client/src/common/components/state/Empty.jsx | 19 - .../common/components/state/Empty.module.scss | 27 - .../components/title-card/TitleCard.scss | 41 - .../components/title-card/TitleCard.tsx | 21 - .../components/title-side/TitleSide.jsx | 26 - .../components/title-side/TitleSide.scss | 61 - .../upload-modal/UploadModal.module.scss | 45 - .../components/upload-modal/UploadModal.tsx | 137 - client/src/common/context/AppContext.jsx | 56 - client/src/common/context/CollapseContext.jsx | 72 - client/src/common/context/CursorContext.jsx | 64 - client/src/common/context/LoggingContext.tsx | 135 - client/src/common/context/socketContext.tsx | 44 - client/src/common/hooks/useFetch.js | 18 - client/src/common/hooks/useLocalStorage.js | 37 - client/src/common/hooks/useMutateEvents.js | 38 - client/src/common/hooks/useSocketProvider.js | 239 - client/src/common/models/OntimeTypes.ts | 20 - .../common/utils/__tests__/dateConfig.test.js | 452 - .../utils/__tests__/eventsManager.test.js | 436 - client/src/common/utils/dateConfig.js | 140 - client/src/common/utils/entryValidator.js | 13 - client/src/common/utils/eventsManager.js | 88 - client/src/common/utils/generate_id.js | 8 - client/src/common/utils/time.js | 86 - client/src/declarations/declaration.d.ts | 10 - client/src/features/FeatureWrapper.jsx | 17 - .../src/features/FeatureWrapper.module.scss | 10 - .../control/__tests__/MessageControl.test.jsx | 42 - .../__tests__/PlaybackControl.test.jsx | 24 - .../src/features/control/message/InputRow.tsx | 63 - .../control/message/MessageControl.jsx | 61 - .../message/MessageControl.module.scss | 79 - .../control/message/MessageControlExport.jsx | 23 - .../features/control/playback/Playback.jsx | 43 - .../control/playback/PlaybackButtons.jsx | 42 - .../control/playback/PlaybackControl.jsx | 26 - .../control/playback/PlaybackTimer.jsx | 124 - .../control/playback/TimerControlExport.jsx | 23 - .../features/control/playback/Transport.jsx | 53 - .../editors/BlockBlock/BlockBlock.jsx | 47 - .../editors/BlockBlock/BlockBlock.module.scss | 57 - .../editors/DelayBlock/DelayBlock.jsx | 61 - .../editors/DelayBlock/DelayBlock.module.scss | 67 - client/src/features/editors/Editor.tsx | 61 - .../editors/EntryBlock/EntryBlock.jsx | 103 - .../editors/EntryBlock/EntryBlock.module.scss | 101 - .../editors/EventBlock/CollapsedBlock.jsx | 71 - .../editors/EventBlock/EventBlock.jsx | 79 - .../editors/EventBlock/EventBlock.module.scss | 221 - .../editors/EventBlock/ExpandedBlock.jsx | 111 - .../src/features/editors/list/EventList.jsx | 214 - .../features/editors/list/EventListExport.jsx | 30 - .../features/editors/list/EventListItem.jsx | 147 - .../editors/list/EventListWrapper.jsx | 350 - client/src/features/info/Info.jsx | 44 - client/src/features/info/Info.module.scss | 87 - client/src/features/info/InfoExport.jsx | 23 - client/src/features/info/InfoLogger.jsx | 147 - .../src/features/info/InfoLogger.module.scss | 89 - client/src/features/info/InfoNif.jsx | 41 - client/src/features/info/InfoTitle.jsx | 54 - .../src/features/info/__tests__/Info.test.jsx | 23 - client/src/features/menu/EventListMenu.jsx | 118 - .../features/menu/EventListMenu.module.css | 5 - .../src/features/menu/MenuActionButtons.jsx | 54 - client/src/features/menu/MenuBar.module.scss | 9 - client/src/features/menu/MenuBar.tsx | 145 - .../menu/__tests__/MenuActionButtons.test.jsx | 20 - .../features/menu/__tests__/MenuBar.test.tsx | 29 - client/src/features/modals/AliasesModal.jsx | 308 - .../src/features/modals/AppSettingsModal.jsx | 251 - .../features/modals/EventSettingsModal.jsx | 172 - .../modals/IntegrationSettingsModal.jsx | 360 - client/src/features/modals/ModalManager.jsx | 77 - client/src/features/modals/Modals.module.scss | 186 - .../src/features/modals/OscSettingsModal.jsx | 293 - .../src/features/modals/SubmitContainer.jsx | 35 - .../src/features/modals/TableOptionsModal.jsx | 133 - .../features/modals/ViewsSettingsModal.jsx | 124 - .../__snapshots__/utils.test.js.snap | 97 - client/src/features/viewers/ViewWrapper.jsx | 260 - .../features/viewers/backstage/Backstage.jsx | 169 - .../features/viewers/backstage/Backstage.scss | 152 - client/src/features/viewers/clock/Clock.scss | 23 - .../features/viewers/countdown/Countdown.jsx | 160 - .../features/viewers/countdown/Countdown.scss | 113 - .../viewers/countdown/countdown.helpers.js | 68 - .../viewers/picture-in-picture/Pip.jsx | 137 - .../viewers/picture-in-picture/Pip.scss | 136 - client/src/features/viewers/public/Public.jsx | 146 - .../src/features/viewers/public/Public.scss | 146 - client/src/features/viewers/timer/Timer.jsx | 162 - client/src/features/viewers/timer/Timer.scss | 138 - client/src/index.jsx | 15 - client/src/ontimeConfig.js | 3 - client/src/setupTests.js | 4 - client/src/theme/_mixins.scss | 28 - client/src/theme/_viewerDefs.scss | 29 - client/src/theme/_viewers.scss | 189 - client/src/theme/_viewers_mixins.scss | 189 - client/src/theme/theme.js | 50 - client/vite-env.d.ts | 1 - client/vite.config.js | 19 - client/yarn.lock | 5493 ---------- demo-db/db.json | 96 + docker-compose.yml | 9 +- e2e/.eslintrc | 13 + e2e/tests/000-smoke-tests.spec.ts | 42 + e2e/tests/001-view-navigation.spec.ts | 58 + e2e/tests/002-upload-showfile.spec.ts | 37 + .../features/201-message-control.spec.ts | 41 + e2e/tests/fixtures/test-db.json | 150 + e2e/tests/utils/uploadTestShowfile.ts | 25 + e2e/tsconfig.json | 6 + package.json | 50 + packages/types/.eslintrc | 15 + packages/types/package.json | 20 + .../types/src/definitions/DataModel.type.ts | 17 + .../types/src/definitions/EndAction.type.ts | 6 + .../types/src/definitions/TimerType.type.ts | 5 + .../types/src/definitions/core/Alias.type.ts | 5 + .../src/definitions/core/EventData.type.ts | 7 + .../src/definitions/core/OntimeEvent.type.ts | 52 + .../src/definitions/core/OscSettings.type.ts | 13 + .../src/definitions/core/Rundown.type.ts | 4 + .../src/definitions/core/Settings.type.ts | 11 + .../src/definitions/core/TimeFormat.type.ts | 1 + .../definitions/core/TimerLifecycle.type.ts | 10 + .../src/definitions/core/UserFields.type.ts | 13 + .../types/src/definitions/core/Views.type.ts | 9 + .../src/definitions/runtime/Logger.type.ts | 18 + .../runtime/MessageControl.type.ts | 4 + .../src/definitions/runtime/Playback.type.ts | 7 + .../src/definitions/runtime/Playlist.type.ts | 8 + .../definitions/runtime/RuntimeStore.type.ts | 22 + .../definitions/runtime/TimerState.type.ts | 17 + .../definitions/runtime/TitleBlock.type.ts | 10 + packages/types/src/index.ts | 69 + packages/utils/.eslintrc | 30 + packages/utils/.prettierrc | 8 + packages/utils/index.ts | 3 + packages/utils/package.json | 30 + .../utils/src/date-utils/formatFromMillis.ts | 11 + .../src/date-utils/millisToString.test.ts | 71 + .../utils/src/date-utils/millisToString.ts | 19 + .../utils/src/generate-id/generateId.test.ts | 6 +- packages/utils/src/generate-id/generateId.ts | 8 + packages/utils/tsconfig.json | 34 + packages/utils/vite.config.ts | 7 + playwright.config.ts | 51 + pnpm-lock.yaml | 9013 +++++++++++++++++ pnpm-workspace.yaml | 4 + server/.eslintrc | 21 - server/assets/images/empty.svg | 21 - server/assets/images/logos/LOGO-120.png | Bin 6063 -> 0 bytes server/assets/images/logos/LOGO-128.png | Bin 6543 -> 0 bytes server/assets/images/logos/LOGO-144.png | Bin 7637 -> 0 bytes server/assets/images/logos/LOGO-152.png | Bin 8287 -> 0 bytes server/assets/images/logos/LOGO-180.png | Bin 10263 -> 0 bytes server/assets/images/logos/LOGO-192.png | Bin 11285 -> 0 bytes server/assets/images/logos/LOGO-384.png | Bin 30705 -> 0 bytes server/assets/images/logos/LOGO-512.png | Bin 48091 -> 0 bytes server/assets/images/logos/LOGO-72.png | Bin 3312 -> 0 bytes server/assets/images/logos/LOGO-96.png | Bin 4625 -> 0 bytes server/assets/images/logosbwa/LOGO-120.png | Bin 3457 -> 0 bytes server/assets/images/logosbwa/LOGO-128.png | Bin 3773 -> 0 bytes server/assets/images/logosbwa/LOGO-144.png | Bin 4445 -> 0 bytes server/assets/images/logosbwa/LOGO-152.png | Bin 4787 -> 0 bytes server/assets/images/logosbwa/LOGO-180.png | Bin 5750 -> 0 bytes server/assets/images/logosbwa/LOGO-192.png | Bin 6359 -> 0 bytes server/assets/images/logosbwa/LOGO-384.png | Bin 17686 -> 0 bytes server/assets/images/logosbwa/LOGO-512.png | Bin 28402 -> 0 bytes server/assets/images/logosbwa/LOGO-72.png | Bin 1930 -> 0 bytes server/assets/images/logosbwa/LOGO-96.png | Bin 2663 -> 0 bytes server/cypress.json | 5 - server/cypress/integration/navigation.spec.js | 166 - server/cypress/plugins/index.js | 22 - server/cypress/support/commands.js | 25 - server/cypress/support/index.js | 20 - server/demo-db/db.json | 150 - server/jsconfig.json | 3 - server/main.js | 445 - server/src/app.js | 160 - .../src/classes/data-provider/DataProvider.js | 36 - .../__tests__/DataProvider.test.js | 97 - server/src/classes/timer/EventTimer.js | 1786 ---- server/src/classes/timer/Timer.js | 268 - .../timer/__tests__/eventtimer.test.js | 134 - .../src/classes/timer/__tests__/timer.test.js | 54 - server/src/classes/timer/classUtils.js | 217 - server/src/classes/timer/integrations/Http.js | 53 - server/src/classes/timer/integrations/Osc.js | 169 - .../timer/integrations/__tests__/Osc.test.js | 162 - server/src/config/config.js | 24 - server/src/controllers/OscController.js | 160 - server/src/controllers/eventController.js | 25 - server/src/controllers/eventsController.js | 392 - server/src/controllers/ontimeController.js | 328 - server/src/controllers/playbackController.js | 103 - server/src/external/styles/override.css | 11 - server/src/models/dataModel.js | 71 - server/src/models/eventsDefinition.js | 35 - server/src/modules/loadDb.js | 78 - server/src/package.json | 28 - .../src/routes/__tests__/eventRouter.test.js | 22 - .../src/routes/__tests__/eventsRouter.test.js | 67 - .../src/routes/__tests__/ontimeRouter.test.js | 109 - .../routes/__tests__/playbackRouter.tests.js | 198 - server/src/routes/eventRouter.js | 11 - server/src/routes/eventsRouter.js | 43 - server/src/run.js | 14 - server/src/settings.js | 1 - .../src/utils/__tests__/generate_id.test.js | 28 - server/src/utils/fileManagement.js | 42 - server/src/utils/generate_id.js | 8 - server/src/utils/getRandomName.js | 2864 ------ server/src/utils/parserUtils_v1.js | 265 - server/src/validation/ontimeValidator.js | 13 - server/src/yarn.lock | 1499 --- server/yarn.lock | 4857 --------- turbo.json | 21 + 698 files changed, 31750 insertions(+), 34069 deletions(-) rename .github/{ => aux-images}/02_screentypes.png (100%) rename .github/{ => aux-images}/app.jpg (100%) rename .github/{ => aux-images}/dockerhub.png (100%) rename .github/{ => aux-images}/linux-download.png (100%) rename .github/{ => aux-images}/mac-download.png (100%) rename .github/{ => aux-images}/social-preview.png (100%) rename .github/{ => aux-images}/win-download.png (100%) create mode 100644 .github/workflows/build_docker_v2.yml create mode 100644 .github/workflows/build_v2.yml delete mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/test_v2.yml create mode 100644 .nvmrc create mode 100644 DEVELOPMENT.md rename {client => apps/client}/.eslintignore (100%) rename {client => apps/client}/.eslintrc (88%) create mode 100644 apps/client/.prettierrc rename {client => apps/client}/.stylelintrc (100%) rename {client => apps/client}/index.html (94%) create mode 100644 apps/client/package.json rename {client => apps/client}/public/android-chrome-192x192.png (100%) rename {client => apps/client}/public/android-chrome-512x512.png (100%) rename {client => apps/client}/public/apple-touch-icon.png (100%) rename {client => apps/client}/public/favicon-16x16.png (100%) rename {client => apps/client}/public/favicon-32x32.png (100%) rename {client => apps/client}/public/favicon.ico (100%) rename {client => apps/client}/public/logo192.png (100%) rename {client => apps/client}/public/logo512.png (100%) rename {client => apps/client}/public/manifest.json (100%) rename {client => apps/client}/public/robots.txt (100%) rename {client => apps/client}/public/site.webmanifest (100%) rename client/src/App.jsx => apps/client/src/App.tsx (52%) create mode 100644 apps/client/src/AppRouter.tsx rename {client => apps/client}/src/__mocks__/QueryClient.mock.js (100%) create mode 100644 apps/client/src/appConstants.ts rename {client => apps/client}/src/assets/fonts/digital-7.monoitalic.ttf (100%) rename {client => apps/client}/src/assets/images/empty.svg (100%) create mode 100644 apps/client/src/assets/images/ontime-logo.svg create mode 100644 apps/client/src/common/api/apiConstants.ts rename client/src/common/api/eventApi.js => apps/client/src/common/api/eventDataApi.ts (59%) create mode 100644 apps/client/src/common/api/eventsApi.ts create mode 100644 apps/client/src/common/api/ontimeApi.ts rename {client => apps/client}/src/common/components/buttons/EnableBtn.jsx (94%) rename client/src/common/components/buttons/PauseIconBtn.jsx => apps/client/src/common/components/buttons/PauseIconBtn.tsx (61%) rename {client => apps/client}/src/common/components/buttons/PublicIconBtn.jsx (88%) rename client/src/common/components/buttons/QuitIconBtn.jsx => apps/client/src/common/components/buttons/QuitIconBtn.tsx (51%) rename {client => apps/client}/src/common/components/buttons/RollIconBtn.jsx (85%) rename {client => apps/client}/src/common/components/buttons/StartIconBtn.jsx (88%) rename {client => apps/client}/src/common/components/buttons/TooltipActionBtn.tsx (50%) rename {client => apps/client}/src/common/components/buttons/TransportIconBtn.jsx (88%) rename {client => apps/client}/src/common/components/buttons/UnloadIconBtn.jsx (87%) create mode 100644 apps/client/src/common/components/collapse-bar/CollapseBar.module.scss create mode 100644 apps/client/src/common/components/collapse-bar/CollapseBar.tsx create mode 100644 apps/client/src/common/components/copy-tag/CopyTag.tsx rename {client/src/common/components/errorBoundary => apps/client/src/common/components/error-boundary}/ErrorBoundary.jsx (60%) rename {client/src/common/components/errorBoundary => apps/client/src/common/components/error-boundary}/ErrorBoundary.module.scss (68%) create mode 100644 apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx create mode 100644 apps/client/src/common/components/input/colour-input/Swatch.tsx create mode 100644 apps/client/src/common/components/input/colour-input/SwatchSelect.module.scss create mode 100644 apps/client/src/common/components/input/colour-input/SwatchSelect.tsx create mode 100644 apps/client/src/common/components/input/delay-input/DelayInput.module.scss create mode 100644 apps/client/src/common/components/input/delay-input/DelayInput.tsx create mode 100644 apps/client/src/common/components/input/popover-picker/PopoverPicker.module.scss create mode 100644 apps/client/src/common/components/input/popover-picker/PopoverPicker.tsx create mode 100644 apps/client/src/common/components/input/text-input/TextInput.tsx create mode 100644 apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx create mode 100644 apps/client/src/common/components/input/time-input/TimeInput.module.scss create mode 100644 apps/client/src/common/components/input/time-input/TimeInput.tsx create mode 100644 apps/client/src/common/components/multi-part-progress-bar/MultiPartProgressBar.scss create mode 100644 apps/client/src/common/components/multi-part-progress-bar/MultiPartProgressBar.tsx create mode 100644 apps/client/src/common/components/navigation-menu/NavigationMenu.module.scss create mode 100644 apps/client/src/common/components/navigation-menu/NavigationMenu.tsx create mode 100644 apps/client/src/common/components/progress-bar/ProgressBar.scss create mode 100644 apps/client/src/common/components/progress-bar/ProgressBar.tsx create mode 100644 apps/client/src/common/components/protect-route/PinPage.tsx rename {client/src/common/components/protectRoute => apps/client/src/common/components/protect-route}/ProtectRoute.module.scss (63%) create mode 100644 apps/client/src/common/components/protect-route/ProtectRoute.tsx create mode 100644 apps/client/src/common/components/schedule/Schedule.scss create mode 100644 apps/client/src/common/components/schedule/Schedule.tsx create mode 100644 apps/client/src/common/components/schedule/ScheduleContext.tsx create mode 100644 apps/client/src/common/components/schedule/ScheduleItem.tsx create mode 100644 apps/client/src/common/components/schedule/ScheduleNav.tsx create mode 100644 apps/client/src/common/components/state/Empty.module.scss create mode 100644 apps/client/src/common/components/state/Empty.tsx create mode 100644 apps/client/src/common/components/timer-display/TimerDisplay.scss create mode 100644 apps/client/src/common/components/timer-display/TimerDisplay.tsx create mode 100644 apps/client/src/common/components/title-card/TitleCard.scss create mode 100644 apps/client/src/common/components/title-card/TitleCard.tsx create mode 100644 apps/client/src/common/context/AppContext.tsx rename {client => apps/client}/src/common/context/TableSettingsContext.jsx (100%) create mode 100644 apps/client/src/common/hooks-query/useAliases.ts create mode 100644 apps/client/src/common/hooks-query/useEventData.ts create mode 100644 apps/client/src/common/hooks-query/useInfo.ts create mode 100644 apps/client/src/common/hooks-query/useOscSettings.ts create mode 100644 apps/client/src/common/hooks-query/useRundown.ts create mode 100644 apps/client/src/common/hooks-query/useSettings.ts create mode 100644 apps/client/src/common/hooks-query/useUserFields.ts create mode 100644 apps/client/src/common/hooks-query/useViewSettings.ts create mode 100644 apps/client/src/common/hooks/__tests__/useClickOutside.test.ts create mode 100644 apps/client/src/common/hooks/useClickOutside.ts rename {client => apps/client}/src/common/hooks/useElectronEvent.ts (72%) create mode 100644 apps/client/src/common/hooks/useEventAction.ts rename {client => apps/client}/src/common/hooks/useFitText.ts (100%) rename {client => apps/client}/src/common/hooks/useFullscreen.js (52%) rename {client => apps/client}/src/common/hooks/useInterval.js (100%) create mode 100644 apps/client/src/common/hooks/useKeyDown.ts create mode 100644 apps/client/src/common/hooks/useLocalStorage.ts rename {client => apps/client}/src/common/hooks/useRuntimeStylesheet.js (92%) create mode 100644 apps/client/src/common/hooks/useSocket.ts create mode 100644 apps/client/src/common/models/Alias.ts create mode 100644 apps/client/src/common/models/EventData.ts create mode 100644 apps/client/src/common/models/Http.ts create mode 100644 apps/client/src/common/models/Info.ts create mode 100644 apps/client/src/common/models/OntimeSettings.ts create mode 100644 apps/client/src/common/models/OntimeVars.ts create mode 100644 apps/client/src/common/models/OscSettings.ts create mode 100644 apps/client/src/common/models/TimeManager.type.ts create mode 100644 apps/client/src/common/models/UserFields.ts create mode 100644 apps/client/src/common/models/Util.type.ts rename client/src/common/models/ViewTypes.ts => apps/client/src/common/models/View.types.ts (80%) create mode 100644 apps/client/src/common/models/ViewSettings.type.ts create mode 100644 apps/client/src/common/queryClient.ts create mode 100644 apps/client/src/common/stores/appModeStore.ts create mode 100644 apps/client/src/common/stores/localEvent.ts create mode 100644 apps/client/src/common/stores/logger.ts create mode 100644 apps/client/src/common/stores/runtime.ts create mode 100644 apps/client/src/common/stores/viewOptions.ts create mode 100644 apps/client/src/common/utils/__tests__/__snapshots__/styleUtils.test.ts.snap rename {client => apps/client}/src/common/utils/__tests__/aliases.test.js (71%) create mode 100644 apps/client/src/common/utils/__tests__/dateConfig.test.js create mode 100644 apps/client/src/common/utils/__tests__/eventsManager.test.js rename {client => apps/client}/src/common/utils/__tests__/getDelayTo.test.js (100%) rename {client => apps/client}/src/common/utils/__tests__/math.test.js (87%) create mode 100644 apps/client/src/common/utils/__tests__/regex.test.ts create mode 100644 apps/client/src/common/utils/__tests__/styleUtils.module.scss create mode 100644 apps/client/src/common/utils/__tests__/styleUtils.test.ts rename {client => apps/client}/src/common/utils/__tests__/time.test.js (83%) create mode 100644 apps/client/src/common/utils/__tests__/timesManager.test.ts rename client/src/common/utils/aliases.js => apps/client/src/common/utils/aliases.ts (94%) create mode 100644 apps/client/src/common/utils/dateConfig.ts rename client/src/features/viewers/timer/Timer.module.scss => apps/client/src/common/utils/entryValidator.ts (100%) create mode 100644 apps/client/src/common/utils/eventsManager.ts rename {client => apps/client}/src/common/utils/getDelayTo.js (100%) rename {client => apps/client}/src/common/utils/linkUtils.js (100%) create mode 100644 apps/client/src/common/utils/localStorage.ts rename client/src/common/utils/math.js => apps/client/src/common/utils/math.ts (79%) create mode 100644 apps/client/src/common/utils/regex.ts create mode 100644 apps/client/src/common/utils/socket.ts create mode 100644 apps/client/src/common/utils/styleUtils.ts create mode 100644 apps/client/src/common/utils/time.ts rename {client => apps/client}/src/common/utils/timeConstants.js (100%) create mode 100644 apps/client/src/common/utils/timesManager.ts create mode 100644 apps/client/src/common/utils/viewUtils.ts create mode 100644 apps/client/src/declarations/declaration.d.ts create mode 100644 apps/client/src/declarations/test.d.ts create mode 100644 apps/client/src/externals.ts create mode 100644 apps/client/src/features/EditorFeatureWrapper.tsx create mode 100644 apps/client/src/features/FeatureWrapper.module.scss create mode 100644 apps/client/src/features/control/message/InputRow.module.scss create mode 100644 apps/client/src/features/control/message/InputRow.tsx create mode 100644 apps/client/src/features/control/message/MessageControl.module.scss create mode 100644 apps/client/src/features/control/message/MessageControl.tsx create mode 100644 apps/client/src/features/control/message/MessageControlExport.jsx create mode 100644 apps/client/src/features/control/playback/PlaybackControl.module.scss create mode 100644 apps/client/src/features/control/playback/PlaybackControl.tsx create mode 100644 apps/client/src/features/control/playback/TimerControlExport.tsx create mode 100644 apps/client/src/features/control/playback/playback-buttons/PlaybackButtons.module.scss create mode 100644 apps/client/src/features/control/playback/playback-buttons/PlaybackButtons.tsx rename client/src/features/control/playback/PlaybackControl.module.scss => apps/client/src/features/control/playback/playback-timer/PlaybackTimer.module.scss (60%) create mode 100644 apps/client/src/features/control/playback/playback-timer/PlaybackTimer.tsx create mode 100644 apps/client/src/features/control/playback/tap-button/TapButton.module.scss create mode 100644 apps/client/src/features/control/playback/tap-button/TapButton.tsx rename {client => apps/client}/src/features/editors/Editor.module.scss (64%) create mode 100644 apps/client/src/features/editors/Editor.tsx rename client/src/features/editors/ProtectedEditor.jsx => apps/client/src/features/editors/ProtectedEditor.tsx (52%) create mode 100644 apps/client/src/features/event-editor/EventEditor.module.scss create mode 100644 apps/client/src/features/event-editor/EventEditor.tsx create mode 100644 apps/client/src/features/event-editor/EventEditorExport.tsx create mode 100644 apps/client/src/features/event-editor/composite/CountedTextArea.tsx create mode 100644 apps/client/src/features/event-editor/composite/CountedTextInput.tsx create mode 100644 apps/client/src/features/event-editor/composite/EventEditorTimes.tsx create mode 100644 apps/client/src/features/event-editor/composite/EventEditorTitles.tsx create mode 100644 apps/client/src/features/info/CollapsableInfo.tsx create mode 100644 apps/client/src/features/info/Info.module.scss create mode 100644 apps/client/src/features/info/Info.tsx create mode 100644 apps/client/src/features/info/InfoExport.tsx create mode 100644 apps/client/src/features/info/InfoLogger.module.scss create mode 100644 apps/client/src/features/info/InfoLogger.tsx create mode 100644 apps/client/src/features/info/InfoNif.tsx create mode 100644 apps/client/src/features/info/InfoTitles.tsx create mode 100644 apps/client/src/features/menu/MenuBar.module.scss create mode 100644 apps/client/src/features/menu/MenuBar.tsx create mode 100644 apps/client/src/features/menu/RundownMenu.module.scss create mode 100644 apps/client/src/features/menu/RundownMenu.tsx create mode 100644 apps/client/src/features/modals/Modal.module.scss create mode 100644 apps/client/src/features/modals/ModalInput.tsx create mode 100644 apps/client/src/features/modals/ModalLink.module.scss create mode 100644 apps/client/src/features/modals/ModalLink.tsx create mode 100644 apps/client/src/features/modals/ModalSplitInput.tsx create mode 100644 apps/client/src/features/modals/ModalWrapper.tsx create mode 100644 apps/client/src/features/modals/OntimeModalFooter.tsx create mode 100644 apps/client/src/features/modals/about-modal/AboutModal.tsx create mode 100644 apps/client/src/features/modals/about-modal/UpdateChecker.tsx create mode 100644 apps/client/src/features/modals/integration-modal/IntegrationModal.tsx create mode 100644 apps/client/src/features/modals/integration-modal/OscIntegration.tsx create mode 100644 apps/client/src/features/modals/integration-modal/OscSettings.tsx create mode 100644 apps/client/src/features/modals/integration-modal/OscSubscriptionRow.tsx rename {client => apps/client}/src/features/modals/modalHelper.js (87%) create mode 100644 apps/client/src/features/modals/quick-start/QuickStart.tsx create mode 100644 apps/client/src/features/modals/settings-modal/AliasesForm.tsx create mode 100644 apps/client/src/features/modals/settings-modal/AppSettings.tsx create mode 100644 apps/client/src/features/modals/settings-modal/CuesheetSettings.tsx create mode 100644 apps/client/src/features/modals/settings-modal/EditorSettings.tsx create mode 100644 apps/client/src/features/modals/settings-modal/EventDataForm.tsx create mode 100644 apps/client/src/features/modals/settings-modal/InputMillisWithString.tsx create mode 100644 apps/client/src/features/modals/settings-modal/ModalPinInput.tsx create mode 100644 apps/client/src/features/modals/settings-modal/SettingsModal.module.scss create mode 100644 apps/client/src/features/modals/settings-modal/SettingsModal.tsx create mode 100644 apps/client/src/features/modals/settings-modal/ViewSettingsForm.tsx create mode 100644 apps/client/src/features/modals/upload-modal/UploadModal.module.scss create mode 100644 apps/client/src/features/modals/upload-modal/UploadModal.tsx rename {client/src/common/components => apps/client/src/features/modals}/upload-modal/utils.ts (89%) rename client/src/features/editors/list/List.module.scss => apps/client/src/features/rundown/Rundown.module.scss (50%) create mode 100644 apps/client/src/features/rundown/Rundown.tsx create mode 100644 apps/client/src/features/rundown/RundownEmpty.tsx create mode 100644 apps/client/src/features/rundown/RundownEntry.tsx create mode 100644 apps/client/src/features/rundown/RundownExport.tsx create mode 100644 apps/client/src/features/rundown/RundownWrapper.tsx create mode 100644 apps/client/src/features/rundown/_blockMixins.scss create mode 100644 apps/client/src/features/rundown/block-block/BlockBlock.module.scss create mode 100644 apps/client/src/features/rundown/block-block/BlockBlock.tsx create mode 100644 apps/client/src/features/rundown/common/EditableBlockTitle.tsx create mode 100644 apps/client/src/features/rundown/common/TitleEditor.module.scss create mode 100644 apps/client/src/features/rundown/delay-block/DelayBlock.module.scss create mode 100644 apps/client/src/features/rundown/delay-block/DelayBlock.tsx create mode 100644 apps/client/src/features/rundown/event-block/EventBlock.module.scss create mode 100644 apps/client/src/features/rundown/event-block/EventBlock.tsx create mode 100644 apps/client/src/features/rundown/event-block/EventBlockInner.tsx create mode 100644 apps/client/src/features/rundown/event-block/composite/BlockActionMenu.tsx create mode 100644 apps/client/src/features/rundown/event-block/composite/EventBlockPlayback.tsx create mode 100644 apps/client/src/features/rundown/event-block/composite/EventBlockProgressBar.module.scss create mode 100644 apps/client/src/features/rundown/event-block/composite/EventBlockProgressBar.tsx create mode 100644 apps/client/src/features/rundown/event-block/composite/EventBlockTimers.tsx create mode 100644 apps/client/src/features/rundown/quick-add-block/QuickAddBlock.module.scss create mode 100644 apps/client/src/features/rundown/quick-add-block/QuickAddBlock.tsx rename {client => apps/client}/src/features/table/OntimeTable.jsx (96%) rename client/src/features/table/ProtectedTable.jsx => apps/client/src/features/table/ProtectedTable.tsx (70%) rename {client => apps/client}/src/features/table/Table.module.scss (84%) rename {client => apps/client}/src/features/table/TableHeader.jsx (83%) rename {client => apps/client}/src/features/table/TableWrapper.jsx (57%) create mode 100644 apps/client/src/features/table/__tests__/__snapshots__/utils.test.js.snap rename {client => apps/client}/src/features/table/__tests__/utils.test.js (97%) rename {client => apps/client}/src/features/table/columns.jsx (89%) rename {client => apps/client}/src/features/table/defaults.js (100%) rename {client => apps/client}/src/features/table/tableElements/EditableCell.jsx (85%) rename client/src/features/table/tableElements/PlaybackIcon.jsx => apps/client/src/features/table/tableElements/PlaybackIcon.tsx (74%) rename {client => apps/client}/src/features/table/tableElements/SortableCell.jsx (73%) rename {client => apps/client}/src/features/table/tableElements/TableSettings.jsx (97%) rename {client => apps/client}/src/features/table/tableRows/BlockRow.jsx (78%) rename {client => apps/client}/src/features/table/tableRows/DelayRow.jsx (53%) rename {client => apps/client}/src/features/table/tableRows/EventRow.jsx (56%) rename client/src/features/table/utils.js => apps/client/src/features/table/tableUtils.js (86%) create mode 100644 apps/client/src/features/viewers/ViewWrapper.tsx create mode 100644 apps/client/src/features/viewers/backstage/Backstage.scss create mode 100644 apps/client/src/features/viewers/backstage/Backstage.tsx create mode 100644 apps/client/src/features/viewers/clock/Clock.scss rename {client => apps/client}/src/features/viewers/clock/Clock.tsx (82%) rename {client => apps/client}/src/features/viewers/common/animation.js (100%) create mode 100644 apps/client/src/features/viewers/common/viewerUtils.ts create mode 100644 apps/client/src/features/viewers/countdown/Countdown.scss create mode 100644 apps/client/src/features/viewers/countdown/Countdown.tsx create mode 100644 apps/client/src/features/viewers/countdown/CountdownSelect.tsx rename {client => apps/client}/src/features/viewers/countdown/__tests__/Countdown.test.js (68%) create mode 100644 apps/client/src/features/viewers/countdown/countdown.helpers.ts rename {client => apps/client}/src/features/viewers/lower-thirds/LowerClean.jsx (96%) rename {client => apps/client}/src/features/viewers/lower-thirds/LowerClean.scss (73%) rename {client => apps/client}/src/features/viewers/lower-thirds/LowerLines.jsx (97%) rename {client => apps/client}/src/features/viewers/lower-thirds/LowerLines.scss (90%) rename {client => apps/client}/src/features/viewers/lower-thirds/LowerWrapper.jsx (95%) rename {client => apps/client}/src/features/viewers/minimal-timer/MinimalTimer.scss (55%) rename {client => apps/client}/src/features/viewers/minimal-timer/MinimalTimer.tsx (54%) create mode 100644 apps/client/src/features/viewers/public/Public.scss create mode 100644 apps/client/src/features/viewers/public/Public.tsx rename {client => apps/client}/src/features/viewers/studio/StudioClock.jsx (62%) rename {client => apps/client}/src/features/viewers/studio/StudioClock.scss (89%) create mode 100644 apps/client/src/features/viewers/timer/Timer.scss create mode 100644 apps/client/src/features/viewers/timer/Timer.tsx rename {client => apps/client}/src/index.scss (59%) create mode 100644 apps/client/src/index.tsx create mode 100644 apps/client/src/ontimeConfig.ts create mode 100644 apps/client/src/setupTests.js create mode 100644 apps/client/src/theme/OntimeAlert.ts rename {client => apps/client}/src/theme/_main.scss (71%) create mode 100644 apps/client/src/theme/_mixins.scss create mode 100644 apps/client/src/theme/_ontimeColours.scss create mode 100644 apps/client/src/theme/_v2Styles.scss rename {client => apps/client}/src/theme/_viewerCommon.scss (100%) create mode 100644 apps/client/src/theme/_viewerDefs.scss create mode 100644 apps/client/src/theme/ontimeButton.ts create mode 100644 apps/client/src/theme/ontimeCheckbox.ts create mode 100644 apps/client/src/theme/ontimeEditable.ts create mode 100644 apps/client/src/theme/ontimeMenu.ts create mode 100644 apps/client/src/theme/ontimeModal.ts create mode 100644 apps/client/src/theme/ontimeRadio.ts create mode 100644 apps/client/src/theme/ontimeSelect.ts create mode 100644 apps/client/src/theme/ontimeSwitch.ts create mode 100644 apps/client/src/theme/ontimeTab.ts create mode 100644 apps/client/src/theme/ontimeTextInputs.ts create mode 100644 apps/client/src/theme/ontimeTooltip.ts create mode 100644 apps/client/src/theme/theme.ts rename server/src/preloaded-db/.keep => apps/client/src/translation/Translation.types.ts (100%) create mode 100644 apps/client/src/translation/TranslationProvider.tsx create mode 100644 apps/client/src/translation/languages/de.ts create mode 100644 apps/client/src/translation/languages/en.ts create mode 100644 apps/client/src/translation/languages/es.ts create mode 100644 apps/client/src/translation/languages/no.ts create mode 100644 apps/client/src/translation/languages/pt.ts create mode 100644 apps/client/src/translation/languages/sv.ts rename client/src/common/components/nav/navigatorConstants.js => apps/client/src/viewerConfig.ts (77%) rename {client => apps/client}/tsconfig.json (80%) create mode 100644 apps/client/vite-env.d.ts create mode 100644 apps/client/vite.config.js create mode 100644 apps/electron/.eslintignore create mode 100644 apps/electron/.eslintrc rename {server => apps/electron}/assets/background.png (100%) rename {server => apps/electron}/assets/background@2x.png (100%) rename {server => apps/electron}/assets/icon.icns (100%) rename {server => apps/electron}/assets/icon.ico (100%) rename {server => apps/electron}/assets/icon.png (100%) rename {server => apps/electron}/assets/logo.png (100%) rename {server => apps/electron}/assets/ontime-install.bmp (100%) rename {server => apps/electron}/assets/ontime-uninstall.bmp (100%) rename {server => apps/electron}/electron.config.js (53%) create mode 100644 apps/electron/main.js rename {server => apps/electron}/package.json (57%) create mode 100644 apps/electron/src/menu/applicationMenu.js create mode 100644 apps/electron/src/menu/trayMenu.js rename {server/electron => apps/electron/src}/preload.js (100%) rename {server/electron => apps/electron/src}/splash/splash.html (100%) create mode 100644 apps/server/.eslintrc create mode 100644 apps/server/.prettierrc create mode 100644 apps/server/nodemon.json create mode 100644 apps/server/package.json create mode 100644 apps/server/src/adapters/IAdapter.ts create mode 100644 apps/server/src/adapters/OscAdapter.ts create mode 100644 apps/server/src/adapters/WebsocketAdapter.ts create mode 100644 apps/server/src/adapters/websocketAux.ts create mode 100644 apps/server/src/app.ts create mode 100644 apps/server/src/classes/Logger.ts create mode 100644 apps/server/src/classes/data-provider/DataProvider.ts create mode 100644 apps/server/src/classes/data-provider/DataProvider.utils.ts create mode 100644 apps/server/src/classes/data-provider/__test__/DataProvider.test.ts create mode 100644 apps/server/src/classes/event-loader/EventLoader.ts create mode 100644 apps/server/src/config/config.js create mode 100644 apps/server/src/controllers/eventDataController.ts create mode 100644 apps/server/src/controllers/eventDataController.validate.ts create mode 100644 apps/server/src/controllers/integrationController.ts create mode 100644 apps/server/src/controllers/ontimeController.ts create mode 100644 apps/server/src/controllers/ontimeController.validate.js create mode 100644 apps/server/src/controllers/playbackController.js create mode 100644 apps/server/src/controllers/rundownController.js create mode 100644 apps/server/src/controllers/rundownController.validate.js create mode 100644 apps/server/src/external/styles/override.css create mode 100644 apps/server/src/index.ts rename {server => apps/server}/src/models/aliasDefinition.js (100%) create mode 100644 apps/server/src/models/dataModel.ts create mode 100644 apps/server/src/models/eventsDefinition.ts create mode 100644 apps/server/src/modules/loadDb.ts create mode 100644 apps/server/src/modules/loadStyles.ts create mode 100644 apps/server/src/preloaded-db/.keep create mode 100644 apps/server/src/routes/eventDataRouter.js rename {server => apps/server}/src/routes/ontimeRouter.js (73%) rename {server => apps/server}/src/routes/playbackRouter.js (85%) create mode 100644 apps/server/src/routes/rundownRouter.js create mode 100644 apps/server/src/services/Clock.ts create mode 100644 apps/server/src/services/PlaybackService.ts create mode 100644 apps/server/src/services/RundownService.ts create mode 100644 apps/server/src/services/TimerService.ts rename server/src/classes/timer/__tests__/classUtils.test.js => apps/server/src/services/__tests__/rollUtils.test.js (64%) create mode 100644 apps/server/src/services/__tests__/timerUtils.test.ts create mode 100644 apps/server/src/services/integration-service/IIntegration.ts create mode 100644 apps/server/src/services/integration-service/IntegrationService.ts create mode 100644 apps/server/src/services/integration-service/OscIntegration.ts create mode 100644 apps/server/src/services/integration-service/integrationUtils.test.ts create mode 100644 apps/server/src/services/integration-service/integrationUtils.ts create mode 100644 apps/server/src/services/message-service/MessageService.ts create mode 100644 apps/server/src/services/rollUtils.ts create mode 100644 apps/server/src/services/timerUtils.ts create mode 100644 apps/server/src/settings.ts create mode 100644 apps/server/src/setup.ts create mode 100644 apps/server/src/stores/EventStore.ts rename {server => apps/server}/src/utils/__tests__/eventUtils.test.js (100%) rename {server => apps/server}/src/utils/__tests__/getRandomName.test.js (58%) rename {server => apps/server}/src/utils/__tests__/parser.tests.js (84%) create mode 100644 apps/server/src/utils/__tests__/parserFunctions.test.js create mode 100644 apps/server/src/utils/__tests__/parserUtils.tests.js rename {server => apps/server}/src/utils/__tests__/time.test.js (100%) rename {server => apps/server}/src/utils/__tests__/url.test.js (90%) create mode 100644 apps/server/src/utils/__tests__/varUtils.test.ts rename {server => apps/server}/src/utils/eventUtils.js (100%) create mode 100644 apps/server/src/utils/fileManagement.js create mode 100644 apps/server/src/utils/getRandomName.js rename server/src/utils/parser.js => apps/server/src/utils/parser.ts (72%) create mode 100644 apps/server/src/utils/parserFunctions.ts rename {server => apps/server}/src/utils/parserUtils.js (59%) create mode 100644 apps/server/src/utils/routerUtils.js rename {server => apps/server}/src/utils/time.js (75%) rename {server => apps/server}/src/utils/upload.js (92%) rename {server => apps/server}/src/utils/url.js (100%) create mode 100644 apps/server/src/utils/varUtils.ts create mode 100644 apps/server/test-db/db.json create mode 100644 apps/server/tsconfig.json create mode 100644 apps/server/vite.config.ts create mode 100644 apps/test-db/db.json delete mode 100644 client/package.json delete mode 100644 client/src/AppRouter.jsx delete mode 100644 client/src/appConstants.js delete mode 100644 client/src/assets/images/logos/LOGO-120.png delete mode 100644 client/src/assets/images/logos/LOGO-128.png delete mode 100644 client/src/assets/images/logos/LOGO-144.png delete mode 100644 client/src/assets/images/logos/LOGO-152.png delete mode 100644 client/src/assets/images/logos/LOGO-180.png delete mode 100644 client/src/assets/images/logos/LOGO-192.png delete mode 100644 client/src/assets/images/logos/LOGO-384.png delete mode 100644 client/src/assets/images/logos/LOGO-512.png delete mode 100644 client/src/assets/images/logos/LOGO-72.png delete mode 100644 client/src/assets/images/logos/LOGO-96.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-120.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-128.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-144.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-152.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-180.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-192.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-384.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-512.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-72.png delete mode 100644 client/src/assets/images/logosbwa/LOGO-96.png delete mode 100644 client/src/common/api/apiConstants.js delete mode 100644 client/src/common/api/eventsApi.js delete mode 100644 client/src/common/api/ontimeApi.js delete mode 100644 client/src/common/api/playbackApi.js delete mode 100644 client/src/common/atoms/LocalEventSettings.js delete mode 100644 client/src/common/atoms/ViewerSettings.ts delete mode 100644 client/src/common/components/buttons/ActionButtons.jsx delete mode 100644 client/src/common/components/buttons/TooltipLoadingActionBtn.jsx delete mode 100644 client/src/common/components/collapseBar/CollapseBar.jsx delete mode 100644 client/src/common/components/collapseBar/CollapseBar.module.scss delete mode 100644 client/src/common/components/countdown/TimerDisplay.jsx delete mode 100644 client/src/common/components/countdown/TimerDisplay.scss delete mode 100644 client/src/common/components/eventTimes/EventTimes.jsx delete mode 100644 client/src/common/components/eventTimes/EventTimesVertical.jsx delete mode 100644 client/src/common/components/eventTimes/Times.jsx delete mode 100644 client/src/common/components/eventTimes/Times.module.scss delete mode 100644 client/src/common/components/eventTimes/TimesDelayed.jsx delete mode 100644 client/src/common/components/input/AutoTextArea.jsx delete mode 100644 client/src/common/components/input/DelayInput.jsx delete mode 100644 client/src/common/components/input/EditableText.jsx delete mode 100644 client/src/common/components/input/EditableText.module.scss delete mode 100644 client/src/common/components/input/EditableTimer.jsx delete mode 100644 client/src/common/components/input/EditableTimer.module.scss delete mode 100644 client/src/common/components/input/TimeInput.module.css delete mode 100644 client/src/common/components/myProgressBar/MyProgressBar.jsx delete mode 100644 client/src/common/components/myProgressBar/MyProgressBar.module.scss delete mode 100644 client/src/common/components/nav/NavLogo.jsx delete mode 100644 client/src/common/components/nav/NavLogo.module.scss delete mode 100644 client/src/common/components/paginator/Paginator.jsx delete mode 100644 client/src/common/components/paginator/Paginator.scss delete mode 100644 client/src/common/components/paginator/TodayItem.jsx delete mode 100644 client/src/common/components/protectRoute/ProtectRoute.jsx delete mode 100644 client/src/common/components/state/Empty.jsx delete mode 100644 client/src/common/components/state/Empty.module.scss delete mode 100644 client/src/common/components/title-card/TitleCard.scss delete mode 100644 client/src/common/components/title-card/TitleCard.tsx delete mode 100644 client/src/common/components/title-side/TitleSide.jsx delete mode 100644 client/src/common/components/title-side/TitleSide.scss delete mode 100644 client/src/common/components/upload-modal/UploadModal.module.scss delete mode 100644 client/src/common/components/upload-modal/UploadModal.tsx delete mode 100644 client/src/common/context/AppContext.jsx delete mode 100644 client/src/common/context/CollapseContext.jsx delete mode 100644 client/src/common/context/CursorContext.jsx delete mode 100644 client/src/common/context/LoggingContext.tsx delete mode 100644 client/src/common/context/socketContext.tsx delete mode 100644 client/src/common/hooks/useFetch.js delete mode 100644 client/src/common/hooks/useLocalStorage.js delete mode 100644 client/src/common/hooks/useMutateEvents.js delete mode 100644 client/src/common/hooks/useSocketProvider.js delete mode 100644 client/src/common/models/OntimeTypes.ts delete mode 100644 client/src/common/utils/__tests__/dateConfig.test.js delete mode 100644 client/src/common/utils/__tests__/eventsManager.test.js delete mode 100644 client/src/common/utils/dateConfig.js delete mode 100644 client/src/common/utils/entryValidator.js delete mode 100644 client/src/common/utils/eventsManager.js delete mode 100644 client/src/common/utils/generate_id.js delete mode 100644 client/src/common/utils/time.js delete mode 100644 client/src/declarations/declaration.d.ts delete mode 100644 client/src/features/FeatureWrapper.jsx delete mode 100644 client/src/features/FeatureWrapper.module.scss delete mode 100644 client/src/features/control/__tests__/MessageControl.test.jsx delete mode 100644 client/src/features/control/__tests__/PlaybackControl.test.jsx delete mode 100644 client/src/features/control/message/InputRow.tsx delete mode 100644 client/src/features/control/message/MessageControl.jsx delete mode 100644 client/src/features/control/message/MessageControl.module.scss delete mode 100644 client/src/features/control/message/MessageControlExport.jsx delete mode 100644 client/src/features/control/playback/Playback.jsx delete mode 100644 client/src/features/control/playback/PlaybackButtons.jsx delete mode 100644 client/src/features/control/playback/PlaybackControl.jsx delete mode 100644 client/src/features/control/playback/PlaybackTimer.jsx delete mode 100644 client/src/features/control/playback/TimerControlExport.jsx delete mode 100644 client/src/features/control/playback/Transport.jsx delete mode 100644 client/src/features/editors/BlockBlock/BlockBlock.jsx delete mode 100644 client/src/features/editors/BlockBlock/BlockBlock.module.scss delete mode 100644 client/src/features/editors/DelayBlock/DelayBlock.jsx delete mode 100644 client/src/features/editors/DelayBlock/DelayBlock.module.scss delete mode 100644 client/src/features/editors/Editor.tsx delete mode 100644 client/src/features/editors/EntryBlock/EntryBlock.jsx delete mode 100644 client/src/features/editors/EntryBlock/EntryBlock.module.scss delete mode 100644 client/src/features/editors/EventBlock/CollapsedBlock.jsx delete mode 100644 client/src/features/editors/EventBlock/EventBlock.jsx delete mode 100644 client/src/features/editors/EventBlock/EventBlock.module.scss delete mode 100644 client/src/features/editors/EventBlock/ExpandedBlock.jsx delete mode 100644 client/src/features/editors/list/EventList.jsx delete mode 100644 client/src/features/editors/list/EventListExport.jsx delete mode 100644 client/src/features/editors/list/EventListItem.jsx delete mode 100644 client/src/features/editors/list/EventListWrapper.jsx delete mode 100644 client/src/features/info/Info.jsx delete mode 100644 client/src/features/info/Info.module.scss delete mode 100644 client/src/features/info/InfoExport.jsx delete mode 100644 client/src/features/info/InfoLogger.jsx delete mode 100644 client/src/features/info/InfoLogger.module.scss delete mode 100644 client/src/features/info/InfoNif.jsx delete mode 100644 client/src/features/info/InfoTitle.jsx delete mode 100644 client/src/features/info/__tests__/Info.test.jsx delete mode 100644 client/src/features/menu/EventListMenu.jsx delete mode 100644 client/src/features/menu/EventListMenu.module.css delete mode 100644 client/src/features/menu/MenuActionButtons.jsx delete mode 100644 client/src/features/menu/MenuBar.module.scss delete mode 100644 client/src/features/menu/MenuBar.tsx delete mode 100644 client/src/features/menu/__tests__/MenuActionButtons.test.jsx delete mode 100644 client/src/features/menu/__tests__/MenuBar.test.tsx delete mode 100644 client/src/features/modals/AliasesModal.jsx delete mode 100644 client/src/features/modals/AppSettingsModal.jsx delete mode 100644 client/src/features/modals/EventSettingsModal.jsx delete mode 100644 client/src/features/modals/IntegrationSettingsModal.jsx delete mode 100644 client/src/features/modals/ModalManager.jsx delete mode 100644 client/src/features/modals/Modals.module.scss delete mode 100644 client/src/features/modals/OscSettingsModal.jsx delete mode 100644 client/src/features/modals/SubmitContainer.jsx delete mode 100644 client/src/features/modals/TableOptionsModal.jsx delete mode 100644 client/src/features/modals/ViewsSettingsModal.jsx delete mode 100644 client/src/features/table/__tests__/__snapshots__/utils.test.js.snap delete mode 100644 client/src/features/viewers/ViewWrapper.jsx delete mode 100644 client/src/features/viewers/backstage/Backstage.jsx delete mode 100644 client/src/features/viewers/backstage/Backstage.scss delete mode 100644 client/src/features/viewers/clock/Clock.scss delete mode 100644 client/src/features/viewers/countdown/Countdown.jsx delete mode 100644 client/src/features/viewers/countdown/Countdown.scss delete mode 100644 client/src/features/viewers/countdown/countdown.helpers.js delete mode 100644 client/src/features/viewers/picture-in-picture/Pip.jsx delete mode 100644 client/src/features/viewers/picture-in-picture/Pip.scss delete mode 100644 client/src/features/viewers/public/Public.jsx delete mode 100644 client/src/features/viewers/public/Public.scss delete mode 100644 client/src/features/viewers/timer/Timer.jsx delete mode 100644 client/src/features/viewers/timer/Timer.scss delete mode 100644 client/src/index.jsx delete mode 100644 client/src/ontimeConfig.js delete mode 100644 client/src/setupTests.js delete mode 100644 client/src/theme/_mixins.scss delete mode 100644 client/src/theme/_viewerDefs.scss delete mode 100644 client/src/theme/_viewers.scss delete mode 100644 client/src/theme/_viewers_mixins.scss delete mode 100644 client/src/theme/theme.js delete mode 100644 client/vite-env.d.ts delete mode 100644 client/vite.config.js delete mode 100644 client/yarn.lock create mode 100644 demo-db/db.json create mode 100644 e2e/.eslintrc create mode 100644 e2e/tests/000-smoke-tests.spec.ts create mode 100644 e2e/tests/001-view-navigation.spec.ts create mode 100644 e2e/tests/002-upload-showfile.spec.ts create mode 100644 e2e/tests/features/201-message-control.spec.ts create mode 100644 e2e/tests/fixtures/test-db.json create mode 100644 e2e/tests/utils/uploadTestShowfile.ts create mode 100644 e2e/tsconfig.json create mode 100644 package.json create mode 100644 packages/types/.eslintrc create mode 100644 packages/types/package.json create mode 100644 packages/types/src/definitions/DataModel.type.ts create mode 100644 packages/types/src/definitions/EndAction.type.ts create mode 100644 packages/types/src/definitions/TimerType.type.ts create mode 100644 packages/types/src/definitions/core/Alias.type.ts create mode 100644 packages/types/src/definitions/core/EventData.type.ts create mode 100644 packages/types/src/definitions/core/OntimeEvent.type.ts create mode 100644 packages/types/src/definitions/core/OscSettings.type.ts create mode 100644 packages/types/src/definitions/core/Rundown.type.ts create mode 100644 packages/types/src/definitions/core/Settings.type.ts create mode 100644 packages/types/src/definitions/core/TimeFormat.type.ts create mode 100644 packages/types/src/definitions/core/TimerLifecycle.type.ts create mode 100644 packages/types/src/definitions/core/UserFields.type.ts create mode 100644 packages/types/src/definitions/core/Views.type.ts create mode 100644 packages/types/src/definitions/runtime/Logger.type.ts create mode 100644 packages/types/src/definitions/runtime/MessageControl.type.ts create mode 100644 packages/types/src/definitions/runtime/Playback.type.ts create mode 100644 packages/types/src/definitions/runtime/Playlist.type.ts create mode 100644 packages/types/src/definitions/runtime/RuntimeStore.type.ts create mode 100644 packages/types/src/definitions/runtime/TimerState.type.ts create mode 100644 packages/types/src/definitions/runtime/TitleBlock.type.ts create mode 100644 packages/types/src/index.ts create mode 100644 packages/utils/.eslintrc create mode 100644 packages/utils/.prettierrc create mode 100644 packages/utils/index.ts create mode 100644 packages/utils/package.json create mode 100644 packages/utils/src/date-utils/formatFromMillis.ts create mode 100644 packages/utils/src/date-utils/millisToString.test.ts create mode 100644 packages/utils/src/date-utils/millisToString.ts rename client/src/common/utils/__tests__/generate_id.test.js => packages/utils/src/generate-id/generateId.test.ts (81%) create mode 100644 packages/utils/src/generate-id/generateId.ts create mode 100644 packages/utils/tsconfig.json create mode 100644 packages/utils/vite.config.ts create mode 100644 playwright.config.ts create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml delete mode 100644 server/.eslintrc delete mode 100644 server/assets/images/empty.svg delete mode 100644 server/assets/images/logos/LOGO-120.png delete mode 100644 server/assets/images/logos/LOGO-128.png delete mode 100644 server/assets/images/logos/LOGO-144.png delete mode 100644 server/assets/images/logos/LOGO-152.png delete mode 100644 server/assets/images/logos/LOGO-180.png delete mode 100644 server/assets/images/logos/LOGO-192.png delete mode 100644 server/assets/images/logos/LOGO-384.png delete mode 100644 server/assets/images/logos/LOGO-512.png delete mode 100644 server/assets/images/logos/LOGO-72.png delete mode 100644 server/assets/images/logos/LOGO-96.png delete mode 100644 server/assets/images/logosbwa/LOGO-120.png delete mode 100644 server/assets/images/logosbwa/LOGO-128.png delete mode 100644 server/assets/images/logosbwa/LOGO-144.png delete mode 100644 server/assets/images/logosbwa/LOGO-152.png delete mode 100644 server/assets/images/logosbwa/LOGO-180.png delete mode 100644 server/assets/images/logosbwa/LOGO-192.png delete mode 100644 server/assets/images/logosbwa/LOGO-384.png delete mode 100644 server/assets/images/logosbwa/LOGO-512.png delete mode 100644 server/assets/images/logosbwa/LOGO-72.png delete mode 100644 server/assets/images/logosbwa/LOGO-96.png delete mode 100644 server/cypress.json delete mode 100644 server/cypress/integration/navigation.spec.js delete mode 100644 server/cypress/plugins/index.js delete mode 100644 server/cypress/support/commands.js delete mode 100644 server/cypress/support/index.js delete mode 100644 server/demo-db/db.json delete mode 100644 server/jsconfig.json delete mode 100644 server/main.js delete mode 100644 server/src/app.js delete mode 100644 server/src/classes/data-provider/DataProvider.js delete mode 100644 server/src/classes/data-provider/__tests__/DataProvider.test.js delete mode 100644 server/src/classes/timer/EventTimer.js delete mode 100644 server/src/classes/timer/Timer.js delete mode 100644 server/src/classes/timer/__tests__/eventtimer.test.js delete mode 100644 server/src/classes/timer/__tests__/timer.test.js delete mode 100644 server/src/classes/timer/classUtils.js delete mode 100644 server/src/classes/timer/integrations/Http.js delete mode 100644 server/src/classes/timer/integrations/Osc.js delete mode 100644 server/src/classes/timer/integrations/__tests__/Osc.test.js delete mode 100644 server/src/config/config.js delete mode 100644 server/src/controllers/OscController.js delete mode 100644 server/src/controllers/eventController.js delete mode 100644 server/src/controllers/eventsController.js delete mode 100644 server/src/controllers/ontimeController.js delete mode 100644 server/src/controllers/playbackController.js delete mode 100644 server/src/external/styles/override.css delete mode 100644 server/src/models/dataModel.js delete mode 100644 server/src/models/eventsDefinition.js delete mode 100644 server/src/modules/loadDb.js delete mode 100644 server/src/package.json delete mode 100644 server/src/routes/__tests__/eventRouter.test.js delete mode 100644 server/src/routes/__tests__/eventsRouter.test.js delete mode 100644 server/src/routes/__tests__/ontimeRouter.test.js delete mode 100644 server/src/routes/__tests__/playbackRouter.tests.js delete mode 100644 server/src/routes/eventRouter.js delete mode 100644 server/src/routes/eventsRouter.js delete mode 100644 server/src/run.js delete mode 100644 server/src/settings.js delete mode 100644 server/src/utils/__tests__/generate_id.test.js delete mode 100644 server/src/utils/fileManagement.js delete mode 100644 server/src/utils/generate_id.js delete mode 100644 server/src/utils/getRandomName.js delete mode 100644 server/src/utils/parserUtils_v1.js delete mode 100644 server/src/validation/ontimeValidator.js delete mode 100644 server/src/yarn.lock delete mode 100644 server/yarn.lock create mode 100644 turbo.json diff --git a/.deepsource.toml b/.deepsource.toml index 6ba5756480..ce1d28d5f6 100644 --- a/.deepsource.toml +++ b/.deepsource.toml @@ -3,7 +3,6 @@ version = 1 test_patterns = [ "__mocks__/**", "__tests__/**", - "cypress/**", "*.test.*", "*.mock.*", "*.spec.*" diff --git a/.eslintrc b/.eslintrc index 389d1e47f4..44af6bf474 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,26 +9,18 @@ "extends": [ "eslint:recommended" ], + "overrides": [ + { + "files": [ + "e2e/**/**.spec.ts", + "e2e/**/**.test.ts" + ], + "extends": [ + "plugin:playwright/playwright-test" + ] + } + ], "rules": { - // disallow certain object properties - // https://eslint.org/docs/rules/no-restricted-properties - "no-restricted-properties": [ - "error", - { - "object": "global", - "property": "isNaN", - "message": "Please use Number.isNaN instead" - }, - { - "object": "self", - "property": "isNaN", - "message": "Please use Number.isNaN instead" - }, - { - "object": "window", - "property": "isNaN", - "message": "Please use Number.isNaN instead" - } - ] + "no-console": "warn" } } \ No newline at end of file diff --git a/.github/02_screentypes.png b/.github/aux-images/02_screentypes.png similarity index 100% rename from .github/02_screentypes.png rename to .github/aux-images/02_screentypes.png diff --git a/.github/app.jpg b/.github/aux-images/app.jpg similarity index 100% rename from .github/app.jpg rename to .github/aux-images/app.jpg diff --git a/.github/dockerhub.png b/.github/aux-images/dockerhub.png similarity index 100% rename from .github/dockerhub.png rename to .github/aux-images/dockerhub.png diff --git a/.github/linux-download.png b/.github/aux-images/linux-download.png similarity index 100% rename from .github/linux-download.png rename to .github/aux-images/linux-download.png diff --git a/.github/mac-download.png b/.github/aux-images/mac-download.png similarity index 100% rename from .github/mac-download.png rename to .github/aux-images/mac-download.png diff --git a/.github/social-preview.png b/.github/aux-images/social-preview.png similarity index 100% rename from .github/social-preview.png rename to .github/aux-images/social-preview.png diff --git a/.github/win-download.png b/.github/aux-images/win-download.png similarity index 100% rename from .github/win-download.png rename to .github/aux-images/win-download.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00192684ad..cf175fe3fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,14 +2,12 @@ name: Ontime build on: push: - # run when a tag is created - tags: - - '*' + tags: [ "v1.*.*" ] workflow_dispatch: jobs: build_mac: - runs-on: macOS-latest + runs-on: macos-latest timeout-minutes: 20 env: CI: '' @@ -138,54 +136,4 @@ jobs: with: files: ./server/dist/ontime-linux.AppImage env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish_docker: - runs-on: ubuntu-latest - timeout-minutes: 20 - env: - CI: '' - - steps: - - uses: actions/checkout@v2 - - name: Setup env - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - name: Use Node.js - uses: actions/setup-node@v1 - with: - node-version: '14.x' - - # React - - name: React - Install dependencies - run: yarn install --network-timeout 300000 - working-directory: ./client - - - name: React - Build project - run: yarn build - working-directory: ./client - - # Node server - - name: Server - Install dependencies - run: yarn install --frozen-lockfile --production --network-timeout 300000 - working-directory: ./server/src - - # Login to docker - - name: Login to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - # Prepare builder - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - # Build and push - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ secrets.DOCKERHUB_USERNAME }}/ontime:${{ env.RELEASE_VERSION }} , ${{ secrets.DOCKERHUB_USERNAME }}/ontime:latest - platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/build_docker_v2.yml b/.github/workflows/build_docker_v2.yml new file mode 100644 index 0000000000..33ff929934 --- /dev/null +++ b/.github/workflows/build_docker_v2.yml @@ -0,0 +1,56 @@ +name: Docker Image CI Ontime V2 + +on: + push: + tags: [ "v2.*.*" ] + workflow_dispatch: + +jobs: + + publish_docker: + runs-on: ubuntu-latest + env: + CI: '' + + steps: + - uses: actions/checkout@v3 + - name: Setup env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Setup Node.js environment + uses: actions/setup-node@v3.6.0 + with: + version: 16.16.0 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + version: 7.26.3 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project packages + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: pnpm turbo build:docker + + - name: Docker Login + uses: docker/login-action@v2.1.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker Setup Buildx + uses: docker/setup-buildx-action@v2.5.0 + + - name: Build and push Docker images + uses: docker/build-push-action@v4.0.0 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 + # Push is a shorthand for --output=type=registry + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/ontime:beta_${{ env.RELEASE_VERSION }} , ${{ secrets.DOCKERHUB_USERNAME }}/ontime:beta_v2 + diff --git a/.github/workflows/build_v2.yml b/.github/workflows/build_v2.yml new file mode 100644 index 0000000000..4d9488bddf --- /dev/null +++ b/.github/workflows/build_v2.yml @@ -0,0 +1,106 @@ +name: Ontime build v2 + +on: + push: + tags: [ "v2.*.*" ] + workflow_dispatch: + +jobs: + build_macos: + runs-on: macOS-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + version: 7.26.3 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project packages + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: pnpm build + + - name: Electron - Build app + run: pnpm dist-mac + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: './apps/electron/dist/ontime-macOS.dmg' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build_windows: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + version: 7.26.3 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project packages + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: pnpm build + + - name: Electron - Build app + run: pnpm dist-win + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: './apps/electron/dist/ontime-win64.exe' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build_ubuntu: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + version: 7.26.3 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project packages + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: pnpm build + + - name: Electron - Build app + run: pnpm dist-linux + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: './apps/electron/dist/ontime-linux.AppImage' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 4f2f0b8ef1..0000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '33 02 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/ontime_cy.yml b/.github/workflows/ontime_cy.yml index 2d6734373e..627e4d6937 100644 --- a/.github/workflows/ontime_cy.yml +++ b/.github/workflows/ontime_cy.yml @@ -3,7 +3,10 @@ name: ontime_test_CI -on: [push, pull_request] +on: + pull_request: + branches: [ master ] + workflow_dispatch: jobs: build: @@ -14,11 +17,11 @@ jobs: CI: '' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: 16 # React - name: React - Install dependencies @@ -40,15 +43,24 @@ jobs: # App - name: Electron - Install dependencies - run: yarn install && yarn setdb + run: yarn setup working-directory: ./server - - name: Electron - Run tests + - name: Server - run tests run: yarn test working-directory: ./server - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - working-directory: ./server - start: yarn cypress +# - name: Install Playwright Browsers +# run: npx playwright install --with-deps +# working-directory: ./server +# +# - name: Run Playwright tests +# run: yarn e2e +# working-directory: ./server +# +# - uses: actions/upload-artifact@v3 +# if: always() +# with: +# name: playwright-report +# path: playwright-report/ +# retention-days: 7 diff --git a/.github/workflows/test_v2.yml b/.github/workflows/test_v2.yml new file mode 100644 index 0000000000..48980776d4 --- /dev/null +++ b/.github/workflows/test_v2.yml @@ -0,0 +1,76 @@ +name: Ontime test v2 + +on: + pull_request: + branches: [ v2 ] + workflow_dispatch: + +jobs: + unit-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + CI: '' + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + version: 7.26.3 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + # We choose to run tests separately + - name: React - Run unit tests + run: pnpm test:pipeline + working-directory: ./apps/client + + - name: Server - Run unit tests + run: pnpm test:pipeline + working-directory: ./apps/server + + - name: Utils - Run unit tests + run: pnpm test:pipeline + working-directory: ./packages/utils + + e2e-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Setup pnpm + uses: pnpm/action-setup@v2.2.4 + with: + version: 7.26.3 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build client + run: pnpm build:local + + - name: Install Playwright Browsers + run: npx playwright install --with-deps + + - name: Run Playwright tests + run: pnpm e2e + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index f862b6075e..07063a3a56 100644 --- a/.gitignore +++ b/.gitignore @@ -5,38 +5,42 @@ node_modules/ /.pnp .pnp.js -# testing -coverage/ -*.mp4 - -# production -build/ -dist/ - # misc .DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local +*.local npm-debug.log* yarn-debug.log* yarn-error.log* -# working stuff -_SS/ -db backup.json -server/src/preloaded-db/db.json -server/src/models/db.json -TODO.md -ontime-db/ -ontime-external/ - # vscode stuff .vscode/* ontime.code-workspace # webstorm stuff -.idea/* \ No newline at end of file +.idea/* + +# turborepo stuff +.turbo + +# testing +test-results +playwright-report +/playwright/.cache/ + +# production +build/ +dist/ + +# working stuff +**/TODO.md + +# docker utils +ontime-db +ontime-external/ + +# working database +apps/server/src/preloaded-db/db.json + +# versioning file +**/ONTIME_VERSION.js diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000000000000000000000000000000000..f272a541791d9e88d96ede216c38df960bec4650 GIT binary patch literal 22 YcmezWuZ+Qv!Hhu=16.16) +- __pnpm__ (>=7) +- __docker__ (only necessary to run and build docker images) + +## LOCAL DEVELOPMENT + +The electron app is only necessary to distribute an installable version of the app and is not required for local development. +Locally, we would need to run both the React client and the node.js server in development mode + +From the project root, run the following commands +- __Install the project dependencies__ by running `pnpm i` +- __Run dev mode__ by running `turbo dev` + +## TESTING + +Generally we have 2 types of tests. +- Unit tests for functions that contain business logic +- End-to-end tests for core features + +### Unit tests +Unit tests are contained in mostly all the apps and packages (client, server and utils) + +You can run unit tests by running turbo `turbo test:pipeline` from the project root. +This will run all tests and close test runner. + +Alternatively you can navigate to an app or project and run `pnpm test` to run those tests in watch mode + +### E2E tests +E2E tests are in a separate package. On running, [playwright](https://playwright.dev/) will spin up an instance of the webserver to test against +These tests also run against a separate version of the DB (test-db) + +You can run playwright tests from project root with `pnpm e2e` + +When writing tests, it can be handy to run playwright in interactive mode with `pnpm e2e:i`. You would need to manually start the webserver with `pnpm dev:server` + +## CREATE AN INSTALLABLE FILE (Windows | MacOS | Linux) + +Ontime uses Electron to distribute the application. +You can generate a distribution for your OS by running the following steps. + +From the project root, run the following commands +- __Install the project dependencies__ by running `pnpm i` +- __Build the UI and server__ by running `turbo build:local` +- __Create the package__ by running `turbo dist-win`, `turbo dist-mac` or `turbo dist-linux` + +The build distribution assets will be at `.apps/electron/dist` + +## DOCKER + +Ontime provides a docker-compose file to aid with building and running docker images. +While it should allow for a generic setup, it might need to be modified to fit your infrastructure. + +From the project root, run the following commands +- __Install the project dependencies__ by running `pnpm i` +- __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 +- __List running processes__ by running `docker ps` +- __Kill running process__ by running `docker kill ` diff --git a/Dockerfile b/Dockerfile index 81669ade19..65df28fe3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,27 @@ -FROM node:14-alpine +FROM node:16-alpine -WORKDIR /app/server +# Set environment variables +# Environment Variable to signal that we are running production +ENV NODE_ENV=docker +# Ontime Data path +ENV ONTIME_DATA=/external/ + +WORKDIR /app/ # Prepare UI -COPY /client/build ../client/build +COPY /apps/client/build ./client/ # Prepare Backend -COPY /server/src ./ +COPY /apps/server/dist/ ./server/ +COPY /demo-db/ ./preloaded-db/ +COPY /apps/server/src/external/ ./external/ -# Export default ports Main - OSC IN -EXPOSE 4001/tcp 8888/udp -ENV NODE_ENV=production -ENV ONTIME_DATA=/server/ +# Export default ports +EXPOSE 4001/tcp 8888/udp 9999/udp -CMD ["yarn", "start:headless"] +CMD ["node", "server/docker.cjs"] -# Build an run commandsN -# docker build -t getontime/ontime . -# docker run -p 4001:4001 -p 10.0.0.12:8888:8888/udp --mount type=bind,source="$(pwd)/ontime-db",target=/server/preloaded-db getontime/ontime +# Build and run commands +# !!! Note that this command needs pre-build versions of the UI and server apps +# docker buildx build . -t getontime/ontime +# docker run -p 4001:4001 -p 8888:8888/udp -p 9999:9999/udp -v ./ontime-db:/external/db/ -v ./ontime-styles:/external/styles/ getontime/ontime diff --git a/README.md b/README.md index 0dd58db43e..f0d5a4dbd5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![ontime_test_CI](https://github.com/cpvalente/ontime/actions/workflows/ontime_cy.yml/badge.svg)](https://github.com/cpvalente/ontime/actions/workflows/ontime_cy.yml) [![Ontime build](https://github.com/cpvalente/ontime/actions/workflows/build.yml/badge.svg)](https://github.com/cpvalente/ontime/actions/workflows/build.yml) -[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-green.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Documentation in Gitbook](https://badges.aleen42.com/src/gitbook_2.svg)](https://cpvalente.gitbook.io/ontime/) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-green.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Documentation in Gitbook](https://badges.aleen42.com/src/gitbook_2.svg)](https://ontime.gitbook.io) ## Download the latest releases here @@ -14,120 +14,115 @@ Ontime is an application for managing event rundowns and running stage timers. -It allows a center application to be able to distribute event information in the local network. This -minimises needs for using Media Server outputs or expensive video distribution while allowing easy -integration in workflows including OBS and d3. +A single, locally hosted central application distributes your event information over the local network. +This enables the distribution of the data to a series of views and allows integration into video and control workflows, including OBS and d3. -![App Window](https://github.com/cpvalente/ontime/blob/master/.github/app.jpg) +![App Window](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/app.jpg) -![Views](https://github.com/cpvalente/ontime/blob/master/.github/02_screentypes.png) +![Views](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/02_screentypes.png) ## Using Ontime -Once installed and running, ontime starts a background server that is the heart of all processes. -The app, is used to add / edit your running order in the event list, and running the timers using -the Playback Control function. +Once installed and running, Ontime starts a background server that is the heart of all processes. +From the app, you can add / edit your running order and control the timer playback. -From here, any device in the same network with a browser is able to render the views as described. +Any device with a browser in the same network can choose one of the supported views to render the available data. This is done by reaching the ontime server at the _default port 4001_ eg: `localhost:4001` or `192.168.1.3:4001` -You can then use the ontime logo in the top right corner to select the desired view (event in the -lower thirds view, where it is hidden). +
+You can then use the Ontime logo in the top left corner to select the desired view. +The logo will be initially hidden until there is mouse interaction. -In case of unattended machines or automations, it is possible to use different URL to recall -individual views and extend with using the URL aliases feature +In the case of unattended machines or automation, it is possible to use different URL to recall +individual views and extend view settings using the URL aliases feature ``` -For the presentation views... +For the presentation views ------------------------------------------------------------- IP.ADDRESS:4001 > Web server default to presenter timer view IP.ADDRESS:4001/timer > Presenter / Stage timer view +IP.ADDRESS:4001/minimal > Simple timer view +IP.ADDRESS:4001/clock > Simple clock view IP.ADDRESS:4001/sm > Stage Manager / Backstage view IP.ADDRESS:4001/public > Public / Foyer view -IP.ADDRESS:4001/pip > Picture in Picture view IP.ADDRESS:4001/lower > Lower Thirds IP.ADDRESS:4001/studio > Studio Clock -IP.ADDRESS:4001/cuesheet > Cue Sheet - -...and for the editor (the control interface, same as the app) +``` +``` +For management views ------------------------------------------------------------- -IP.ADDRESS:4001/editor - +IP.ADDRESS:4001/editor > the control interface, same as the app +IP.ADDRESS:4001/cuesheet > realtime cuesheets for collaboration ``` -More documentation available [here](https://cpvalente.gitbook.io/ontime/) +More documentation is available [in our docs](https://ontime.gitbook.io) ## Feature List (in no specific order) -- [x] Distribute Data over network and render in the browser +- [x] Distribute data over network and render it in the browser - [x] Different screen types - Stage Timer - Backstage Info - Public Info - - Picture in Picture - Studio Clock + - Countdown - [Make your own?](#make-your-own-viewer) -- [x] Configurable realtime Lower Thirds -- [x] Cuesheets with additional custom fields +- [x] Configurable Lower Thirds +- [x] Cuesheets with user definable fields - [x] Send live messages to different screen types -- [x] Ability to differentiate between backstage and public data -- [x] Manage delays workflow -- [x] Open Sound Control (OSC) Control and Feedback -- [x] Integrate with hardware using Companion or one of the APIs +- [x] Differentiate between backstage and public data +- [x] Workflow for managing delays +- [x] Protocol integrations for Control and Feedback + - OSC (Open Sound Control) + - HTTP + - WebSockets - [x] Roll mode: run independently using the system clock -- [x] Import event list from Excel -- [x] URL Aliases (define configurable aliases to ease onsite setup) -- [x] Logging view -- [x] Edit anywhere: run ontime in your local network and use any machine to reach the editor page ( - same as app) -- [x] Multi platform (available on Windows, MacOS and Linux) -- [x] [Headless run](#headless-run) (run server only, configure from a browser locally) -- [x] [Countdown to anything!](https://cpvalente.gitbook.io/ontime/views/countdown): ability to have +- [x] [Headless run](#headless-run): run server in a separate machine, configure from a browser locally +- [x] [Countdown to anything!](https://ontime.gitbook.io/v2/views/countdown): have a countdown to any scheduled event +- [x] Multi-platform (available on Windows, MacOS and Linux) +- [x] [Companion integration](https://bitfocus.io/connections/getontime-ontime) ## Unopinionated -We are not interested in forcing workflows and have made ontime, so it is flexible to whichever way +We are not interested in forcing workflows and have made Ontime, so it is flexible to whichever way you would like to work. -- [x] You do not need an order list to use the timer. Create an empty event and the OSC API works - just the same -- [x] If you want just the info screens, no need to use the timer! +- [x] If you want just the info screens, there is no need to use the timer! - [x] Don't have or care for a schedule? - - [x] a single event with no data is enough to use the OSC API and get going + - [x] a single event with no data is enough to use one of the APIs and use a dynamic timer - [x] use the order list to create a set of quick timers by setting the beginning and start - times to 00:00 and 00:10 (**BAM**! 10 minute timer). You can quickly recall this with OSC as - always + times to 00:00 and 00:10 (**BAM**! 10 minute timer). You can quickly recall this with OSC or any of the other available integrations ## Rich APIs for workflow integrations -The app is being currently developed to a wide user base, from broadcast to entertainment and +The app is currently being developed for a broad user base, from broadcast to entertainment and conference halls. -Taking advantage of the integrations in Ontime, we currently use Ontime with: +Taking advantage of the integrations, we currently use Ontime with: -- `disguise`: trigger ontime from d3's timeline using the **OSC API**, **render views** using d3's +- `disguise`: trigger Ontime from d3's timeline using the **OSC API**, and **render views** using d3's webmodule - `OBS`: **render views** using the Browser Module -- `QLab`: trigger ontime using **OSC API** +- `QLab`: trigger Ontime using **OSC API** - `Companion`: Ontime has a **companion module**. Issue report and feature requests should be done - in - the [repository getontime/ontime](https://github.com/bitfocus/companion-module-getontime-ontime) + in the [repository getontime/ontime](https://github.com/bitfocus/companion-module-getontime-ontime) ### Make your own viewer -Ontime broadcasts its data over websockets. This allows you to build your own viewers by leveranging -basic knowledge of HTML + CSS + Javascript (or any other language that can run in the browser). +Ontime broadcasts its data over WebSockets. This allows you to consume its data outside the application. -See [this repository](https://github.com/cpvalente/ontime-viewer-template) with a small template on +Writing a new view for the browser can be done with basic knowledge of HTML + CSS + Javascript (or any other language that can run in the browser). +
+See [this repository](https://github.com/cpvalente/ontime-viewer-template-v2) with a small template on how to get you started and read the docs about -the [Websocket API](https://app.gitbook.com/s/-Mc0giSOToAhq0ROd0CR/control-and-feedback/websocket-api) +the [Websocket API](https://ontime.gitbook.io/v2/control-and-feedback/websocket-api) ### Headless run️ -You can self host and run ontime in a docker image, the run command should: +You can self-host and run Ontime in a docker image. The run command will: -- expose the necessary ports (listen in Dockerfile) +- expose the necessary ports (listed in the Dockerfile) - mount a local file to persist your data (in the example: ````$(pwd)/local-data````) - the image name __getontime/ontime__ @@ -138,13 +133,7 @@ in [available Docker Hub at getontime/ontime](https://hub.docker.com/r/getontime docker pull getontime/ontime ``` -```bash -# Port 4001 - ontime server port -# Port 8888 - OSC input, bound to localhost IP Address -docker run -p 4001:4001 -p 127.0.0.1:8888:8888/udp --mount type=bind,source="$(pwd)/ontime-db",target=/server/preloaded-db getontime/ontime -``` - -or if running from the docker compose +and use the included docker compose to get started ```bash docker-compose up @@ -154,19 +143,14 @@ docker-compose up ### Continued development -There are several features planned in the roadmap. These will be implemented in a development -friendly order unless there is user demand to bump any of them. - -- [ ] HTTP Server (vMix integration) -- [ ] Improvements in event interface -- [ ] Moderator view -- [ ] New playback mode for [cumulative time keeping](https://github.com/cpvalente/ontime/issues/100) -- [ ] Lower Third Manager -- [ ] Reach Schedule: way to speedup timer to meet a deadline +Several features are planned in the roadmap, and we continuously adjust this to match how users interact with the app. +
+Have an idea? Reach out via [email](mail@getontime.no) or [open an issue](https://github.com/cpvalente/ontime/issues/new) ### Issues -If you come across any bugs, [please open an issue]((https://github.com/cpvalente/ontime/issues/new)). Usually bugs get fixed pretty quickly when reported +We use Github's issue tracking for bug reporting and feature requests.
+Found a bug? [Open an issue](https://github.com/cpvalente/ontime/issues/new). #### Unsigned App @@ -192,22 +176,28 @@ You can circumvent this by allowing the execution of the app manually. Long story short: Ontime app is unsigned.
Purchasing the certificates for both Mac and Windows would mean a recurrent expense and is not a priority. This is unlikely to change in future. If you -have tips on how to improve this, or would like to sponsor the code signing, -please [open an issue, so we can discuss it](https://github.com/cpvalente/ontime/issues/new) +have tips on how to improve this or would like to sponsor the code signing, +please [open an issue](https://github.com/cpvalente/ontime/issues/new) #### Safari -There are some issues with Safari versions lower than 13: - +There are known issues with Safari versions lower than 13: - Spacing and text styles might have small inconsistencies - Table view does not work -There is no plan for any further work on this since the breaking code belongs to third party -libraries. +There is no plan for any further work on this. + +# Contributing + +Looking to contribute? All types of help are appreciated, from coding to testing and feature specification. +

+If you are a developer and would like to contribute with some code, please open an issue to discuss before opening a Pull Request. +
+Information about the project setup can be found in the [development documentation](./DEVELOPMENT.md) # Help -Help is underway! ... and can be viewed [here](https://cpvalente.gitbook.io/ontime/) +Help is underway! ... and can be found [here](https://ontime.gitbook.io) # License diff --git a/client/.eslintignore b/apps/client/.eslintignore similarity index 100% rename from client/.eslintignore rename to apps/client/.eslintignore diff --git a/client/.eslintrc b/apps/client/.eslintrc similarity index 88% rename from client/.eslintrc rename to apps/client/.eslintrc index 27e0ad027f..402e99e49f 100644 --- a/client/.eslintrc +++ b/apps/client/.eslintrc @@ -8,18 +8,32 @@ "browser": true, "node": true }, + "parser": "@typescript-eslint/parser", "extends": [ "eslint:recommended", "plugin:react/recommended", + "plugin:react-hooks/recommended", "plugin:@typescript-eslint/recommended", - "eslint-config-prettier" + "eslint-config-prettier", + "plugin:@tanstack/eslint-plugin-query/recommended", + "prettier" ], "plugins": [ "react", "testing-library", - "simple-import-sort" + "simple-import-sort", + "@tanstack/query", + "@typescript-eslint", + "prettier" ], "rules": { + "@typescript-eslint/no-non-null-assertion": "warn", + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ], "no-useless-concat": "warn", "prefer-template": "warn", "react/jsx-no-bind": [ diff --git a/apps/client/.prettierrc b/apps/client/.prettierrc new file mode 100644 index 0000000000..2a186374a0 --- /dev/null +++ b/apps/client/.prettierrc @@ -0,0 +1,8 @@ +{ + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "jsxSingleQuote": true, + "printWidth": 120 +} diff --git a/client/.stylelintrc b/apps/client/.stylelintrc similarity index 100% rename from client/.stylelintrc rename to apps/client/.stylelintrc diff --git a/client/index.html b/apps/client/index.html similarity index 94% rename from client/index.html rename to apps/client/index.html index 4a2721deeb..c6a234f367 100644 --- a/client/index.html +++ b/apps/client/index.html @@ -32,6 +32,6 @@
- + diff --git a/apps/client/package.json b/apps/client/package.json new file mode 100644 index 0000000000..aadc5ed142 --- /dev/null +++ b/apps/client/package.json @@ -0,0 +1,99 @@ +{ + "name": "ontime-ui", + "version": "2.0.0-beta", + "private": true, + "dependencies": { + "@chakra-ui/react": "^2.5.5", + "@dnd-kit/core": "^6.0.8", + "@dnd-kit/sortable": "^7.0.2", + "@dnd-kit/utilities": "^3.2.1", + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@react-icons/all-files": "^4.1.0", + "@sentry/react": "^7.46.0", + "@sentry/tracing": "^7.46.0", + "@tanstack/react-query": "^4.28.0", + "@tanstack/react-query-devtools": "^4.29.0", + "autosize": "^5.0.2", + "axios": "^1.2.0", + "color": "^4.2.3", + "csv-stringify": "^6.2.3", + "deepmerge": "^4.3.0", + "framer-motion": "^10.10.0", + "react": "^18.2.0", + "react-colorful": "^5.6.1", + "react-dom": "^18.2.0", + "react-fast-compare": "^3.2.0", + "react-hook-form": "^7.43.5", + "react-qr-code": "^2.0.11", + "react-router-dom": "^6.3.0", + "react-table": "^7.7.0", + "typeface-open-sans": "^1.1.13", + "web-vitals": "^3.1.1", + "zustand": "^4.3.6" + }, + "scripts": { + "addversion": "node -p \"'export const ONTIME_VERSION = ' + JSON.stringify(require('../../package.json').version) + ';'\" > src/ONTIME_VERSION.js", + "postinstall": "pnpm addversion", + "dev": "cross-env BROWSER=none vite", + "build": "vite build", + "build:local": "cross-env NODE_ENV=local vite build", + "build:docker": "vite build", + "lint": "eslint .", + "stylelint": "npx stylelint \"**/*.scss\"\n", + "test": "vitest", + "test:pipeline": "vitest run", + "cleanup": "rm -rf .turbo && rm -rf node_modules && rm -rf build" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@sentry/vite-plugin": "^0.4.0", + "@tanstack/eslint-plugin-query": "^4.26.2", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.1.1", + "@testing-library/user-event": "^14.1.1", + "@types/color": "^3.0.3", + "@types/luxon": "^3.2.0", + "@types/prop-types": "^15.7.5", + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.10", + "@types/testing-library__jest-dom": "^5.14.5", + "@typescript-eslint/eslint-plugin": "^5.48.1", + "@typescript-eslint/parser": "^5.48.1", + "@vitejs/plugin-react": "^3.0.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-jest": "^27.1.7", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-simple-import-sort": "^8.0.0", + "eslint-plugin-testing-library": "^5.9.1", + "jsdom": "^21.1.0", + "ontime-types": "workspace:*", + "ontime-utils": "workspace:*", + "prettier": "^2.8.3", + "prop-types": "^15.8.1", + "sass": "^1.57.1", + "stylelint": "^14.16.1", + "stylelint-config-prettier": "^9.0.4", + "stylelint-config-standard-scss": "^6.1.0", + "typescript": "^4.9.4", + "vite": "^4.3.1", + "vite-plugin-compression2": "^0.9.0", + "vite-plugin-svgr": "^2.4.0", + "vite-tsconfig-paths": "^4.2.0", + "vitest": "^0.30.1" + } +} diff --git a/client/public/android-chrome-192x192.png b/apps/client/public/android-chrome-192x192.png similarity index 100% rename from client/public/android-chrome-192x192.png rename to apps/client/public/android-chrome-192x192.png diff --git a/client/public/android-chrome-512x512.png b/apps/client/public/android-chrome-512x512.png similarity index 100% rename from client/public/android-chrome-512x512.png rename to apps/client/public/android-chrome-512x512.png diff --git a/client/public/apple-touch-icon.png b/apps/client/public/apple-touch-icon.png similarity index 100% rename from client/public/apple-touch-icon.png rename to apps/client/public/apple-touch-icon.png diff --git a/client/public/favicon-16x16.png b/apps/client/public/favicon-16x16.png similarity index 100% rename from client/public/favicon-16x16.png rename to apps/client/public/favicon-16x16.png diff --git a/client/public/favicon-32x32.png b/apps/client/public/favicon-32x32.png similarity index 100% rename from client/public/favicon-32x32.png rename to apps/client/public/favicon-32x32.png diff --git a/client/public/favicon.ico b/apps/client/public/favicon.ico similarity index 100% rename from client/public/favicon.ico rename to apps/client/public/favicon.ico diff --git a/client/public/logo192.png b/apps/client/public/logo192.png similarity index 100% rename from client/public/logo192.png rename to apps/client/public/logo192.png diff --git a/client/public/logo512.png b/apps/client/public/logo512.png similarity index 100% rename from client/public/logo512.png rename to apps/client/public/logo512.png diff --git a/client/public/manifest.json b/apps/client/public/manifest.json similarity index 100% rename from client/public/manifest.json rename to apps/client/public/manifest.json diff --git a/client/public/robots.txt b/apps/client/public/robots.txt similarity index 100% rename from client/public/robots.txt rename to apps/client/public/robots.txt diff --git a/client/public/site.webmanifest b/apps/client/public/site.webmanifest similarity index 100% rename from client/public/site.webmanifest rename to apps/client/public/site.webmanifest diff --git a/client/src/App.jsx b/apps/client/src/App.tsx similarity index 52% rename from client/src/App.jsx rename to apps/client/src/App.tsx index 37365f3eab..e2b8b247d8 100644 --- a/client/src/App.jsx +++ b/apps/client/src/App.tsx @@ -1,24 +1,29 @@ -import { Suspense, useCallback, useEffect } from 'react'; +import { useEffect } from 'react'; import { BrowserRouter } from 'react-router-dom'; import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import ErrorBoundary from 'common/components/errorBoundary/ErrorBoundary'; +import ErrorBoundary from './common/components/error-boundary/ErrorBoundary'; import { AppContextProvider } from './common/context/AppContext'; -import SocketProvider from './common/context/socketContext'; import useElectronEvent from './common/hooks/useElectronEvent'; +import { ontimeQueryClient } from './common/queryClient'; +import { connectSocket } from './common/utils/socket'; import theme from './theme/theme'; +import { TranslationProvider } from './translation/TranslationProvider'; import AppRouter from './AppRouter'; // Load Open Sans typeface +// @ts-expect-error no types from font import import('typeface-open-sans'); -export const ontimeQueryClient = new QueryClient(); + +connectSocket(); function App() { const { isElectron, sendToElectron } = useElectronEvent(); - const handleKeyPress = useCallback((event) => { + useEffect(() => { + const handleKeyPress = (event: KeyboardEvent) => { // handle held key if (event.repeat) return; // check if the alt key is pressed @@ -28,9 +33,8 @@ function App() { sendToElectron('set-window', 'show-dev'); } } - },[]); + }; - useEffect(() => { if (isElectron) { document.addEventListener('keydown', handleKeyPress); } @@ -39,26 +43,24 @@ function App() { document.removeEventListener('keydown', handleKeyPress); } }; - }, [handleKeyPress]); + }, [isElectron, sendToElectron]); return ( - - - - -
- - - - - - -
-
-
-
-
+ + + +
+ + + + + + +
+
+
+
); } diff --git a/apps/client/src/AppRouter.tsx b/apps/client/src/AppRouter.tsx new file mode 100644 index 0000000000..a71c3e9451 --- /dev/null +++ b/apps/client/src/AppRouter.tsx @@ -0,0 +1,121 @@ +import { lazy, Suspense, useEffect } from 'react'; +import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; + +import useAliases from './common/hooks-query/useAliases'; +import withData from './features/viewers/ViewWrapper'; + +const Editor = lazy(() => import('./features/editors/ProtectedEditor')); +const Table = lazy(() => import('./features/table/ProtectedTable')); + +const TimerView = lazy(() => import('./features/viewers/timer/Timer')); +const MinimalTimerView = lazy(() => import('./features/viewers/minimal-timer/MinimalTimer')); +const ClockView = lazy(() => import('./features/viewers/clock/Clock')); +const Countdown = lazy(() => import('./features/viewers/countdown/Countdown')); + +const Backstage = lazy(() => import('./features/viewers/backstage/Backstage')); +const Public = lazy(() => import('./features/viewers/public/Public')); +const Lower = lazy(() => import('./features/viewers/lower-thirds/LowerWrapper')); +const StudioClock = lazy(() => import('./features/viewers/studio/StudioClock')); + +const STimer = withData(TimerView); +const SMinimalTimer = withData(MinimalTimerView); +const SClock = withData(ClockView); +const SCountdown = withData(Countdown); +const SBackstage = withData(Backstage); +const SPublic = withData(Public); +const SLowerThird = withData(Lower); +const SStudio = withData(StudioClock); + +const EditorFeatureWrapper = lazy(() => import('./features/EditorFeatureWrapper')); +const RundownPanel = lazy(() => import('./features/rundown/RundownExport')); +const TimerControl = lazy(() => import('./features/control/playback/TimerControlExport')); +const MessageControl = lazy(() => import('./features/control/message/MessageControlExport')); +const Info = lazy(() => import('./features/info/InfoExport')); + +export default function AppRouter() { + const { data } = useAliases(); + const location = useLocation(); + const navigate = useNavigate(); + + // navigate if is alias route + useEffect(() => { + if (!data) return; + + for (const d of data) { + if (`/${d.alias}` === location.pathname && d.enabled) { + navigate(`/${d.pathAndParams}`); + break; + } + } + }, [data, location, navigate]); + + return ( + + + } /> + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + + } /> + + } /> + + } /> + } /> + + } /> + } /> + {/*/!* Lower cannot have fallback *!/*/} + } /> + + {/*/!* Protected Routes *!/*/} + } /> + } /> + } /> + } /> + + {/*/!* Protected Routes - Elements *!/*/} + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + {/*/!* Send to default if nothing found *!/*/} + } /> + + + ); +} diff --git a/client/src/__mocks__/QueryClient.mock.js b/apps/client/src/__mocks__/QueryClient.mock.js similarity index 100% rename from client/src/__mocks__/QueryClient.mock.js rename to apps/client/src/__mocks__/QueryClient.mock.js diff --git a/apps/client/src/appConstants.ts b/apps/client/src/appConstants.ts new file mode 100644 index 0000000000..a44531dca8 --- /dev/null +++ b/apps/client/src/appConstants.ts @@ -0,0 +1,22 @@ +// Exported viewer link location +const minimalLocation = 'minimal'; +const speakerLocation = 'speaker'; +const smLocation = 'sm'; +const publicLocation = 'public'; +const studioLocation = 'studio'; +const cuesheetLocation = 'cuesheet'; +const countdownLocation = 'countdown'; +const clockLocation = 'clock'; +const lowerLocation = 'lower'; + +export const viewerLocations = [ + { link: speakerLocation, label: 'Stage timer' }, + { link: clockLocation, label: 'Clock' }, + { link: minimalLocation, label: 'Minimal timer' }, + { link: smLocation, label: 'Backstage screen' }, + { link: publicLocation, label: 'Public screen' }, + { link: lowerLocation, label: 'Lower thirds' }, + { link: studioLocation, label: 'Studio clock' }, + { link: countdownLocation, label: 'Countdown' }, + { link: cuesheetLocation, label: 'Cuesheet' }, +]; diff --git a/client/src/assets/fonts/digital-7.monoitalic.ttf b/apps/client/src/assets/fonts/digital-7.monoitalic.ttf similarity index 100% rename from client/src/assets/fonts/digital-7.monoitalic.ttf rename to apps/client/src/assets/fonts/digital-7.monoitalic.ttf diff --git a/client/src/assets/images/empty.svg b/apps/client/src/assets/images/empty.svg similarity index 100% rename from client/src/assets/images/empty.svg rename to apps/client/src/assets/images/empty.svg diff --git a/apps/client/src/assets/images/ontime-logo.svg b/apps/client/src/assets/images/ontime-logo.svg new file mode 100644 index 0000000000..41594e5e6c --- /dev/null +++ b/apps/client/src/assets/images/ontime-logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/client/src/common/api/apiConstants.ts b/apps/client/src/common/api/apiConstants.ts new file mode 100644 index 0000000000..36bf11324f --- /dev/null +++ b/apps/client/src/common/api/apiConstants.ts @@ -0,0 +1,24 @@ +export const STATIC_PORT = 4001; + +// REST stuff +export const EVENT_DATA = ['eventdata']; +export const ALIASES = ['aliases']; +export const USERFIELDS = ['userFields']; +export const RUNDOWN_TABLE_KEY = 'rundown'; +export const RUNDOWN_TABLE = [RUNDOWN_TABLE_KEY]; +export const APP_INFO = ['appinfo']; +export const OSC_SETTINGS = ['oscSettings']; +export const APP_SETTINGS = ['appSettings']; +export const VIEW_SETTINGS = ['viewSettings']; +export const RUNTIME = ['runtimeStore']; + +export const serverPort = import.meta.env.DEV ? STATIC_PORT : window.location.port; +export const serverURL = import.meta.env.DEV ? `http://localhost:${serverPort}` : window.location.origin; +export const websocketUrl = `ws://${window.location.hostname}:${serverPort}/ws`; + +export const eventURL = `${serverURL}/eventdata`; +export const rundownURL = `${serverURL}/events`; +export const ontimeURL = `${serverURL}/ontime`; + +export const stylesPath = 'external/styles/override.css'; +export const overrideStylesURL = `${serverURL}/${stylesPath}`; diff --git a/client/src/common/api/eventApi.js b/apps/client/src/common/api/eventDataApi.ts similarity index 59% rename from client/src/common/api/eventApi.js rename to apps/client/src/common/api/eventDataApi.ts index d59335b7c3..9e29750eaf 100644 --- a/client/src/common/api/eventApi.js +++ b/apps/client/src/common/api/eventDataApi.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import { EventData } from 'ontime-types'; import { eventURL } from './apiConstants'; @@ -6,13 +7,15 @@ import { eventURL } from './apiConstants'; * @description HTTP request to fetch event data * @return {Promise} */ -export const fetchEvent = async () => { +export async function fetchEventData(): Promise { const res = await axios.get(eventURL); return res.data; -}; +} /** * @description HTTP request to mutate event data * @return {Promise} */ -export const postEvent = async (data) => axios.post(eventURL, data); +export async function postEventData(data: EventData) { + return axios.post(eventURL, data); +} diff --git a/apps/client/src/common/api/eventsApi.ts b/apps/client/src/common/api/eventsApi.ts new file mode 100644 index 0000000000..fd8c406bdc --- /dev/null +++ b/apps/client/src/common/api/eventsApi.ts @@ -0,0 +1,75 @@ +import axios from 'axios'; +import { OntimeRundown, OntimeRundownEntry } from 'ontime-types'; + +import { rundownURL } from './apiConstants'; + +/** + * @description HTTP request to fetch all events + * @return {Promise} + */ +export async function fetchRundown(): Promise { + const res = await axios.get(rundownURL); + return res.data; +} + +/** + * @description HTTP request to post new event + * @return {Promise} + */ +export async function requestPostEvent(data: OntimeRundownEntry) { + return axios.post(rundownURL, data); +} + +/** + * @description HTTP request to put new event + * @return {Promise} + */ +export async function requestPutEvent(data: Partial) { + return axios.put(rundownURL, data); +} + +/** + * @description HTTP request to modify event + * @return {Promise} + */ +export async function requestPatchEvent(data: OntimeRundownEntry) { + return axios.patch(rundownURL, data); +} + +export type ReorderEntry = { + eventId: string; + from: number; + to: number; +}; + +/** + * @description HTTP request to reorder events + * @return {Promise} + */ +export async function requestReorderEvent(data: ReorderEntry) { + return axios.patch(`${rundownURL}/reorder`, data); +} + +/** + * @description HTTP request to request application of delay + * @return {Promise} + */ +export async function requestApplyDelay(eventId: string) { + return axios.patch(`${rundownURL}/applydelay/${eventId}`); +} + +/** + * @description HTTP request to delete given event + * @return {Promise} + */ +export async function requestDelete(eventId: string) { + return axios.delete(`${rundownURL}/${eventId}`); +} + +/** + * @description HTTP request to delete all events + * @return {Promise} + */ +export async function requestDeleteAll() { + return axios.delete(`${rundownURL}/all`); +} diff --git a/apps/client/src/common/api/ontimeApi.ts b/apps/client/src/common/api/ontimeApi.ts new file mode 100644 index 0000000000..a826d49819 --- /dev/null +++ b/apps/client/src/common/api/ontimeApi.ts @@ -0,0 +1,175 @@ +import axios from 'axios'; +import { Alias, EventData, OSCSettings, Settings, UserFields, ViewSettings } from 'ontime-types'; + +import { apiRepoLatest } from '../../externals'; +import { InfoType } from '../models/Info'; + +import { ontimeURL } from './apiConstants'; + +/** + * @description HTTP request to retrieve application settings + * @return {Promise} + */ +export async function getSettings(): Promise { + const res = await axios.get(`${ontimeURL}/settings`); + return res.data; +} + +/** + * @description HTTP request to mutate application settings + * @return {Promise} + */ +export async function postSettings(data: Settings) { + return axios.post(`${ontimeURL}/settings`, data); +} + +/** + * @description HTTP request to retrieve application info + * @return {Promise} + */ +export async function getInfo(): Promise { + const res = await axios.get(`${ontimeURL}/info`); + return res.data; +} + +/** + * @description HTTP request to retrieve view settings + * @return {Promise} + */ +export async function getView(): Promise { + const res = await axios.get(`${ontimeURL}/views`); + return res.data; +} + +/** + * @description HTTP request to mutate view settings + * @return {Promise} + */ +export async function postViewSettings(data: ViewSettings) { + return axios.post(`${ontimeURL}/views`, data); +} + +/** + * @description HTTP request to retrieve aliases + * @return {Promise} + */ +export async function getAliases(): Promise { + const res = await axios.get(`${ontimeURL}/aliases`); + return res.data; +} + +/** + * @description HTTP request to mutate aliases + * @return {Promise} + */ +export async function postAliases(data: Alias[]) { + return axios.post(`${ontimeURL}/aliases`, data); +} + +/** + * @description HTTP request to retrieve user fields + * @return {Promise} + */ +export async function getUserFields(): Promise { + const res = await axios.get(`${ontimeURL}/userfields`); + return res.data; +} + +/** + * @description HTTP request to mutate user fields + * @return {Promise} + */ +export async function postUserFields(data: UserFields) { + return axios.post(`${ontimeURL}/userfields`, data); +} + +/** + * @description HTTP request to retrieve osc settings + * @return {Promise} + */ +export async function getOSC(): Promise { + const res = await axios.get(`${ontimeURL}/osc`); + return res.data; +} + +/** + * @description HTTP request to mutate osc settings + * @return {Promise} + */ +export async function postOSC(data: OSCSettings) { + return axios.post(`${ontimeURL}/osc`, data); +} + +/** + * @description HTTP request to download db + * @return {Promise} + */ +export const downloadRundown = async () => { + await axios({ + url: `${ontimeURL}/db`, + method: 'GET', + responseType: 'blob', // important + }).then((response) => { + const headerLine = response.headers['Content-Disposition']; + let filename = 'rundown.json'; + + // try and get the filename from the response + if (headerLine != null) { + const startFileNameIndex = headerLine.indexOf('"') + 1; + const endFileNameIndex = headerLine.lastIndexOf('"'); + filename = headerLine.substring(startFileNameIndex, endFileNameIndex); + } + + const url = window.URL.createObjectURL(new Blob([response.data], { type: 'application/json' })); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + }); +}; + +/** + * @description HTTP request to upload events db + * @return {Promise} + */ +type UploadDataOptions = { + onlyRundown?: boolean; +}; +export const uploadData = async (file: File, setProgress: (value: number) => void, options?: UploadDataOptions) => { + const formData = new FormData(); + formData.append('userFile', file); + const onlyRundown = options?.onlyRundown || 'false'; + await axios + .post(`${ontimeURL}/db?onlyRundown=${onlyRundown}`, formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + onUploadProgress: (progressEvent) => { + const complete = progressEvent?.total ? Math.round((progressEvent.loaded * 100) / progressEvent.total) : 0; + setProgress(complete); + }, + }) + .then((response) => response.data.id); +}; + +export type HasUpdate = { + url: string; + version: string; +}; + +/** + * @description HTTP request to get the latest version and url from github + * @return {Promise} + */ +export async function getLatestVersion(): Promise { + const res = await axios.get(`${apiRepoLatest}`); + return { + url: res.data.html_url as string, + version: res.data.tag_name as string, + }; +} + +export async function postNew(initialData: Partial) { + return axios.post(`${ontimeURL}/new`, initialData); +} diff --git a/client/src/common/components/buttons/EnableBtn.jsx b/apps/client/src/common/components/buttons/EnableBtn.jsx similarity index 94% rename from client/src/common/components/buttons/EnableBtn.jsx rename to apps/client/src/common/components/buttons/EnableBtn.jsx index 8948d5b4dc..c9dace1278 100644 --- a/client/src/common/components/buttons/EnableBtn.jsx +++ b/apps/client/src/common/components/buttons/EnableBtn.jsx @@ -1,4 +1,4 @@ -import { Button } from '@chakra-ui/button'; +import { Button } from '@chakra-ui/react'; import { IoCheckmarkSharp } from '@react-icons/all-files/io5/IoCheckmarkSharp'; import { IoCloseSharp } from '@react-icons/all-files/io5/IoCloseSharp'; import PropTypes from 'prop-types'; diff --git a/client/src/common/components/buttons/PauseIconBtn.jsx b/apps/client/src/common/components/buttons/PauseIconBtn.tsx similarity index 61% rename from client/src/common/components/buttons/PauseIconBtn.jsx rename to apps/client/src/common/components/buttons/PauseIconBtn.tsx index 7d80b431df..5bc581a6c4 100644 --- a/client/src/common/components/buttons/PauseIconBtn.jsx +++ b/apps/client/src/common/components/buttons/PauseIconBtn.tsx @@ -1,30 +1,28 @@ -import { IconButton } from '@chakra-ui/button'; -import { Tooltip } from '@chakra-ui/tooltip'; +import { IconButton, Tooltip } from '@chakra-ui/react'; import { IoPause } from '@react-icons/all-files/io5/IoPause'; -import PropTypes from 'prop-types'; import { tooltipDelayMid } from '../../../ontimeConfig'; -export default function PauseIconBtn(props) { +interface PauseIconBtnProps { + clickhandler: (event: React.MouseEvent) => void; + active: boolean; + disabled: boolean; +} + +export default function PauseIconBtn(props: PauseIconBtnProps) { const { clickhandler, active, disabled, ...rest } = props; return ( } colorScheme='orange' - _hover={!disabled && { bg: 'orange.400' }} variant={active ? 'solid' : 'outline'} onClick={clickhandler} width={120} disabled={disabled} + aria-label='Pause playback' {...rest} /> ); } - -PauseIconBtn.propTypes = { - clickhandler: PropTypes.func, - active: PropTypes.bool, - disabled: PropTypes.bool -} diff --git a/client/src/common/components/buttons/PublicIconBtn.jsx b/apps/client/src/common/components/buttons/PublicIconBtn.jsx similarity index 88% rename from client/src/common/components/buttons/PublicIconBtn.jsx rename to apps/client/src/common/components/buttons/PublicIconBtn.jsx index 969559b85f..c9f9c03749 100644 --- a/client/src/common/components/buttons/PublicIconBtn.jsx +++ b/apps/client/src/common/components/buttons/PublicIconBtn.jsx @@ -1,5 +1,4 @@ -import { IconButton } from '@chakra-ui/button'; -import { Tooltip } from '@chakra-ui/tooltip'; +import { IconButton, Tooltip } from '@chakra-ui/react'; import { FiUsers } from '@react-icons/all-files/fi/FiUsers'; import PropTypes from 'prop-types'; diff --git a/client/src/common/components/buttons/QuitIconBtn.jsx b/apps/client/src/common/components/buttons/QuitIconBtn.tsx similarity index 51% rename from client/src/common/components/buttons/QuitIconBtn.jsx rename to apps/client/src/common/components/buttons/QuitIconBtn.tsx index 7dd1325b2e..43b03b85f4 100644 --- a/client/src/common/components/buttons/QuitIconBtn.jsx +++ b/apps/client/src/common/components/buttons/QuitIconBtn.tsx @@ -1,5 +1,4 @@ -import { useCallback, useContext, useEffect, useRef, useState } from 'react'; -import { Button, IconButton } from '@chakra-ui/button'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { AlertDialog, AlertDialogBody, @@ -7,24 +6,52 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, -} from '@chakra-ui/modal'; -import { Tooltip } from '@chakra-ui/tooltip'; + Button, + IconButton, + Tooltip, +} from '@chakra-ui/react'; import { FiPower } from '@react-icons/all-files/fi/FiPower'; -import PropTypes from 'prop-types'; -import { LoggingContext } from '../../context/LoggingContext'; +import { Size } from '../../models/Util.type'; +import { useEmitLog } from '../../stores/logger'; -export default function QuitIconBtn(props) { - const { clickHandler, size = 'lg', ...rest } = props; +interface QuitIconBtnProps { + clickHandler: () => void; + size?: Size; + disabled?: boolean; +} + +const quitBtnStyle = { + color: '#D20300', // $red-700 + borderColor: '#D20300', // $red-700 + _focus: { boxShadow: 'none' }, + _hover: { + background: '#D20300', // $red-700 + color: 'white', + _disabled: { + color: '#D20300', // $red-700 + background: 'none', + }, + }, + _active: { + background: '#9A0000', // $red-1000 + color: 'white', + }, + variant: 'outline', + isRound: true, +}; + +export default function QuitIconBtn(props: QuitIconBtnProps) { + const { clickHandler, size = 'lg', disabled, ...rest } = props; const [isOpen, setIsOpen] = useState(false); - const { emitInfo } = useContext(LoggingContext); + const { emitInfo } = useEmitLog(); const onClose = () => setIsOpen(false); - const cancelRef = useRef(); + const cancelRef = useRef(null); useEffect(() => { if (window.process?.type === 'renderer') { window.ipcRenderer.on('user-request-shutdown', () => { - emitInfo('Shutdown request') + emitInfo('Shutdown request'); setIsOpen(true); }); } @@ -39,13 +66,12 @@ export default function QuitIconBtn(props) { <> } - colorScheme='red' - variant='outline' - isRound onClick={() => setIsOpen(true)} - _focus={{ boxShadow: 'none' }} + isDisabled={disabled} + {...quitBtnStyle} {...rest} /> @@ -53,13 +79,11 @@ export default function QuitIconBtn(props) { - Server Shutdown + Ontime Shutdown - - This will shutdown the program and all running servers. Are you sure? - + This will shutdown the program and all running servers. Are you sure? - + } variant='ontime-filled' tabIndex={-1} onClick={handleClick} /> + + + ); +} diff --git a/client/src/common/components/errorBoundary/ErrorBoundary.jsx b/apps/client/src/common/components/error-boundary/ErrorBoundary.jsx similarity index 60% rename from client/src/common/components/errorBoundary/ErrorBoundary.jsx rename to apps/client/src/common/components/error-boundary/ErrorBoundary.jsx index 9f8e31c5e6..0fb8bf8fc8 100644 --- a/client/src/common/components/errorBoundary/ErrorBoundary.jsx +++ b/apps/client/src/common/components/error-boundary/ErrorBoundary.jsx @@ -1,13 +1,10 @@ /* eslint-disable react/destructuring-assignment */ import React from 'react'; - -import { version as appVersion } from '../../../../package.json'; -import { LoggingContext } from '../../context/LoggingContext'; +import * as Sentry from '@sentry/react'; import style from './ErrorBoundary.module.scss'; class ErrorBoundary extends React.Component { - static contextType = LoggingContext; reportContent = ''; constructor(props) { @@ -25,36 +22,34 @@ class ErrorBoundary extends React.Component { error: error, errorInfo: info, }); - try { - this.context.emitError(error.toString()); - } catch (e) { - console.log('Unable to emit error', error, e ) - } + + Sentry.withScope((scope) => { + scope.setExtras(error); + const eventId = Sentry.captureException(error); + this.setState({ eventId, info }); + }); this.reportContent = `${error} ${info.componentStack}`; } render() { if (this.state.errorMessage) { return ( -
+

:/

Something went wrong

-

{ - if (navigator.clipboard) { - const copyContent = `ontime version ${appVersion} \n ${this.reportContent}`; - navigator.clipboard.writeText(copyContent); - } - }} + onClick={() => Sentry.showReportDialog({ eventId: this.state.eventId })} > - Copy error -

-

+

{ - if (window.process.type === 'renderer') { + if (window?.process?.type === 'renderer') { window.ipcRenderer.send('reload'); } else { window.location.reload(); @@ -62,7 +57,7 @@ class ErrorBoundary extends React.Component { }} > Reload interface -

+
); diff --git a/client/src/common/components/errorBoundary/ErrorBoundary.module.scss b/apps/client/src/common/components/error-boundary/ErrorBoundary.module.scss similarity index 68% rename from client/src/common/components/errorBoundary/ErrorBoundary.module.scss rename to apps/client/src/common/components/error-boundary/ErrorBoundary.module.scss index afde836085..71182baf6a 100644 --- a/client/src/common/components/errorBoundary/ErrorBoundary.module.scss +++ b/apps/client/src/common/components/error-boundary/ErrorBoundary.module.scss @@ -1,4 +1,4 @@ -@use '../../../theme/main' as *; +@use '../../../theme/v2Styles' as *; .errorContainer { width: 100%; @@ -9,17 +9,17 @@ color: white; .error { - color: $ontime-pink; + color: $error-red; font-weight: 600; } .report { - text-decoration: underline $ontime-pink; + text-decoration: underline $error-red; cursor: pointer; } .report:hover { - color: $ontime-pink; + color: $error-red; } .report:active { diff --git a/apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx b/apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx new file mode 100644 index 0000000000..2ed97a970b --- /dev/null +++ b/apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx @@ -0,0 +1,33 @@ +import { useEffect, useRef } from 'react'; +import { Textarea, TextareaProps } from '@chakra-ui/react'; +// @ts-expect-error no types from library +import autosize from 'autosize/dist/autosize'; + +interface AutoTextAreaProps extends TextareaProps { + isDark?: boolean; +} + +export const AutoTextArea = (props: AutoTextAreaProps) => { + const { isDark, ...rest } = props; + const ref = useRef(null); + + useEffect(() => { + const node = ref.current; + autosize(ref.current); + return () => { + autosize.destroy(node); + }; + }, []); + + return ( +