Compare commits

..

828 Commits

Author SHA1 Message Date
Carlos Valente b13d5792f3 fixup! feat: implement speed controls 2025-03-02 14:45:40 +01:00
Carlos Valente d0027d4016 fixup! feat: implement speed controls 2025-03-02 14:45:32 +01:00
Carlos Valente ae1639802c feat: implement speed controls 2025-03-02 14:13:53 +01:00
Carlos Valente 9167a50eda refactor: project info design review 2025-02-28 19:28:55 +01:00
Carlos Valente 8adca908b3 refactor: improve links inside editor 2025-02-28 19:21:48 +01:00
Carlos Valente bf99646ad5 refactor: restructure directories 2025-02-28 19:21:48 +01:00
Carlos Valente 308285ce3e chore: add missing variables 2025-02-28 19:21:48 +01:00
Carlos Valente dd781a32f6 bump version to 3.13.1 2025-02-27 08:28:21 +01:00
Carlos Valente c2a6de6195 fix: memoisation of row should allow changes 2025-02-27 08:28:21 +01:00
Carlos Valente 0ac2ce8e84 bump version to 3.13.0 2025-02-26 21:43:24 +01:00
Carlos Valente 3bdd8424eb chore: remove console statement 2025-02-26 21:43:24 +01:00
Carlos Valente b3a099255f fix: missing backstage prop 2025-02-26 21:43:24 +01:00
Carlos Valente 570ff59cfc feat: add custom field type of image 2025-02-26 21:42:24 +01:00
Alex Christoffer Rasmussen d0b4c6a279 import id's from sheet (#1516)
* import id's from sheet

* fix test

* fix test in utils

* remove comment

* ensure uri safe ids
2025-02-26 21:12:36 +01:00
Carlos Valente e90161aa33 refactor: consistent logo sizes 2025-02-25 21:25:28 +01:00
Carlos Valente e37254107e style: reword prompt 2025-02-25 21:25:28 +01:00
Carlos Valente 9d6bc0a137 style: clarify resource 2025-02-25 21:25:28 +01:00
Carlos Valente 4cd2dcbab0 refactor: move logic to service 2025-02-25 21:25:28 +01:00
Carlos Valente 8c593b3487 refactor: use memoised selector 2025-02-23 21:50:01 +01:00
Carlos Valente ba74622569 refactor: use native button 2025-02-23 21:50:01 +01:00
Carlos Valente f76c0d1a6d refactor: improve composition performance 2025-02-23 21:50:01 +01:00
Carlos Valente 8e8d3a7824 refactor: send client list on patch 2025-02-23 21:49:53 +01:00
Carlos Valente 6c3ae1f914 refactor: show schedule in smaller screens 2025-02-23 21:49:53 +01:00
Alex Christoffer Rasmussen b6507c27a6 Report (#1469)
* create report service

* write report from runtimeState

* use in UI

* clear report

* update types

* clear all from settings menu

* rearence rightclik menu

* refactor styling

* also report roll events

* ontime/under time is same colour

* refactor reporter

* add target to ontime-refetch

* remove menu

* fectch only on message from server

* memo useGetEventReport

* refactor

* use staleTime

* dont add to menu yet

* implement review

* clear all from menu

* fix merge

* start end show

* combine test for the go button text and action

* add report to menu

* extract csv utility

* report management

* unneeded async

* small refacort of triggerReportEntry

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2025-02-23 17:02:09 +01:00
Carlos Valente 21877e4bff refactor: allow redirecting to view 2025-02-22 16:15:24 +01:00
Carlos Valente b8d7324be0 feat: allow redirecting to preset 2025-02-22 16:15:24 +01:00
Carlos Valente 88b8e83494 Time until (#1497)
* Timeuntil in UI (#1461)

* cherry pick EventBlockChip

* pull data down throug components

* add comment

* cleanup css

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* fix: account for running day

* refactor: improve composition

* add partial test

---------

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
2025-02-19 13:17:53 +01:00
Carlos Valente abce0c498c bump version to 3.12.0 2025-02-18 21:43:16 +01:00
Carlos Valente 6b2e45e7de refactor: improve template input 2025-02-18 21:43:03 +01:00
Carlos Valente 5fb30c75c4 feat: ontime actions in automation 2025-02-18 21:43:03 +01:00
Carlos Valente 636f78e21e fix: unique reference for filter items 2025-02-18 21:43:03 +01:00
Carlos Valente 1636745fed refactor: improve automation flow logging 2025-02-18 21:43:03 +01:00
Carlos Valente e01ab0c88b fix: update navigation references 2025-02-18 21:43:03 +01:00
Carlos Valente 0ede753652 fix: missing reference on template input 2025-02-18 21:43:03 +01:00
Alex Christoffer Rasmussen 1f6f3df0f2 ensure extension during rename and delete (#1508) 2025-02-18 21:25:36 +01:00
Carlos Valente a5afb32b8a refactor: show projected time 2025-02-18 14:55:24 +01:00
Carlos Valente 9c41f8ff6b refactor: public design review 2025-02-18 14:55:24 +01:00
Carlos Valente 1edde03bb4 chore: directory restructure 2025-02-18 14:55:24 +01:00
Carlos Valente 946b6717d2 refactor: backstage design review
refactor: improve empty state

refactor: review schedule design

- fit as many elements as possible
- expose cycle interval as an option
- stabilise rundown reference
- style tweaks
2025-02-18 14:55:24 +01:00
Carlos Valente f99ad83049 chore: folder structure 2025-02-18 14:55:24 +01:00
Carlos Valente 665496907e refactor: improve overflow style 2025-02-18 14:14:14 +01:00
Carlos Valente 2867c8301d refactor: stabilise table options 2025-02-18 14:14:14 +01:00
Carlos Valente 84a5b4fe5b refactor: use a single menu for table 2025-02-18 14:14:14 +01:00
Carlos Valente 86bb739d90 chore: upgrade zustand 2025-02-18 14:14:14 +01:00
Carlos Valente 2c8b6180d7 refactor: show menu only if enabled 2025-02-18 14:14:14 +01:00
Carlos Valente 4cc138e3c0 chore: directory structure 2025-02-18 14:14:14 +01:00
Carlos Valente d21e1f996f refactor: simplify typing 2025-02-17 21:36:18 +01:00
Carlos Valente 11c1b472a2 refactor: do not test automations without outputs 2025-02-17 21:36:18 +01:00
Carlos Valente 891bda6661 refactor: improve async handling 2025-02-17 21:36:18 +01:00
Carlos Valente c65761448d refactor: simplify import paths 2025-02-17 21:36:18 +01:00
Carlos Valente 70558c5104 refactor: remove unused template literals 2025-02-17 21:36:18 +01:00
Carlos Valente c8bf74a719 refactor: migrate chakra alert to custom component 2025-02-17 14:45:23 +01:00
Carlos Valente 10bf4b93ee doc: add osc disabled warning for cloud users 2025-02-17 14:45:23 +01:00
Carlos Valente f6449a4326 refactor: tweak reusable info component 2025-02-17 14:45:23 +01:00
Carlos Valente 8d38f52b69 bump version to 3.11.1 2025-02-17 12:59:10 +01:00
Carlos Valente 3d40e31730 fix: error on reading malformed package 2025-02-17 12:59:10 +01:00
Carlos Valente 8ac5c0a9a2 Revert "Timeuntil in UI (#1461)"
This reverts commit 221ff7b3af.
2025-02-12 22:19:18 +01:00
Carlos Valente 649f0af2cf refactor: reword error 2025-02-12 22:19:18 +01:00
Carlos Valente fd9b944ecf bump version to 3.11.0 2025-02-12 22:19:18 +01:00
Alex Christoffer Rasmussen 0b36608134 Catch xlsx error (#1487)
* catch potential xlsx errors

* clear worksheet errors when starting new connections
2025-02-12 13:38:18 +01:00
Carlos Valente bac11adeb1 feat: add autocomplete to osc arguments 2025-02-10 20:01:36 +01:00
Carlos Valente 31799f8fab fix: project created without extension 2025-02-10 07:39:05 +01:00
Carlos Valente af177060ff refactor: add next to source fields 2025-02-06 21:20:25 +01:00
Carlos Valente d26a3cd393 refactor: change order of operations 2025-02-06 21:20:25 +01:00
Carlos Valente 38a3165a79 refactor: larger settings panels 2025-02-04 22:35:17 +01:00
Carlos Valente 1715c19747 refactor: clarify empty text 2025-02-04 22:35:17 +01:00
Carlos Valente 6be6e5fd8d refactor: handle overflow in menulist 2025-02-04 22:35:17 +01:00
Carlos Valente 44b0cfd928 refactor: allow locking cuesheet and operator 2025-02-04 22:35:00 +01:00
Carlos Valente 3d50b8ce49 refactor: simplify navigation lock 2025-02-04 22:35:00 +01:00
Carlos Valente c3d66f5bd1 fix: maintain locked and token params 2025-02-01 21:34:29 +01:00
Carlos Valente d08787a6ba refactor: allow presets for op and cuesheet 2025-02-01 21:34:29 +01:00
Carlos Valente f0e6231338 refactor: simplify url preset logic 2025-02-01 21:34:29 +01:00
Carlos Valente 430bfb38f2 chore: test is typescript 2025-02-01 21:34:29 +01:00
Carlos Valente 60354f8ea3 fix: prevent non alphanumeric in pincode 2025-02-01 11:38:58 +01:00
Carlos Valente bc12531729 refactor: show multiline text in custom fields 2025-02-01 11:38:58 +01:00
Carlos Valente 0b8a694e4f refactor: allow overriding operator styles 2025-02-01 11:38:58 +01:00
Carlos Valente 73ada99596 fix: update time in block (#1474)
* fix: update time in block

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2025-01-31 17:20:02 +01:00
Alex Christoffer Rasmussen f509655d31 update types/node and osc-min (#1475) 2025-01-30 22:25:25 +01:00
Carlos Valente fb1bbd6d5c refactor: fix roll next day 2025-01-27 19:24:11 +01:00
Alex Christoffer Rasmussen 221ff7b3af Timeuntil in UI (#1461)
* cherry pick EventBlockChip

* pull data down throug components

* add comment

* cleanup css

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2025-01-27 16:39:32 +01:00
Carlos Valente 5d5b48aca6 bump version to 3.11.0-beta.1 2025-01-26 20:22:01 +01:00
Carlos Valente 0f57689750 feat: generate authenticated url (#1471)
* refactor: extract info component

* feat: generate authenticated url

* refactor: add companion select

* refactor: ensure behaviour across environments
2025-01-26 16:51:28 +01:00
Alex Christoffer Rasmussen d34280c03d More batch (#1468)
* batch updates in client

* rearange updating logic

* utilety type

* guard undefinde in affectsLoaded

* fix: pause state not saved to restore point
2025-01-26 13:14:24 +01:00
Carlos Valente bb1e9072fd refactor: apply param structure 2025-01-25 18:54:25 +01:00
Carlos Valente 4503d1e411 refactor: param sections are collapsible 2025-01-25 18:54:25 +01:00
Carlos Valente b4caec0644 refactor: use type imports 2025-01-24 17:06:50 +01:00
Carlos Valente 960f0322ad refactor: improve Esc handling in forms 2025-01-24 16:48:42 +01:00
Carlos Valente a12694b186 refactor: use inline elements 2025-01-24 16:48:42 +01:00
Carlos Valente a1d34c8f6c refactor: remove > and < comparisons 2025-01-24 13:53:17 +01:00
Carlos Valente 7f8dbbfa87 refactor: simplify string comparisons 2025-01-24 13:53:17 +01:00
Carlos Valente 39e012452b refactor: improve form ux 2025-01-24 13:53:17 +01:00
Carlos Valente c333117347 refactor: start with small runtimedata subset 2025-01-24 13:53:17 +01:00
Carlos Valente eb0e5e6420 refactor: handle boolean comparisons 2025-01-24 13:53:17 +01:00
Carlos Valente 8ba65fa2bd refactor: handle non numeric comparisons 2025-01-24 13:53:17 +01:00
Carlos Valente efe5ac16f2 chore: rename feature elements
rename automations > triggers
rename blueprints > automations

chore: add link to documentation
2025-01-24 13:53:17 +01:00
arc-alex f4f266dbd4 refactor: migrate to OSC min 2025-01-24 13:53:17 +01:00
Carlos Valente bc9345199b feat: filtering logic 2025-01-24 13:53:17 +01:00
Carlos Valente 2cc434b0e9 refactor: remove legacy service 2025-01-24 13:53:17 +01:00
Carlos Valente 1f71d4578c refactor: migrate triggers to new service 2025-01-24 13:53:17 +01:00
Carlos Valente 6c4d80158c feat: send osc 2025-01-24 13:53:17 +01:00
Carlos Valente ab4dd300ca feat: send http 2025-01-24 13:53:17 +01:00
Carlos Valente 8b84963e17 feat: automation UI
merge with automation service
2025-01-24 13:53:17 +01:00
Carlos Valente 05e61e7bf8 feat: automation service 2025-01-24 13:53:17 +01:00
Carlos Valente a8fe4c8e68 refactor: allow both http and https 2025-01-24 13:53:17 +01:00
Alex Christoffer Rasmussen d175c788c5 Batch client updates (#1448) 2025-01-24 13:52:58 +01:00
Carlos Valente f1f628a48e bump version to 3.10.5 2025-01-24 13:31:18 +01:00
Carlos Valente d58335d1a1 refactor: allow overriding timer type in view 2025-01-24 13:13:53 +01:00
Carlos Valente 78c2bd79b5 refactor: card content on preload 2025-01-24 13:13:53 +01:00
Carlos Valente 28452d1e38 refactor: allow overriding progress bar phases 2025-01-24 13:13:53 +01:00
Carlos Valente 46790441e0 refactor: review view styles 2025-01-24 13:13:53 +01:00
Carlos Valente 3f35b5e297 refactor: extract and simplify logic 2025-01-24 13:13:53 +01:00
Carlos Valente 49cae647d6 refactor: larger progress bar 2025-01-24 13:13:53 +01:00
Carlos Valente 90700c85e8 refactor: subscript clock 2025-01-24 13:13:53 +01:00
Carlos Valente 8fac23c078 refactor: make function private 2025-01-24 13:13:53 +01:00
Carlos Valente b5cf6c4bd1 chore: directory restructure 2025-01-24 13:13:53 +01:00
Carlos Valente 0ea00ff6be chore: remove unused code 2025-01-24 12:41:42 +01:00
Carlos Valente 30e290c320 refactor: remove unnecessary handler 2025-01-22 20:51:12 +01:00
Carlos Valente ac52b3f0c1 chore: use smaller dependency 2025-01-22 20:51:12 +01:00
Carlos Valente 8e3db6c559 refactor: remove dom dependencies 2025-01-22 20:51:12 +01:00
Carlos Valente 1d2013ad41 fix: show correct state for welcome option 2025-01-19 22:18:03 +01:00
Carlos Valente 9c910c079d bump version to 3.10.4 2025-01-19 20:04:52 +01:00
Carlos Valente 420cef8b0d chore: add html files to docker 2025-01-19 19:57:10 +01:00
Carlos Valente b4c7b84f92 refactor: handle trailing slash in URL preset 2025-01-19 19:57:10 +01:00
Carlos Valente 0450eb9169 refactor: set token from query params 2025-01-19 19:57:10 +01:00
Carlos Valente 7fe5223af9 feat: add auth to server requests 2025-01-19 19:57:10 +01:00
arc-alex ce8d534953 feat: optional welcome modal
welcome modal is persisted in app state

created endpoints to set the visibility

added UI to support feature

Co-authored-by: Carlos Valente
<34649812+cpvalente@users.noreply.github.com>
2025-01-18 20:24:46 +01:00
Carlos Valente 4a6fbc2a92 refactor: add timezone data to session 2025-01-17 20:05:56 +01:00
Carlos Valente 50ebcf4e14 refactor: review welcome modal design 2025-01-17 20:04:00 +01:00
Carlos Valente f0f7d1cede docs: add homebrew links 2025-01-17 20:02:44 +01:00
Carlos Valente d2bdb1ea03 docs: add links to sponsor 2025-01-17 20:02:44 +01:00
Carlos Valente 9be6febcda chore: upgrade playwright 2025-01-17 19:57:01 +01:00
Carlos Valente aa929fd0dc refactor: create utility for nested templates 2025-01-12 10:20:24 +01:00
Carlos Valente 7baa6a4ab9 refactor: create mock data utilities 2025-01-12 10:20:24 +01:00
Carlos Valente 082fe8b8d7 chore: write feature spec 2025-01-12 10:14:44 +01:00
Alex Christoffer Rasmussen e9a7cd0400 More rundown metadata (#1429)
* add dayOffset to OntimeEvent

* refactor: isNewLatest

* calculate totalDays

* refactor: getTimeFromPrevious

* add gap as dataset in OntimeEvent

* use in ui

* format overlap is just a simple text formatting, big test is not needed

* add new fields where needed

* update apply delay

* show nex day eaven if there is no gap

* create test

* use buildin day offset in timeline

* remove todo

* consistent naming

* make a calculateDayOffset util for rundownCache

* refactor: checkIsNextDay to use dayOffset

* spelling

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* remove unneeded test

* remove todo

* update test db

* use data-testid

* spelling

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* update comments

* remove null option

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2025-01-09 13:35:11 +01:00
Carlos Valente 9ba40c35a1 refactor: avoid matching file versions 2025-01-06 22:58:06 +01:00
Carlos Valente f94db06812 refactor: wider sheet id length 2025-01-06 22:58:06 +01:00
Carlos Valente 35424cfff2 bump version to 3.10.3 2025-01-06 20:33:39 +01:00
Alex Christoffer Rasmussen 13eadeb0af fix download (#1434)
* fix download

* update test db

* create download test
2025-01-06 20:26:06 +01:00
Carlos Valente 9cfed5a150 fix: issue with persistent script 2025-01-06 20:11:15 +01:00
Alex Christoffer Rasmussen a22c2d380d bump: v3.10.2 (#1431) 2025-01-06 14:08:36 +01:00
Alex Christoffer Rasmussen cd913fc144 small strict improvements (#1428)
* small `strict` improvements

* fix type

* use isObject
2025-01-06 14:07:36 +01:00
Alex Christoffer Rasmussen 743d7fa782 fix: validateLinkStart (#1430)
* fix validateLinkStart

* update comment

* use fallback

* cast to MaybeString

* update comment

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2025-01-06 13:12:03 +01:00
Carlos Valente 891c43ba77 refactor: countToEnd does not cause rundown recalculation 2025-01-05 15:18:28 +01:00
Carlos Valente fba20b889e refactor: only allow testing saved URLs 2025-01-05 15:17:53 +01:00
Carlos Valente bc4d913ba7 refactor: always show client path 2025-01-05 15:17:53 +01:00
Alex Christoffer Rasmussen 533f9798e8 convert to and from database type (#1410)
* create db event type

* dont use it yet

* convert to and from database type

* type needed in one place in client

* use flatMap to filter out unknow stuff

* leave revision in save file

* move to utils

* make test

* destructur entry

* simple test

* throw in rundownToDatabaseRundown

* clerify comment

* Refactor: avoid shadowing the rundown variable in rundownCache (#1409)


---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* rename to DAO

* add simple edit test

* only the generate function clears the state state

* strict guard for custom fields

* fix small strict issues

* ensure deep copy

* safely set isStale

* todo is done

* small type error

* these functions can work on DAO entries

* only reat rundown as DAO on initial load and the cast immediately and esure all fields are present

* eslint comment

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* fix spelling

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* fix spelling

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* comment not needed

* setIsStale

* remove DAO

* clean up commits

* remove unneeded async/await

* revert test

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2025-01-05 14:35:58 +01:00
Carlos Valente 1b62ed5f2d bump version to 3.10.1 2025-01-04 23:12:57 +01:00
Carlos Valente bd0c951da8 declare env variables 2025-01-04 23:12:57 +01:00
Carlos Valente 2d5b86808f refactor: cleanup pin styles 2025-01-04 16:39:47 +01:00
Carlos Valente c69bce3e89 refactor: cleanup picker implementations 2025-01-03 13:02:26 +01:00
Carlos Valente d62e314d19 bump version to 3.10.0 2025-01-03 12:56:37 +01:00
Shobhit-Nagpal dbd56522f6 refactor: swatch picker and inline colour picker 2025-01-02 21:30:41 +01:00
Shobhit-Nagpal 1ba48c6a6f refactor: inline colour picker 2025-01-02 21:30:41 +01:00
Carlos Valente f4f24da47b refactor: stop port change in dev 2025-01-02 14:18:19 +01:00
Carlos Valente c3609b2aed chore: extract middleware config 2025-01-02 14:18:19 +01:00
Carlos Valente 260d326989 chore: add noindex to app entry 2024-12-31 23:20:28 +01:00
Carlos Valente a21e32a097 refactor: expose indent style 2024-12-31 15:01:34 +01:00
Carlos Valente 617e4b579b refactor: introduce empty placeholder 2024-12-31 15:01:34 +01:00
Carlos Valente 44f65b2fcc refactor: extract utility 2024-12-31 13:04:00 +01:00
Carlos Valente 760de608e3 refactor: simplify logic 2024-12-31 13:01:22 +01:00
Carlos Valente 0dfef732bf refactor: prevent race conditions on init 2024-12-29 22:53:41 +01:00
Carlos Valente f65ec0da3c chore: upgrade dependencies 2024-12-29 20:02:56 +01:00
Shobhit Nagpal 6bbf8ce795 refactor: event editor color picker (#1400)
* refactor: event editor color picker

* refactor: throttle and debounce function signature
2024-12-27 10:57:48 +01:00
Carlos Valente 7f39d035fd refactor: show delayed times 2024-12-22 21:43:37 +01:00
Carlos Valente bdd2a62cee feat: allow editing times in cuesheet 2024-12-22 21:43:37 +01:00
Carlos Valente b38a7e5c92 refactor: allow submitting same value 2024-12-22 21:43:37 +01:00
Carlos Valente b173b5a8e8 chore: update manifest 2024-12-22 20:06:35 +01:00
Alex Christoffer Rasmussen 29243e3f6c detect EADDRINUSE on server start (#1348)
* detect `EADDRINUSE` on server start

* @ts-expect-error

* send portError to electron

* use escalateErrorFn

* dont move in docker

* allow errors to be sendt to electron UI

* Log after the new port is found

* Update comment

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* update comment

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* update comment

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* rename to escalate

* extract `serverTryDesiredPort`

* type check server.address()

* request shutdown on `unrecoverable` `escalateError`

* combine network utils

* reject promise

* not unrecoverable by default

* unneeded assignment

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-12-22 16:23:47 +01:00
Carlos Valente 1af394cd49 chore: upgrade turbo 2024-12-21 22:46:07 +01:00
Carlos Valente 1c85265623 fix: section can only be selected if parent is 2024-12-21 13:56:23 +01:00
Carlos Valente 6199d0ad10 refactor: improve section style and composition 2024-12-20 21:24:34 +01:00
Carlos Valente 2f2c26ed00 chore: rename time-to-end to count-to-end 2024-12-20 21:24:34 +01:00
Carlos Valente c9ef2465f8 refactor: visibility options 2024-12-20 21:15:26 +01:00
Carlos Valente 430b72c1d0 fix: missing return when data is handled 2024-12-20 21:15:26 +01:00
Carlos Valente 88b114020b feat: edit duration in cuesheet 2024-12-20 21:15:26 +01:00
Carlos Valente c445c42f8a refactor: extract edit element in table 2024-12-20 21:15:26 +01:00
Carlos Valente 2fc4e6da16 refactor: extract utility type 2024-12-20 21:15:26 +01:00
Carlos Valente 4cbe25a845 refactor: simplify update functions 2024-12-20 21:15:26 +01:00
Carlos Valente ab6765b332 refactor: tweak table element styles 2024-12-20 21:15:26 +01:00
Carlos Valente fb38d82855 refactor: show cuesheet as long as we have data 2024-12-20 21:15:26 +01:00
Carlos Valente 1061ed2a0e refactor: improve fallback timer consistency 2024-12-20 15:27:57 +01:00
Carlos Valente 3d37f42fe0 refactor: tweak styling 2024-12-20 09:03:02 +01:00
Carlos Valente 1bdea8e436 refactor: edit cue field 2024-12-20 09:03:02 +01:00
Carlos Valente 2c25910863 refactor: add table actions 2024-12-20 09:03:02 +01:00
Carlos Valente 8f30c0a7df refactor: restructure element composition 2024-12-20 09:03:02 +01:00
Carlos Valente 67fa747aae refactor: extract cuesheet dnd 2024-12-20 09:03:02 +01:00
Carlos Valente 8116b169b2 refactor: generalise event editor 2024-12-20 09:03:02 +01:00
Carlos Valente ec823e0095 refactor: improve cuesheet composition
refactor: simplify placing events in rundown

m
2024-12-20 09:03:02 +01:00
Carlos Valente c7faab00a3 feat: create offline indicator 2024-12-19 22:15:48 +01:00
Alex Christoffer Rasmussen cfcf6a5684 extract isPlaybackActive to a global util function (#1393) 2024-12-18 12:44:48 +01:00
Carlos Valente df1cf7a96b feat: parse timeToEnd from excel 2024-12-16 21:59:38 +01:00
Carlos Valente 0f3feca7ab refactor: extract time-to-end 2024-12-16 21:59:38 +01:00
Carlos Valente 41fe213ebb refactor: settings in params 2024-12-16 15:13:49 +01:00
Carlos Valente e91d5f5cd9 refactor: always show settings 2024-12-16 15:13:49 +01:00
Carlos Valente bedab221d9 chore: dedupe lock file 2024-12-16 15:13:49 +01:00
Carlos Valente 97208c052a chore: upgrade dependencies 2024-12-16 15:13:49 +01:00
Alex Christoffer Rasmussen b048d0f88d Edit in cuesheet (#1372)
* pass on all event edits

* MakePublic

* trim value in cell

* edit notes

* title

* add key check

* don't log error

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

* checkbox

* refactor

* remove log

* fix test

* use row number to test value

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-12-16 14:27:25 +01:00
asharonbaltazar d8f7d4bba6 feat(ui): add warning in view params when styles are overriden (#1384)
* feat: add warning in view params when styles are overriden

* refactor: style tweaks

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-12-15 10:40:27 -05:00
Carlos Valente ed65a4db67 refactor: smaller settings 2024-12-15 11:04:15 +01:00
Carlos Valente 4a70bcfe64 chore: remove unused 2024-12-15 11:04:15 +01:00
Carlos Valente 89e68c3b0e fix: correct aria label 2024-12-15 11:04:15 +01:00
Carlos Valente 976dc9cbde refactor: tweak header style 2024-12-15 11:04:15 +01:00
Carlos Valente 3701ba5174 refactor: handle missing data 2024-12-15 11:04:15 +01:00
Carlos Valente acc6ba63ba refactor: keep drawer open on submit 2024-12-15 11:04:15 +01:00
Carlos Valente 6c5afcb8d9 refactor: improve empty state for pages 2024-12-15 09:55:52 +01:00
Carlos Valente d46dfcf82e refactor: improve redirect 2024-12-14 08:25:53 +01:00
Carlos Valente 4c6acc4013 refactor: improve active styles for navigation buttons 2024-12-13 11:24:03 +01:00
Carlos Valente 26a24449de refactor: prevent modal close on click outside 2024-12-13 10:40:16 +01:00
Carlos Valente a1fb642441 bump version to 3.9.5 2024-12-13 10:40:16 +01:00
Carlos Valente b64b154330 refactor: disable shutdown 2024-12-13 10:39:58 +01:00
Carlos Valente 5032cbf65a refactor: prevent instantiating unavailable services 2024-12-13 10:39:58 +01:00
Carlos Valente 466360f9d1 chore: note service limitations 2024-12-13 10:39:58 +01:00
Carlos Valente ef2ea9a1da fix: recover edit menu and shortcuts 2024-12-13 10:39:45 +01:00
Carlos Valente fb83f48752 refactor: maintain an isOnline flag in client 2024-12-13 10:39:30 +01:00
Carlos Valente c1d53b0e55 refactor: improve empty state for project info 2024-12-13 10:12:06 +01:00
Alex Christoffer Rasmussen 7915cc822d Dockersafe rename (#1370)
* add dockerSafeRename function

* replace all rename functions

* add explanation to function
2024-12-10 23:27:51 +01:00
Carlos Valente 7dbf64d100 chore: restructure directory 2024-12-10 15:53:53 +01:00
Carlos Valente 6ffbf2af9d chore: move files to new structure 2024-12-10 15:53:53 +01:00
Carlos Valente fa7ec623f1 bump version to 3.9.4 2024-12-08 08:52:18 +01:00
Carlos Valente bfb9b51073 fix: secure protocol resolution 2024-12-08 08:52:18 +01:00
Carlos Valente 8bc3f5a56c Fix links (#1366)
* chore: remove unused code

* bump version to 3.9.3

* chore: use constant links

* refactor: build links

* chore: ignore ontime-data
2024-12-06 16:48:35 +01:00
Carlos Valente acf1afb5e9 fix: prevent overflow 2024-12-06 14:54:41 +01:00
Carlos Valente d8e2a8d092 bump version to 3.9.2 2024-12-04 21:41:49 +01:00
Carlos Valente 8e587128a1 refactor: ensure element height 2024-12-04 21:41:49 +01:00
Alex Christoffer Rasmussen 607bc40673 create addTime function in simple timer (#1363)
* create addTime function in simple timer
2024-12-04 20:25:49 +01:00
Carlos Valente e6aa7404f7 chore: correct documentation 2024-12-04 19:49:49 +01:00
Carlos Valente d622a7738f refactor: remove deprecated field 2024-12-04 19:49:49 +01:00
Carlos Valente b9ba416366 refactor: add prefix to relative assets
refactor: add prefix to server entrypoints
refactor: add prefix to express router
refactor: add prefix to router basename
2024-12-04 19:49:49 +01:00
Carlos Valente b3ce247f54 bump version to 3.9.1 2024-12-02 14:45:57 +01:00
Carlos Valente 82a2660fbc fix: router prefix 2024-12-02 14:45:57 +01:00
Carlos Valente 1e8706aa73 feat: allow add time to aux timer 2024-12-02 13:30:22 +01:00
Carlos Valente 7dec32aea7 bump version to 3.9.0 2024-12-02 13:30:11 +01:00
Carlos Valente 7e4cf6ffce refactor: improve time added display 2024-12-01 21:06:33 +01:00
Carlos Valente e6dfe9c363 fix: rolling over midnight wrongly classified as skip 2024-12-01 21:06:33 +01:00
Carlos Valente 29e682ee06 refactor: remove frozen implementation 2024-11-30 22:31:18 +01:00
Carlos Valente 55d349877b fix: prevent stale data in finder 2024-11-30 22:30:19 +01:00
Alex Christoffer Rasmussen 8f2a93d6a3 FIX: OSC TX and RX shutdown was swapped (#1352) 2024-11-30 22:27:36 +01:00
Carlos Valente 6529a05e2a fix: previous eventid is any entry 2024-11-30 21:59:53 +01:00
Alex Christoffer Rasmussen 0f5c47bc82 Small fixes (#1345)
* cleanup: remove console log

* use UI Index
2024-11-30 10:11:36 +01:00
Carlos Valente f561e52bb5 refactor: prevent caching html files 2024-11-29 19:36:39 +01:00
Carlos Valente 35f4472daa chore: define test workspaces 2024-11-29 19:36:39 +01:00
Carlos Valente 272f788c15 refactor: split vendor 2024-11-29 19:36:39 +01:00
Carlos Valente 85b71627a8 refactor: exclude html from compression 2024-11-29 19:36:39 +01:00
Carlos Valente 6e51e5083b refactor: allow route prefix 2024-11-29 19:36:39 +01:00
Ary Neto 1f998fda74 reverted unnecessary change 2024-11-28 22:10:48 +01:00
Ary Neto e7b5baa49a fix: file picker opening on delete 2024-11-28 22:10:48 +01:00
Carlos Valente f3f4cdb19f feat: add support for chinese 2024-11-25 09:55:07 +01:00
Carlos Valente b489214004 refactor: allow copy-paste in interface 2024-11-25 09:54:43 +01:00
Carlos Valente cc55414b57 refactor: show project description 2024-11-25 09:54:43 +01:00
Carlos Valente e694cb7556 refactor: style tweaks to cuesheet 2024-11-25 09:54:43 +01:00
Carlos Valente 988100c1d9 chore: remove extra character 2024-11-25 09:54:04 +01:00
Carlos Valente b4eabfae72 feat: trigger welcome modal from electron 2024-11-25 09:54:04 +01:00
Carlos Valente 22fe65c655 feat: show welcome screen on first login 2024-11-25 09:54:04 +01:00
Carlos Valente 7bf90d669a refactor: expose api for loading demo project 2024-11-25 09:54:04 +01:00
Carlos Valente a518dc4882 refactor: consolidate event editor styles 2024-11-25 09:54:04 +01:00
Carlos Valente dd5ffb2f47 refactor: improve app data 2024-11-25 09:54:04 +01:00
Carlos Valente c5a5eab225 refactor: extract utility hook 2024-11-25 09:54:04 +01:00
Carlos Valente 5d6345717f chore: update ontime assets 2024-11-25 09:54:04 +01:00
asharonbaltazar 4c88f90a15 feat(ui): disable menu buttons with locked param (#1332)
* feat: add lock icon when param `locked=true`

* chore: move `isViewLocked` logic up the component tree

* chore: remove extra container from lock icon

* chore: move fading logic into separate hook

* chore: move locked icon into separate component

* chore: rename variables
2024-11-18 09:49:49 -05:00
Carlos Valente 238eb49b5c bump version to 3.8.0 2024-11-18 14:57:40 +01:00
Carlos Valente 7aec3e0d73 feat: project info view 2024-11-18 14:56:30 +01:00
Carlos Valente 312b294a61 refactor: update test 2024-11-18 14:56:30 +01:00
Carlos Valente 9bfa3e9f8e feat: implement logo in all views 2024-11-18 13:48:05 +01:00
Carlos Valente 9a2cfb59e7 fix: issue with colour string sanitation 2024-11-18 13:12:50 +01:00
Ary a6e1cbbbce Upload corporate logo (#1314)
* feat: upload logo to project data

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-11-17 22:55:20 +01:00
Carlos Valente 8dd448db44 feat: implement naive client ping 2024-11-17 21:41:10 +01:00
Carlos Valente d87542dcf7 refactor: add cloud runtime 2024-11-17 21:41:10 +01:00
Carlos Valente 18575fc558 fix: separator collides with space indicator 2024-11-13 20:23:04 +01:00
Carlos Valente 04e2593939 style: clarify select component 2024-11-13 20:23:04 +01:00
Carlos Valente 73d6b97afa fix: issue with casing in custom fields 2024-11-13 20:23:04 +01:00
Carlos Valente b55724ad0e bump version to 3.7.1 2024-11-12 21:46:31 +01:00
Carlos Valente 3a7c2b8a55 refactor: refetch on load 2024-11-12 21:46:31 +01:00
Carlos Valente 420dfae652 refactor: clarify url preset form 2024-11-09 13:35:43 +01:00
Carlos Valente fb6896de76 refactor: show timer clock in preview 2024-11-07 21:39:04 +01:00
Carlos Valente f574fdbc02 refactor: hide progress bar in timer none 2024-11-07 21:39:04 +01:00
Carlos Valente 597be4e710 refactor: omit modifier in timer type none 2024-11-07 21:39:04 +01:00
Carlos Valente 6e8734c73f fix: prevent stale data on project change 2024-11-07 21:33:20 +01:00
Carlos Valente 9440ad17d2 refactor: show leading zeroes in minimal 2024-11-07 21:33:07 +01:00
Carlos Valente 9ba94288a1 refactor: remove style override 2024-11-01 15:42:32 +01:00
Carlos Valente 6c78d25af1 fix: issue with rem 2024-11-01 15:42:32 +01:00
Carlos Valente 0d8c186c77 feat: add time type none 2024-11-01 15:40:42 +01:00
Carlos Valente 7ccd41eeee fix: validation cycle 2024-10-29 20:23:12 +01:00
Carlos Valente 43b390a079 refactor: register modal in electron 2024-10-29 20:23:12 +01:00
Carlos Valente 80ff3251ea refactor: allow two NIF links in macbook screens 2024-10-29 20:23:12 +01:00
Carlos Valente 3591b93c2d refactor: handle thrown errors 2024-10-29 20:23:12 +01:00
Carlos Valente b637621871 refactor: guarantee minimum width 2024-10-29 20:23:12 +01:00
Carlos Valente ed2efe183b feat: quick project wizard 2024-10-29 20:23:12 +01:00
Carlos Valente 27f99b4c87 refactor: generalise modal footer style 2024-10-29 20:23:12 +01:00
Carlos Valente ed4d0f060b fix: reset rem value 2024-10-29 20:23:12 +01:00
Carlos Valente 7c19c52332 chore: directory restructure
merge with directory
2024-10-29 20:23:12 +01:00
Carlos Valente b1bff22b84 refactor: improve visibility of time-to-end 2024-10-29 20:02:23 +01:00
Carlos Valente 83b9fde45e refactor: improve visibility of extract element 2024-10-29 20:02:23 +01:00
Carlos Valente 37974df5c6 fix: allow changing custom field colour 2024-10-29 09:42:11 +01:00
Carlos Valente 161ec383fd refactor: unify localhost logic 2024-10-29 09:42:01 +01:00
Carlos Valente de38f9d467 refactor: show new app version 2024-10-29 09:42:01 +01:00
Carlos Valente 8ad1f2cb38 refactor: no style overrides in production views 2024-10-29 08:23:44 +01:00
Carlos Valente 143917f11a feat: event finder 2024-10-26 11:57:20 +02:00
Carlos Valente a8756c8afe refactor: clear state on sheet flows 2024-10-25 21:58:37 +02:00
Carlos Valente 5501f57b45 feat: add link to context menu 2024-10-25 19:44:55 +02:00
Carlos Valente 46e9fcb3cb refactor: populate readme on start 2024-10-22 21:18:33 +02:00
Carlos Valente f2d7f4ab82 bump version to 3.6.2 2024-10-22 20:24:22 +02:00
Alex Christoffer Rasmussen a5496434f8 todo note about sanitiseCustomFields (#1281) 2024-10-22 19:13:24 +02:00
Alex Christoffer Rasmussen 42984eed87 Improve xlsx import (#1271)
* use xlsx

* add existing custom fields to import map

* keep colours of existing custom fields

* use unknown

* fix

* revert

* allow space and upper case

* fix test

* define empty sheet
2024-10-22 19:13:07 +02:00
Carlos Valente 59c1c77d48 refactor: timeline has overrideable styles 2024-10-21 22:16:18 +02:00
Carlos Valente dd13eb31d8 refactor: expose public dir 2024-10-20 22:35:26 +02:00
Carlos Valente 82810f1cb1 feat: add sessions stats endpoint 2024-10-20 22:35:26 +02:00
Carlos Valente 71c468d069 refactor: session resource 2024-10-20 22:35:26 +02:00
Carlos Valente cf40001a2a improve style 2024-10-19 20:34:00 +02:00
arc-alex d458928090 fix external path and remove unneeded stuff 2024-10-19 20:34:00 +02:00
Carlos Valente 76e12af116 docs: add initial documentation to external assets 2024-10-19 20:34:00 +02:00
Carlos Valente b577057768 refactor: notes as data source 2024-10-19 20:33:36 +02:00
Carlos Valente dd4a165b08 refactor: add nif to navigation 2024-10-19 20:33:20 +02:00
Carlos Valente ab847a324b refactor: timer strategy is default 2024-10-19 14:31:58 +02:00
Carlos Valente cc5c097ddc refactor: tooltips for time locks 2024-10-19 14:31:58 +02:00
jwetzell ea2330e23b add invisible shortcuts for zooming in 2024-10-18 19:40:21 +02:00
jwetzell c5870452e3 make custom fields case sensitive (#1242)
* remove custom field lowercasing

* don't allow custom field form to submit duplicate field

* remove unused

* update custom field tests

* also keep upper case when editing

* show key in UI

* also kep upper case when creating a new field

* fix test

* allow old forced case keys to stay as is

* allow space

* add extension to import

* supply initial key to CustomFieldForm

* refactor: improve element contrast

* refactor: style and composition

* consistent use of `customFieldLabelToKey`

* fix CopyTag

* remove log

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-10-18 18:53:23 +02:00
Alex Christoffer Rasmussen b73b529c00 hide seconds toggle in cuesheet (#1272) 2024-10-18 13:08:34 +02:00
Carlos Valente 8ef807d6cb refactor: items active by default 2024-10-16 16:34:57 +02:00
Carlos Valente 1d4ddea596 chore: extract views directory 2024-10-15 22:28:50 +02:00
Carlos Valente 4cba970cda feat: add loader to views 2024-10-15 22:28:50 +02:00
Carlos Valente bad9dab0a0 refactor: compound timeline 2024-10-15 22:28:50 +02:00
Carlos Valente f11218a757 refactor: control container growth 2024-10-15 22:28:50 +02:00
Carlos Valente 77e87e1d0c refactor: make message service stateless 2024-10-15 16:11:53 +02:00
Carlos Valente a4aa513d1f refactor: share store initial state 2024-10-15 16:11:53 +02:00
Carlos Valente b73448f827 feat: implement colour picker 2024-10-15 16:01:42 +02:00
Carlos Valente 687ad68726 refactor: recover style override 2024-10-15 16:01:42 +02:00
Carlos Valente 089eba3877 refactor: param type colour 2024-10-15 16:01:42 +02:00
Carlos Valente 24b0cfd24e chore: consistent naming in externals 2024-10-15 15:51:01 +02:00
Carlos Valente 5950551da2 refactor: simplify setup of asset paths 2024-10-15 15:51:01 +02:00
Carlos Valente e46948772e refactor: network interfaces can be copied or followed 2024-10-13 20:39:58 +02:00
Carlos Valente 78fa1df99c refactor: blink style 2024-10-12 11:02:26 +02:00
Alex Christoffer Rasmussen 0500368982 Revert http test (#1257)
* Revert "refactor: allow messages not starting with http"

This reverts commit 887e5c448e.

* Revert "refactor: allow messages not starting with http"

This reverts commit 6ce275da7a.
2024-10-12 10:52:14 +02:00
Carlos Valente 2d53323f60 refactor: unify time to start logic 2024-10-11 16:01:44 +02:00
Carlos Valente 08ca3cd3a5 fix: calculate time to start 2024-10-11 16:01:44 +02:00
Carlos Valente 16fd44a441 refactor: allow aux change direction while playing 2024-10-11 16:01:22 +02:00
Carlos Valente 9a6ca7ac67 refactor: show electron dev tools 2024-10-11 13:26:15 +02:00
Carlos Valente 2c63bbff76 refactor: arrow used in new window navigation 2024-10-11 13:26:15 +02:00
Carlos Valente d2c34757f9 refactor: navigate in electron 2024-10-11 13:26:15 +02:00
Carlos Valente aeadc78578 refactor: remove unused db 2024-10-11 13:26:15 +02:00
Carlos Valente bf98f9792a feat: open asset directories 2024-10-11 13:26:15 +02:00
Carlos Valente 6d2b59ef73 refactor: collocate view navigation 2024-10-11 13:26:15 +02:00
Carlos Valente 0a53018930 refactor: improve native menu links 2024-10-11 13:26:15 +02:00
Carlos Valente f1cac8d1c4 feat: allow download of current project 2024-10-11 13:26:15 +02:00
Carlos Valente cfb76153a0 refactor: create project form state from params 2024-10-11 13:26:15 +02:00
Alex Christoffer Rasmussen fee2021ad7 Fix: time-to-end offset (#1252)
* flip the sign correctly for time-to-end offset
2024-10-10 16:20:59 +02:00
Carlos Valente db956f7955 refactor: await init rundown 2024-10-09 20:15:10 +02:00
Carlos Valente 887e5c448e refactor: allow messages not starting with http 2024-10-09 19:19:20 +02:00
Carlos Valente 6ce275da7a refactor: allow messages not starting with http 2024-10-09 19:19:20 +02:00
Carlos Valente 213f516f71 refactor: message does not have negative style 2024-10-09 19:18:47 +02:00
Alex Christoffer Rasmussen 86e6f8b58c bump version to 3.6.1 (#1237) 2024-10-03 14:50:05 +02:00
Carlos Valente 1de062a38e refactor: remove alt shortcut 2024-10-03 08:35:56 +02:00
Carlos Valente eb7a30fcf3 refactor: improve resizing of column 2024-10-02 22:34:19 +02:00
Carlos Valente e2cbe43a2b fix: form element alignment in form 2024-10-02 21:57:52 +02:00
Carlos Valente 7877af571f fix: apply delay 2024-10-02 21:44:03 +02:00
Carlos Valente 086bd5b644 docs: add discord link 2024-10-01 08:18:19 +02:00
Carlos Valente f045cf2292 bump version to 3.6.0 2024-09-28 20:41:21 +02:00
Alex Christoffer Rasmussen 78e2f217a4 handle timer type whitespace (#1225) 2024-09-28 20:34:04 +02:00
Carlos Valente 8a5cef79a8 refactor: simplify secondary styles 2024-09-27 20:14:58 +02:00
Carlos Valente 4d8bea2940 feat: timer preview 2024-09-27 20:14:58 +02:00
Carlos Valente fa709dc9be fix: issue where event next was stale 2024-09-24 22:25:45 +02:00
Carlos Valente 177c9a35ec feat: electron links open in browser 2024-09-24 13:46:09 +02:00
Carlos Valente 7f7691a452 fix: stop integration if output disabled 2024-09-23 19:39:19 +02:00
Carlos Valente 92a16ea33b refactor: migrate fit text logic 2024-09-23 16:56:15 +02:00
Carlos Valente bc6b7c5596 refactor: fit user message in screen 2024-09-23 16:56:15 +02:00
Carlos Valente 66083813f9 refactor: allow local shutdown 2024-09-23 16:55:22 +02:00
Carlos Valente d8cf1abb37 docs: warn of shutdown conditions 2024-09-23 16:55:22 +02:00
Carlos Valente 5b471980f5 refactor: enable timer type and end action default settings 2024-09-09 10:15:55 +02:00
Carlos Valente ad8f6dfcc7 bump version to 3.5.1 2024-09-07 08:49:39 +02:00
Carlos Valente 4706ed39f6 refactor: scope rundown to selected 2024-09-07 08:46:32 +02:00
Carlos Valente a8182cac8c refactor: simplify logic 2024-09-07 08:46:32 +02:00
Carlos Valente f9a5c55c07 refactor: reactive options 2024-09-07 08:46:32 +02:00
Carlos Valente 980ae7a7c5 refactor: show upcoming events 2024-09-07 08:46:32 +02:00
Carlos Valente db8ed93d41 fix: handle multiple days 2024-09-07 08:46:32 +02:00
Carlos Valente f8ca5b9cef fix: clear internal state on stop 2024-09-07 08:45:43 +02:00
Carlos Valente b9db08089f fix: ignore 0 duration events 2024-09-07 08:45:43 +02:00
Carlos Valente a3020ef3b2 fix: issue with roll evaluating multiple days 2024-09-07 08:45:43 +02:00
Carlos Valente 2492972097 fix: incorrect falsy check 2024-09-04 09:28:15 +02:00
Alex Christoffer Rasmussen aa4ee546ec Merge import (#1164)
---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-09-01 20:38:59 +02:00
Carlos Valente 0abaf7724d refactor: refetch on change 2024-09-01 17:18:48 +02:00
Carlos Valente 7b932ef0f7 refactor: add options to hide schedule 2024-09-01 10:41:54 +02:00
Carlos Valente 8bd7645c95 ui: rename mode to match UI 2024-08-31 10:55:32 +02:00
Carlos Valente 81f0e61953 refactor: add extra data to sentry logs 2024-08-29 15:10:42 +02:00
Carlos Valente 3877e207d0 chore: remove incorrect label 2024-08-27 14:21:35 +02:00
Carlos Valente d78e8838c3 bump version to 3.5.0 2024-08-27 13:16:01 +02:00
Carlos Valente 16c7107069 chore: mark timeline as beta 2024-08-27 13:16:01 +02:00
Alex Christoffer Rasmussen e20cd87673 fix: stop log incorrectly (#1185)
* fix: stop log incorrectly

* prevent start if already playing
2024-08-27 13:09:39 +02:00
Alex Christoffer Rasmussen db5fbd8019 add time in block to restore point (#1192) 2024-08-27 13:08:16 +02:00
Gyuris Gellért 25aefe322b Hungarian translation (#1187)
* Add Hungarian translation
2024-08-27 13:06:23 +02:00
Carlos Valente 73db14c383 refactor: show running gap in UI 2024-08-27 12:58:18 +02:00
Carlos Valente f5936e5254 refactor: unify logic 2024-08-27 12:58:18 +02:00
Carlos Valente 25c7915cf7 refactor: account for overlapping in rundown 2024-08-27 12:58:18 +02:00
Carlos Valente c43b6f37f9 refactor: accumulate times 2024-08-27 12:58:18 +02:00
Carlos Valente 6e5034ef72 refactor: show progress on top 2024-08-27 12:58:18 +02:00
Carlos Valente 66774321a5 refactor: calculate rundown duration 2024-08-27 12:58:18 +02:00
Carlos Valente d71df886f2 style: clarify function scope 2024-08-27 12:58:18 +02:00
Carlos Valente abcee741e2 refactor: prevent index collision 2024-08-27 12:58:18 +02:00
Alex Christoffer Rasmussen ee1b5b7fdd Keep offset when taking over playback with roll v2 (#1184)
* pass on offset

* account for offset in roll

* prevent roll from overtime

* add test
2024-08-26 18:09:03 +02:00
Alex Christoffer Rasmussen 1b1823e0fe Fix: change api endpoint (#1183)
* remove async from parseProperty

* swap shouldThrottle check

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-08-20 11:22:02 +02:00
Alex Christoffer Rasmussen 340f5478fb add shortcut to jump between blocks (#1181)
* add shortcut

* chore: rename getRelevantBlock to getPreviousBlock
2024-08-19 17:20:58 +02:00
Alex Christoffer Rasmussen f708dc0bc4 Fix current block (#1170)
* pass full rundown to loadNow

* remove prevBlock from state

* refactor: simplify load logic (#1174)

* send clock to client on block start to avoid it showing -1 in the client

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-08-15 16:25:29 +02:00
Carlos Valente 49467c66b7 fix: check worksheet errors before submit 2024-08-15 11:12:21 +02:00
Carlos Valente b539b2ecd5 refactor: review styles and implement BEM for user override 2024-08-13 21:54:43 +02:00
Alex Christoffer Rasmussen dc06a9afc3 fix TimerPahse difference from load and reload (#1179)
* use loadEvent function to reload

* rename reload to updateLoaded
2024-08-12 20:14:06 +02:00
Carlos Valente d3620b52f4 refactor: only broadcast public 2024-08-11 18:18:53 +02:00
Carlos Valente 66ed92e215 fix: stop playback when event is deleted 2024-08-10 12:50:30 +02:00
Carlos Valente 347f333b3e refactor: unify progress bar logic 2024-08-09 22:51:50 +02:00
Carlos Valente c3fb3061f6 fix: use unfiltered events in timeline 2024-08-09 20:01:30 +02:00
Carlos Valente a26aa9e01c bump version to 3.5.0-beta.2 2024-08-04 21:37:01 +02:00
Carlos Valente da11ef64c2 refactor: roll mode
* chore: escalate stack trace to console

* refactor: event finding in roll

* docs: initial roll specification

* refactor: call to roll

* refactor: normalise index

* refactor: roll into next event

* refactor: hot reload on waiting to roll

* refactor: wait to roll next
2024-08-04 21:34:01 +02:00
Carlos Valente 3012d73285 feat: timeline view 2024-08-04 21:32:25 +02:00
Alex Christoffer Rasmussen bad491063d fix: getShouldClockUpdate test (#1165)
* useFakeTimers

* now can never be negative
2024-07-31 16:58:02 +02:00
Alex Christoffer Rasmussen a103f8b347 show time in block (#1158) 2024-07-31 14:00:40 +02:00
Alex Christoffer Rasmussen dffccd258f prevent rare case of old customFields (#1163)
as part of subscriptions in operator
2024-07-30 15:42:37 +02:00
Alex Christoffer Rasmussen ce8b0d9850 FIX: remove '/' from host in client-control(#1156) 2024-07-30 12:36:31 +02:00
Alex Christoffer Rasmussen e500fa6b5e about in electron help menu (#1155) 2024-07-29 18:06:10 +02:00
Alex Christoffer Rasmussen 67be4a5631 restore rundownGetAll (#1162) 2024-07-29 13:29:56 +02:00
Alex Christoffer Rasmussen c7893938eb remove old l3 options (#1160) 2024-07-27 09:44:41 +02:00
Alex Christoffer Rasmussen 158ef05ff0 add relevantBlock function (#1100)
* feat: current block

* pass full rundown to functions and use filter utils
2024-07-23 12:22:47 +02:00
Carlos Valente 20838c038a chore: evaluate react 19 migration 2024-07-23 09:02:44 +02:00
Carlos Valente 1ddcec993a chore: upgrade sentry to react version 2024-07-22 22:27:10 +02:00
Alex Christoffer Rasmussen 91d6adf8e0 useFakeTimers for initRundown in tests (#1150) 2024-07-22 14:15:09 +02:00
Carlos Valente a7fe5eceef chore: upgrade sentry 2024-07-20 16:25:46 +02:00
jwetzell e6e00c0d4a add freeze feature to rundown (#1106)
* add frozen flag to runtime store

* add middleware for when frozen

* prevent rundown editing when frozen

* add endpoint to router to set frozen state

* add frozen property to rundown placeholder in client
2024-07-19 14:14:59 +02:00
Carlos Valente edc7f20d7a refactor: timer update 2024-07-19 14:11:12 +02:00
Carlos Valente cb773ded9f refactor: improve pending detection 2024-07-19 14:11:12 +02:00
Carlos Valente 2f65711078 refactor: dev label 2024-07-19 14:11:12 +02:00
jwetzell 3056b75960 clean out unused demo and test db.json files (#1148)
* remove demo and test db JSON

* remove demo-db reference in Dockerfile

* remove preloaded-db folder in server

* cleanup package.json scripts

* remove db.json references from server
2024-07-18 22:27:24 +02:00
jwetzell dd9423abf4 remove unused dependency 2024-07-18 22:26:58 +02:00
jwetzell dee6a67018 Merge pull request #1146 from cpvalente/chore/pnpm-catalogs
convert shared dependencies to pnpm catalog
2024-07-17 22:23:47 -05:00
jwetzell a79fb4ecbb convert shared dependencies to pnpm catalog 2024-07-17 07:53:43 -05:00
jwetzell a53a1f87be Merge pull request #1145 from cpvalente/chore/remove-husky
remove husky and pre-commit scripts
2024-07-17 07:41:17 -05:00
jwetzell ef9afcbf3e remove husky and pre-commit scripts 2024-07-16 17:57:20 -05:00
Carlos Valente 33b04e01c9 chore: cleanup unused 2024-07-16 21:34:21 +02:00
Carlos Valente c5e821df35 bump version to 3.4.0 2024-07-16 19:21:56 +02:00
jwetzell 0fd71c9a00 align docker-compose example with docker image layout 2024-07-16 19:20:05 +02:00
jwetzell 53b453abc8 change docker data path from /external to /data 2024-07-16 19:20:05 +02:00
Carlos Valente fe0665506e chore: update typescript 2024-07-16 13:18:20 +02:00
Carlos Valente 9bd600c4b1 chore: add watch mode in dev 2024-07-16 13:18:20 +02:00
jwetzell bbd4254637 Merge pull request #1138 from cpvalente/chore/bump-version
bump version to 3.4.0-beta.3
2024-07-15 08:23:16 -05:00
jwetzell 2603c777ef bump version to 3.4.0-beta.3 2024-07-15 07:23:00 -05:00
jwetzell 8942a4ba4f Merge pull request #1137 from cpvalente/fix/buildx-platforms
drop arm/v6 image
2024-07-15 07:20:32 -05:00
jwetzell f97be749dc drop arm/v6 image 2024-07-15 07:18:06 -05:00
Carlos Valente 5836d5ffc7 bump version to 3.4.0-beta.2 2024-07-15 10:28:58 +02:00
jwetzell 91f21fdeb1 Merge pull request #1134 from cpvalente/fix/docker-building
switch Dockerfile build stage to non-alpine image
2024-07-14 13:18:24 -05:00
jwetzell 844eec132b use npm to install specific pnpm version 2024-07-13 06:36:22 -05:00
jwetzell adc4b3f8bf switch Dockerfile build stage to non-alpine image 2024-07-12 21:12:57 -05:00
Carlos Valente fb09631db9 bump version to 3.4.0-beta 2024-07-11 14:44:02 +02:00
Carlos Valente 19febb98a5 bump version to 3.4.0.beta 2024-07-11 14:33:18 +02:00
Carlos Valente 6bfa11dd8d fix: format clock as timer 2024-07-11 13:31:25 +02:00
Carlos Valente 4758bc84b5 chore: upgrade node dependencies 2024-07-11 13:31:05 +02:00
Carlos Valente 917b182e39 feat: granular endpoints for rundown 2024-07-11 11:03:07 +02:00
Carlos Valente e6c3322321 feat: add list of changes to refetch 2024-07-11 11:03:07 +02:00
Carlos Valente 00d34eec9b refactor: emit load event on reload 2024-07-11 11:02:49 +02:00
Carlos Valente 84792bc00d refactor: initialise data 2024-07-11 11:02:22 +02:00
Carlos Valente dae32e89a3 refactor: patch project 2024-07-11 11:02:22 +02:00
Carlos Valente 367997fd16 refactor: simplify file checks 2024-07-11 11:02:22 +02:00
Carlos Valente 751c3329f0 refactor: load project 2024-07-11 11:02:22 +02:00
Carlos Valente 9c5e403b18 refactor: add directory for crash logs 2024-07-11 11:02:22 +02:00
Carlos Valente c944e77bc1 refactor: last project may not exist 2024-07-11 11:02:22 +02:00
Carlos Valente d94c1d4252 refactor: remove unnecessary check 2024-07-11 11:02:22 +02:00
Carlos Valente 9f395cb16d refactor: safe get info 2024-07-11 11:02:22 +02:00
Carlos Valente 46195fc043 refactor: rename project 2024-07-11 11:02:22 +02:00
Carlos Valente c9ef8d55c1 refactor: duplicate project 2024-07-11 11:02:22 +02:00
Carlos Valente ad0e821cc0 refactor: delete project 2024-07-11 11:02:22 +02:00
Carlos Valente 21454947e0 refactor: create project 2024-07-11 11:02:22 +02:00
Carlos Valente ad69c0ff80 refactor: project service boundaries 2024-07-11 11:02:22 +02:00
Carlos Valente 20d9df2501 refactor: escalate errors from parser 2024-07-11 11:02:22 +02:00
Carlos Valente de9af5aaa2 refactor: minor code cleanups 2024-07-11 11:02:22 +02:00
Carlos Valente 61280b06b7 refactor: simplify logic dynamic menus 2024-07-10 23:01:47 +02:00
Carlos Valente ce4a48cd8d refactor: extract options per view 2024-07-10 23:01:47 +02:00
Carlos Valente 2877475a35 refactor: allow reset selection by refreshing 2024-07-10 23:01:47 +02:00
Carlos Valente 73e23ee323 feat: projected times in countdown 2024-07-10 23:01:47 +02:00
Carlos Valente 938c5fbb4c refactor: offset cannot be null 2024-07-10 23:01:47 +02:00
Carlos Valente e90e94828d style: add npm badge 2024-07-09 09:30:01 +02:00
jwetzell 1f0401632e have electron dev script wait for local server instance 2024-07-03 22:31:20 +02:00
jwetzell 5c3989c9b6 switch workflows to release trigger (#1115)
* switch docker workflow to release trigger

* switch cli publish workflow to release trigger
2024-07-03 22:30:56 +02:00
Carlos Valente 6ad26f06c7 style: rename log feature 2024-07-02 16:56:23 +02:00
Carlos Valente a63fa68d39 bump version to 3.3.3 2024-06-23 23:02:14 +02:00
Carlos Valente 20503de6fd refactor: minor code cleanups 2024-06-23 22:07:34 +02:00
Carlos Valente 0335da9786 refactor: improve errors to user 2024-06-23 22:07:34 +02:00
Carlos Valente 9f1a64f53c chore: upgrade dependencies 2024-06-23 22:07:34 +02:00
Alex Christoffer Rasmussen 975356f4f4 events with 0 duration dose not contribute to next day calculation (#1099) 2024-06-23 22:06:44 +02:00
Carlos Valente 1b448835cd fix: duplicate validation 2024-06-23 16:17:03 +02:00
Carlos Valente cbf3d566b9 fix: prevent calling service before init 2024-06-23 11:50:49 +02:00
Carlos Valente 6c20cb5e99 refactor: remove size limits in title 2024-06-22 13:48:19 +02:00
Carlos Valente cfc3aab893 style: add background to highlight 2024-06-21 14:45:45 +02:00
Alex Christoffer Rasmussen b7c48f38a9 hotfix-build (#1091)
* skip  "alwaysStrict": true

* bump to 3.3.2

* remove all new ts check to be sure
2024-06-17 11:44:44 +02:00
Carlos Valente dcb6bfa62d bump version to 3.3.1 2024-06-17 08:21:01 +02:00
Carlos Valente 0abc4de3cd fix: column reordering in cuesheet 2024-06-17 08:14:12 +02:00
Carlos Valente f750ed3cdc style: match table header size 2024-06-17 08:14:12 +02:00
Carlos Valente f026c1c1e3 chore: run linter on imports 2024-06-17 08:10:14 +02:00
Piotr Górski ce176b01a2 Added Polish Translation (#1077) 2024-06-16 14:46:11 +02:00
Carlos Valente 337dd7892a chore: fix typo in donation text 2024-06-16 14:45:16 +02:00
Carlos Valente b7daf2926a refactor: improve typing 2024-06-16 09:07:01 +02:00
jwetzell 81a07099ae Merge pull request #1084 from cpvalente/fix/npm-publish-with-provenance
add permission for provenance publishing
2024-06-15 14:59:28 -05:00
jwetzell 8f88ca5053 add permission for provenance publishing
https://docs.npmjs.com/generating-provenance-statements
2024-06-15 14:59:16 -05:00
jwetzell 82a885dc44 Merge pull request #1082 from cpvalente/fix/publish-action
add registry url for publishing via CI
2024-06-15 13:33:58 -05:00
jwetzell c4be814de5 add registry url for publishing via CI 2024-06-15 13:33:08 -05:00
Carlos Valente 9f3186e249 bump version to 3.3.0 2024-06-15 17:30:58 +02:00
jwetzell 5159554697 Merge pull request #1080 from cpvalente/fix/npm-publish-action
disable git checks for pnpm publish workflow
2024-06-15 08:30:30 -05:00
jwetzell cf690aff08 disable git checks for pnpm publish workflow 2024-06-15 08:25:43 -05:00
Carlos Valente 48c4e5f429 bump version to 3.3.0 2024-06-15 15:10:24 +02:00
Carlos Valente ad0da6def4 fix: persistence of custom fields (#1078) 2024-06-15 15:07:20 +02:00
Alex Christoffer Rasmussen a15eb0db4c Client remote control (#930)
---------

Co-authored-by: kellhogs <fabianpos99@gmail.com>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-06-15 12:26:41 +02:00
jwetzell 70e8fbf327 add warning and danger transitions as timer life cycle events (#1071)
* setup detection of TImerPhase changes

* add integration event for transition to warning

* add integration event for transition to danger

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-06-15 09:54:29 +02:00
jwetzell 1044dfac01 Merge pull request #1051 from cpvalente/feat/ontime-headless
add a headless version of ontime
2024-06-13 20:11:00 -05:00
jwetzell b5e5c113e2 update lock file 2024-06-13 20:06:11 -05:00
Carlos Valente cbcff5e7ab docs: initial npm documentation 2024-06-13 20:04:08 -05:00
jwetzell 83cb2f82f5 add SIGHUP and SIGTERM to cli shutdown 2024-06-13 20:01:25 -05:00
jwetzell 837fd53dfd remove pkg bundling of cli 2024-06-13 20:01:04 -05:00
jwetzell 4962288a53 update package name for organization scoping 2024-06-13 19:59:47 -05:00
jwetzell 75a35e8537 add access flag to publish to organization 2024-06-13 19:59:47 -05:00
jwetzell 6e839fcefb rename bin to ontime 2024-06-13 19:59:47 -05:00
jwetzell 052a8e4ccb switch pkg to only build linux x64 and arm64 binaries 2024-06-13 19:59:47 -05:00
jwetzell 969c2bad14 add step to publish to NPM as well 2024-06-13 19:59:47 -05:00
jwetzell 9717222491 remove dev script from cli package.json 2024-06-13 19:59:47 -05:00
jwetzell 081c0bdac4 add necessary files to package.json for publishing 2024-06-13 19:59:47 -05:00
jwetzell 8b99e91883 add github workflow to build cli 2024-06-13 19:59:47 -05:00
jwetzell 4af2e688d1 add basic cli app for bundling a headless ontime 2024-06-13 19:59:47 -05:00
Luke Stein cf8c8d4b2e bump version to 3.2.0 2024-06-13 22:46:32 +02:00
Alex Christoffer Rasmussen 9e63261b35 None colour from API (#1063) 2024-06-12 21:31:08 +02:00
Alex Christoffer Rasmussen b1838a5e9a display multiple custom fields in operator view (#1001)
---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-06-12 14:25:26 +02:00
Alex Christoffer Rasmussen 9d7b5568e4 use port 3000 in dev mode (#1065) 2024-06-11 13:37:10 +02:00
Alex Christoffer Rasmussen 657aed1244 Fix coerce enum (#1064) 2024-06-11 13:03:34 +02:00
Carlos Valente 13c49f3652 chore: improve dev scripts 2024-06-10 18:26:18 +02:00
Carlos Valente 86b4ddadb5 chore: prepare log levels 2024-06-10 18:26:18 +02:00
Carlos Valente e9f806b88a style: organise console levels and semantics 2024-06-10 18:26:18 +02:00
Carlos Valente 4f672670ed chore: document aux functions 2024-06-10 18:26:18 +02:00
Carlos Valente 8742b790f3 refactor: escalate severe to electron 2024-06-10 18:26:18 +02:00
Carlos Valente d41cd78f2e refactor: add severe log level 2024-06-10 18:26:18 +02:00
Carlos Valente 715600a514 refactor: improve console visibility 2024-06-10 18:26:18 +02:00
Carlos Valente b99cf5f255 refactor: improve error states in spreadsheet flow 2024-06-09 22:04:41 +02:00
Carlos Valente 9a9a0eb7cf refactor: use timer phase while waiting 2024-06-08 13:47:26 +02:00
Carlos Valente 4bf2422ebc refactor: show next when waiting to roll 2024-06-08 13:47:26 +02:00
Michael Foster add769fe1e fix for MultiPartProgressBar styling (#1022) 2024-06-07 21:08:17 +02:00
Carlos Valente 3af4c64ff3 chore: upgrade lint dependencies 2024-06-07 20:15:43 +02:00
Alex Christoffer Rasmussen f405e65c55 Custom for timer title (#1055) 2024-06-07 15:24:29 +02:00
Alex Christoffer Rasmussen 0e32b3a3af Fix: link events in sheet when there is nothing to link (#1053)
* create failing tests

* fix missing optional chaining
2024-06-06 22:38:52 +02:00
Alex Christoffer Rasmussen c2fa115946 Validate project filename (#1046) 2024-06-06 22:37:41 +02:00
jwetzell edb48a2fc7 consider custom fields when loading operator main field (#1049) 2024-06-06 21:57:50 +02:00
Alex Christoffer Rasmussen 6f7846bbf7 fix and test only space osc payload (#1052) 2024-06-06 11:19:12 +02:00
Alex Christoffer Rasmussen 48ebd31c54 bump version to 3.1.1 (#1045) 2024-06-04 15:57:52 +02:00
Carlos Valente 6d1a911ab8 refactor: rename negative to overtime 2024-06-04 15:51:00 +02:00
Carlos Valente ee1753ef29 fix: account for pending timers 2024-06-04 15:51:00 +02:00
Carlos Valente 147e5f5a27 chore: remove unused dependencies 2024-06-03 22:38:57 +02:00
Carlos Valente a02b3faacc chore: bump version to 3.1.0 2024-06-03 22:38:57 +02:00
Alex Christoffer Rasmussen a3b21072eb keep the index row as a colour chip (#1039) 2024-06-03 22:38:22 +02:00
Carlos Valente 2076080c5f refactor: supress modifiers in count-up timers 2024-06-03 22:36:05 +02:00
Alex Christoffer Rasmussen 8b3abe9d61 fix: insert above shortcut (#1020)
refactor: unify setCursor and useEventSelection
2024-06-03 21:34:00 +02:00
Carlos Valente c2039866b4 refactor: fix missed first update (#1031) 2024-06-03 20:27:51 +02:00
Carlos Valente 73e4a15718 style: add label to auxiliary timer 2024-06-03 20:26:25 +02:00
asharonbaltazar c4359af2a0 feat:toggle index column (#1037)
* feat:add `showIndexColumn` boolean property to `CuesheetSettings`

* feat:use `showIndexColumn` to hide column index th/tr

* feat:pass `showIndexColumn` to components

* fix:update column headers naming
2024-06-03 14:21:11 -04:00
Carlos Valente f75f45b19a refactor: simplify client logic on timer phases 2024-06-03 20:18:19 +02:00
Carlos Valente fd2eee32aa refactor: declare timer phase 2024-06-03 20:18:19 +02:00
Carlos Valente a53d354b16 refactor: continue roll 2024-06-03 20:17:41 +02:00
Alex Christoffer Rasmussen ec55236eb2 fix: osc new project (#1032) 2024-06-02 18:01:36 +02:00
Alex Christoffer Rasmussen 3895b37572 Allow time change from api (#1009)
Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-06-02 15:21:09 +02:00
Julien Recurt d8626ff324 Add option to display the full time (HH:mm:ss) in the timer view (#988)
* Add option to display the full time (HH:mm:ss) in the timer view

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2024-06-01 13:39:15 +02:00
arc-alex 6c3870c15b catch getWorksheetNames 2024-05-31 22:17:17 +02:00
Carlos Valente 4fadb23b07 refactor: timer overrides do not affect minimal 2024-05-31 22:17:03 +02:00
Carlos Valente 199ed1617f fix: menu link to operator 2024-05-31 18:57:45 +02:00
Carlos Valente 2d618e0657 refactor: remove double import 2024-05-30 22:41:50 +02:00
Carlos Valente f928c1dc95 refactor: avoid unnecessary computer property 2024-05-30 22:41:50 +02:00
jwetzell 8d526c7d31 Merge pull request #1019 from cpvalente/cleanup-server-setup
remove redundant path evaluation
2024-05-30 07:57:23 -05:00
Carlos Valente 686c6108bf refactor: improve payload type for OSC (#954)
---------

Co-authored-by: Joel Wetzell <jwetzell@yahoo.com>
Co-authored-by: arc-alex <ac@omnivox.dk>
2024-05-30 13:02:22 +02:00
Carlos Valente ea3d33ca93 fix: correct key on shortcuts 2024-05-30 12:15:57 +02:00
jwetzell 6bf94ff645 remove redundant path evaluation 2024-05-29 16:25:15 -05:00
Carlos Valente 930cd71ffd chore: upgrade electron 2024-05-29 08:33:44 +02:00
Carlos Valente 45cf1cf199 chore: bump version to 3.0.4 2024-05-28 22:49:29 +02:00
Carlos Valente 354f464263 chore: user feedback 2024-05-28 22:49:29 +02:00
Carlos Valente c46a00febc chore: expand download links 2024-05-28 22:49:29 +02:00
Carlos Valente e991e151db refactor: improve dnd activation strategy 2024-05-28 22:45:10 +02:00
Carlos Valente b5993b91e1 fix: column reordering
refactor: migrate local storage hook
2024-05-28 22:45:10 +02:00
arc-alex 4beac19c4a Clear upload folder on startup 2024-05-28 22:44:55 +02:00
Carlos Valente be852f4546 refactor: allow hiding sidebar 2024-05-27 15:52:02 +02:00
Carlos Valente 84e224dd71 refactor: unify time parsing logic 2024-05-27 15:51:45 +02:00
Carlos Valente 7cbb2112ed refactor: simplify parsing logic 2024-05-27 15:51:45 +02:00
Carlos Valente ce910c9cc6 refactor: extract parseUserTime 2024-05-27 15:51:45 +02:00
Alex Christoffer Rasmussen 9d04954d87 fix change api isPublic (#1008) 2024-05-27 13:01:10 +02:00
Alex Christoffer Rasmussen 345ea6722e add notes to secondaryOptions in timer view (#1004) 2024-05-27 12:22:01 +02:00
Alex Christoffer Rasmussen f43221cf7a don't notify when aux timer is paused (#1003) 2024-05-27 11:51:07 +02:00
Carlos Valente a09aa922bb refactor: delete several events 2024-05-26 21:36:49 +02:00
Carlos Valente 16f31a07b7 chore: upgrade dependencies 2024-05-26 21:36:49 +02:00
Carlos Valente 77d111650a refactor: reduce scope of context 2024-05-26 21:36:49 +02:00
jwetzell 72891a69f4 Merge pull request #998 from cpvalente/fix/smart-time-parsing
address some issues in am/pm time parsing
2024-05-26 11:07:43 -05:00
Carlos Valente b8d5a30caf style: input text alignment 2024-05-25 15:19:01 +02:00
jwetzell 9cbd4c085b slim back tests even further and list out 2024-05-24 06:51:51 -05:00
jwetzell afe0323384 use let not var 2024-05-24 06:12:46 -05:00
jwetzell 1907abc512 pare back am/pm tests 2024-05-24 05:53:07 -05:00
jwetzell 834aafe06d remove need for hardcoded 12am test 2024-05-23 20:29:05 -05:00
jwetzell 98418014d3 lowercase time string before beginning to parse 2024-05-23 20:16:41 -05:00
jwetzell 3d13e784ea fix parsing am/pm times 2024-05-23 19:45:12 -05:00
jwetzell e397500d07 dynamically build am/pm tests 2024-05-23 19:17:36 -05:00
jwetzell c7c0241859 add new am/pm test cases for dateConfig util 2024-05-23 17:39:42 -05:00
Carlos Valente 71a7fe96d1 style: fix input overflow 2024-05-23 22:13:42 +02:00
jwetzell d0f958c13d Merge pull request #990 from cpvalente/fix/docker-build
fix docker multi-architecture build
2024-05-23 08:15:07 -05:00
jwetzell 7ee98fb062 remove node setup and build from docker action 2024-05-21 16:06:28 -05:00
jwetzell c2b66a4215 rework dockerfile to remove need for turbo 2024-05-21 16:06:15 -05:00
jwetzell 1d0ee10c00 remove build:docker from turbo 2024-05-21 16:05:49 -05:00
Carlos Valente 248c952ec7 chore: bump version to 3.0.3 2024-05-21 20:59:58 +02:00
jwetzell 3cda6b222e Merge pull request #983 from thelan/docker-multistage
Multistage docker build
2024-05-21 08:10:21 -05:00
Julien Recurt d161411416 Updating Dockerfile for multistage build based on feedbacks 2024-05-21 11:27:02 +02:00
Leon Eckardt 97b8e6a290 fix #984 Expected End of timeline is not calculated correctly (#985) 2024-05-20 22:28:23 +02:00
Carlos Valente 036d4051fc fix: account for skip in rundown calculations 2024-05-20 22:13:28 +02:00
Carlos Valente 7cefe07594 refactor: cap added time 2024-05-20 21:17:37 +02:00
Carlos Valente d05cc88748 refactor: unify time constants 2024-05-20 21:17:37 +02:00
Carlos Valente 119e6caca3 refactor: cap timer values 2024-05-20 21:17:37 +02:00
Carlos Valente bb199128aa style: rundown takes available space 2024-05-20 21:12:31 +02:00
Carlos Valente dade6f6692 style: tweaks to shortcut panel 2024-05-20 21:12:31 +02:00
Carlos Valente 6bedd7ab1d style: consistent spacing in editor 2024-05-20 21:12:31 +02:00
Carlos Valente eb2c4d0780 refactor: recover day after indicator 2024-05-20 21:11:52 +02:00
Carlos Valente 4069038ed5 chore: forgiving test 2024-05-20 19:32:28 +02:00
Carlos Valente ac430602b4 chore: upgrade vite dependencies 2024-05-20 19:32:28 +02:00
Carlos Valente 082449bede fix: handle finish when adding time 2024-05-20 19:32:28 +02:00
Carlos Valente cfbd540a14 style: expose bg override variable 2024-05-20 19:29:57 +02:00
Julien Recurt a431fab3c4 exclude compose generated volumes directory 2024-05-19 21:16:39 +02:00
Julien Recurt 770d975610 Update DEVELOPMENT.md 2024-05-19 20:44:42 +02:00
Julien Recurt 6f95aac798 Adding multistage build 2024-05-19 20:40:35 +02:00
Carlos Valente dae6f84af0 fix: excel parsing 2024-05-17 19:44:47 +02:00
Carlos Valente ad46fac2d7 chore: add tests to support docs 2024-05-15 21:28:02 +02:00
Carlos Valente 37786c3528 chore: bump version to 3.0.2 2024-05-13 14:15:18 +02:00
Carlos Valente c6d36d2497 refactor: forgiving test 2024-05-13 08:25:57 +02:00
Carlos Valente 2394eced93 refactor: forgiving test 2024-05-13 08:08:43 +02:00
Carlos Valente 13aeeb278d fix: filename may not exist 2024-05-13 08:08:43 +02:00
Carlos Valente af5d6e1aee fix: prevent stale selection 2024-05-13 08:06:28 +02:00
Carlos Valente bc036bdae7 refactor: forviging test
Allow a scenario where the operation execution happens in the next millisecond
2024-05-12 20:15:59 +02:00
Carlos Valente 266a84e5d3 chore: update keywords 2024-05-12 20:15:59 +02:00
Carlos Valente 92c3148e49 chore: bump version to 3.0.1 2024-05-12 20:15:59 +02:00
Carlos Valente efd05bcc34 refactor: simplify overview logic 2024-05-12 17:16:33 +02:00
Carlos Valente 3c7e061e51 refactor: improve detection of day after
fix: prevent mutation of initial object

refactor: download project file

Update apps/client/src/features/rundown/event-block/EventBlock.utils.ts

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>

Update apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
2024-05-12 17:16:33 +02:00
Carlos Valente 07074260a4 refactor: improve integration updates 2024-05-12 17:03:13 +02:00
Carlos Valente c57b0423af refactor: leading updates in timers 2024-05-12 17:03:13 +02:00
Carlos Valente 52145d5e1e chore: update element order 2024-05-11 14:58:28 +02:00
Alex Christoffer Rasmussen b2668e61a5 refactor: improve logging from http integration (#946) 2024-05-11 14:23:07 +02:00
Carlos Valente 7da3480dfe style: improve readability of shortcuts 2024-05-11 14:22:29 +02:00
Carlos Valente e8cfdbe3b9 refactor: simplify tests 2024-05-11 14:22:29 +02:00
Carlos Valente fd052355c3 style: uniform button size 2024-05-11 14:22:29 +02:00
Carlos Valente 00f04fb78c refactor: download project file 2024-05-10 22:35:12 +02:00
Carlos Valente 6f80de58ca fix: prevent mutation of initial object 2024-05-10 21:59:01 +02:00
Carlos Valente 5977266332 chore: update readme 2024-05-07 21:34:49 +02:00
Carlos Valente a40fa0dbf8 chore: version bump 2024-05-07 21:00:42 +02:00
arc-alex e92f59ac55 await and display errors 2024-05-07 15:49:07 +02:00
Carlos Valente 077c67e912 chore: sign macos dist 2024-05-07 12:42:47 +02:00
Alex Christoffer Rasmussen 9644cbde92 fix: demo page, update docs link and fix data destructuring (#932) 2024-05-02 12:17:08 +02:00
Charalambos Makridakis 8b0e03e980 #914 Refactor: Luxon-Depenency, formatFromMillis() (#924) 2024-04-29 23:20:12 +02:00
Carlos Valente 0966659596 chore: version bump 2024-04-29 22:44:24 +02:00
Carlos Valente 1123e29499 fix: explicit rundown order in tests 2024-04-29 22:41:02 +02:00
Carlos Valente 3d2248cceb style: remove unnecessary padding 2024-04-29 22:41:02 +02:00
Carlos Valente 043ba38916 chore: update typeface 2024-04-29 22:41:02 +02:00
Carlos Valente 5b6d4c5b28 style: toggle settings button 2024-04-29 22:41:02 +02:00
Carlos Valente 07e8bedff4 style: text formatting in menu 2024-04-29 22:41:02 +02:00
Carlos Valente 6e61a7ecf9 refactor: runtime side effects 2024-04-29 22:40:39 +02:00
Alex Christoffer Rasmussen accdf2c396 Fix: custom fields with undefined colour is not accepted by parseCustomFields (#925) 2024-04-29 22:33:58 +02:00
Alex Christoffer Rasmussen 5e39c9b51f Feat: export custom fileds to sheets (#926)
* export custom keys to sheets

* use `:` in place of `-`
2024-04-29 15:15:18 +02:00
Carlos Valente b52fb0f9ee chore: update automation scripts 2024-04-28 22:11:42 +02:00
Carlos Valente 54f30e69a1 chore: version bump 2024-04-27 22:39:04 +02:00
Carlos Valente 189cee0104 fix: state stale in integrations 2024-04-27 22:34:08 +02:00
Alex Christoffer Rasmussen 9e04a1dcfa shortcuts using useHotkeys from mantine/hooks (#907)
---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-04-27 18:00:41 +02:00
Carlos Valente 0c3c08ac98 refactor: custom fields casing 2024-04-27 15:36:29 +02:00
Carlos Valente 95b437e18c refactor(build): remove legal 2024-04-27 10:18:10 +02:00
Carlos Valente 75b5118b0f refactor: user alerts on destructive actions 2024-04-27 10:18:10 +02:00
Carlos Valente dcbb92c470 style: prevent overflow on defaults 2024-04-26 19:40:21 +02:00
Carlos Valente 8da8a08464 refactor: invert offset 2024-04-26 19:39:05 +02:00
Carlos Valente 8b5034efbf refactor: added time is time ahead 2024-04-26 19:39:05 +02:00
Alex Christoffer Rasmussen 74418ce17e Link start times from excel import (#903)
* add test for linking start time in excel import

* link ids

* add link to UI

* ensure times with cachedRundown

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-04-26 18:09:59 +02:00
Carlos Valente d8a8f0ad92 style: use user given capitalisation 2024-04-26 15:05:17 +02:00
Carlos Valente 817ebcdd26 Event defaults (#910)
* chore: cleanup outdated comment

* style: align blocks

* style: use ui-black background

* chore: clarify docs

* feat: event defaults

* chore: cleanup
2024-04-24 20:13:51 +02:00
Carlos Valente c4f51192de chore: test custom field renaming 2024-04-23 22:05:56 +02:00
Carlos Valente 5cf5b2fae3 chore: cleanup 2024-04-23 22:05:56 +02:00
Carlos Valente 8f249b9d51 refactor: rundown must be in order 2024-04-19 20:49:37 +02:00
Carlos Valente bef69e7d0f fix: obfuscation logic for operator pin 2024-04-19 20:38:01 +02:00
Carlos Valente dd81b92584 refactor: simplify l3 2024-04-19 20:38:01 +02:00
Alex Christoffer Rasmussen b14ac07568 excel import leading and trailing whitespace (#902)
* add test for leading and trailing whitespace

* trim whitespace
2024-04-19 20:36:06 +02:00
Carlos Valente c4136a0ec7 refactor: simplify custom field shape 2024-04-19 12:06:19 +02:00
Carlos Valente cf14b0b427 refactor: consolidate language of AuxTimer (#896) 2024-04-17 21:31:10 +02:00
Carlos Valente 16a169b22c Beta 2 review (#897)
* style: subdue secondary buttons

* refactor: remove public message
2024-04-17 21:25:03 +02:00
Carlos Valente 8af5feb9af Delete block (#895) 2024-04-17 21:24:27 +02:00
Carlos Valente 88b45fd952 fix: shutdown from menu (#893) 2024-04-16 21:21:01 +02:00
jwetzell a8e9962eed make application menu aware of what port should be used in link items (#890) 2024-04-16 21:20:41 +02:00
Carlos Valente 70c93a69fe Custom add (#889) 2024-04-14 21:52:12 +02:00
Carlos Valente 0ef1b44d9e chore: update README 2024-04-14 12:55:03 +02:00
cv 84839824fb fix: link to managing custom fields 2024-04-14 12:55:03 +02:00
Carlos Valente b63e3ed8f3 chore: update readme (#888)
* chore: update readme

* docs: funding
2024-04-13 11:30:51 +02:00
Carlos Valente 7eab0bb300 chore: version bump (#885) 2024-04-13 10:16:00 +02:00
Carlos Valente 55d1aca9b6 V3 (#657)
* refactor: cleanup routes

* style: smaller base font

* chore: upgrade dependencies

* chore: lock node version to electron

* refactor: pass HTTP to integration controller (#652)

* refactor: deprecate onair control

* refactor: remove playback router

* Several project files user folder (#617)

* chore: automated screenshots (#667)

* feat: app settings (#658)

* refactor: remove deprecated event data (#674)

* Studio clock (#663)

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* Feat: reorder events with alt+ctrl + arrow up/down (#645)

* Warning and danger per event (#677)

---------

Co-authored-by: Fabian Posenau <fabian@fphome.de>

* refactor: stabilise actionHandler (#683)

Co-authored-by: Fabian Posenau <fabian@fphome.de>

* improvement: hide seconds (#675)

* wip: overview (#688)

* fix: focus cursor (#695)

* refactor: update lower third (#665)

* Refactor/time formatting (#696)

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* feat: multiple selection (#703)

---------

Co-authored-by: asharonbaltazar <asharonbaltazar@outlook.com>
Co-authored-by: Alex <ac@omnivox.dk>

* fix: test - go to `Edit mode` befor tying to click `Event options` button (#708)

* refactor: runtime service (#715)

* fix: issue with loosing cursor position on message (#719)

* remove info panel (#721)

* Event editor continue (#722)

* update API - part  (#709)

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* refactor: update timers (#729)

* feat: many timers (#706)

---------

Co-authored-by: arc-alex <ac@omnivox.dk>

* refactor: excel cleanup (#734)

* refactor: allow import of blocks and skip import (#735)

* Project manager (#697)

* refactor: UI for linking events (#763)

* upgraded pipeline actions (#777)

* Over under (#771)

* custom fields (#744)


---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* Sheets settings (#774)

---------

Co-authored-by: arc-alex <ac@omnivox.dk>

* style: tweaks to lower thirds (#785)

* refactor: delays account for gaps (#784)

* refactor: partial state updates (#780)

* feat: generate crash report (#787)

* Sheet use limited input device auth flow (#782)

---------

Co-authored-by: cv <34649812+cpvalente@users.noreply.github.com>
Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* Custom fields views (#789)

* refactor: deprecate presenter and subtitle (#795)

* refactor: organise API around resources (#798)

---------

Co-authored-by: Bianca Procopio <biancahprocopio@gmail.com>

* Time to end (#804)

* Skip fixes (#805)

* fix: onair derives from playback

* Param nav (#822)

---------

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>

* refactor: download files from interface (#831)

* Quick options (#814)

* End pause (#832)

* chore: bump node version in docker (#834)

* refactor: follow in run mode (#840)

* fix: uncaught error in http integration (#837)

* Apply project (#843)

Co-authored-by: Matteo Gheza <matteo.gheza07@gmail.com>
Co-authored-by: Ary <arylmoraesn@gmail.com>
Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
Co-authored-by: Fabian Posenau <19673098+kellhogs@users.noreply.github.com>
Co-authored-by: Fabian Posenau <fabian@fphome.de>
Co-authored-by: Alex Rohleder <alexrohleder96@gmail.com>
Co-authored-by: asharonbaltazar <asharonbaltazar@outlook.com>
Co-authored-by: Bianca Procopio <biancahprocopio@gmail.com>
Co-authored-by: Fabian Posenau <fabianpos99+github@gmail.com>
2024-04-13 10:06:46 +02:00
Fabian Posenau debdbd1c5a Fix danger time not shown (#775)
* wrong order of operations

* chore: version bump
2024-02-14 12:44:06 +01:00
Carlos Valente d1ae407996 chore: version bump (#764) 2024-02-06 11:46:08 +01:00
Carlos Valente 467b595375 fix: issue where a end time can be overflowing (#761) 2024-02-06 11:42:28 +01:00
Carlos Valente 965a7092d9 fix: timer type clock is not negative in public displays (#747) 2024-01-30 12:35:36 +01:00
Alex Christoffer Rasmussen 661337fef9 fix: change all ExcelImportMaps to lowercase (#716)
* fix: change all ExcelImportMaps to lowercase

* chore: bump patch version
2024-01-15 21:37:04 +01:00
Carlos Valente 71092afc02 ontime release (#694)
* chore: version bump

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2024-01-10 20:50:19 +01:00
Alex Christoffer Rasmussen b1ba47a80f Fix/external path (#702)
* leave styles as is but move other external to `external` folder
2024-01-09 22:57:06 +01:00
Alex Christoffer Rasmussen 9611722a6d fix: use background-color: transparent; for overlap indicators (#699) 2024-01-09 16:42:50 +01:00
Alex Christoffer Rasmussen 92cefa1331 refactor: errors from integrationcontroller (#700)
* refactor: these functions don't throw, test the return success and then throw

* refactor: no need to catch and re-throw
2024-01-09 16:01:17 +01:00
Alex Christoffer Rasmussen c0fb865959 feat: google sheets(#579)
---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2024-01-08 15:51:58 +01:00
Oliver Herrmann 068ec800f4 add localdocker build commands (#638) 2024-01-05 21:04:52 +01:00
Alex Christoffer Rasmussen 1a8b35a5ea feat: show overlap (#633)
* feat: show spacing or overlap
2024-01-05 21:04:16 +01:00
Fabian Posenau 40bede200c nightly builds hopefully (#681)
Co-authored-by: Fabian Posenau <fabian@fphome.de>
2023-12-30 10:04:42 +01:00
Fabian Posenau f3e2944c55 fix docker compose ontime version (#680)
Co-authored-by: Fabian Posenau <fabian@fphome.de>
2023-12-29 22:25:41 +01:00
Fabian Posenau 09f2874784 Fix Visual bug on rundown (#678)
* fix: bug with draw order on past rundown items

---------

Co-authored-by: Fabian Posenau <fabian@fphome.de>
2023-12-29 20:18:05 +01:00
Carlos Valente 8afffb9870 style: fix missing overrides (#666)
* style: fix missing overrides

* style: fix recover idle colour
2023-12-22 21:05:23 +01:00
Carlos Valente 33575c551a refactor: improve typing on transform (#626)
* refactor: improve typing on transform

* chore: use placeholder for data errors
2023-12-19 10:03:25 +01:00
Carlos Valente 3173fb57fc chore: add italian to languages (#656) 2023-12-18 15:07:48 +01:00
Carlos Valente 7d33019f53 refactor: prevent accidental edit in operator view (#659)
* refactor: prevent accidental edit in operator view
2023-12-18 15:07:30 +01:00
Matteo Gheza 6526b32d4c Add italian client translation (#655)
* Add Italian client translation
2023-12-17 20:59:05 +01:00
Carlos Valente d6aef5ea31 fix: correct link for CSS overrides (#650) 2023-12-14 20:14:09 +01:00
Alex Christoffer Rasmussen 8756b396cc feat: minimal demo page (#644)
* minimal

* eslint-browser

* dynamic port, reconnect socket, msTo string without Date

* 404 on external not found
2023-12-14 13:27:18 +01:00
Carlos Valente 5a2f711eab refactor: cleanup sentry errors (#653) 2023-12-13 22:12:54 +01:00
Carlos Valente a56e2b1c1c fix: link for mac download (#648) 2023-12-13 19:22:17 +01:00
Carlos Valente da829dc09f Release preparations (#642)
* chore: version bump
2023-12-11 22:06:19 +01:00
Carlos Valente c4d65dbe5f fix: display correct end time in backstage (#635) 2023-12-10 19:12:29 +01:00
Alex Christoffer Rasmussen 2586b0b10c feat: http integration (#575)
* addtime endpoint

* create universal Subscription

* add http integration

* catch error from HTTP integration emit

* unify osc and http validateSubscriptionEntry

* add necessary endpoint for http subscription

* make subscription part of modal generic

* add http subscription to integration modal

* remove log

* Revert "addtime endpoint"

This reverts commit 4c039220dc.

* reuse agent and test url compatibility

* simplify retun path

* add todo in UI

* test for http protocol

* import not needed yet

* lint

* fix merge

* lint

* fix httpPlaceholder

* wip: prepare endpoints

* wip: temporary fix to get form to work

* disable HTTP integration if enabledOut==false

* register/unregister http

* refactor: subscription types and form register

* refactor: validation

* cleanup

* cleanup

* try GOT

* allow https

* split url and searchParams allow for post option

* add options to post

* add retry count

* fix test

* Revert "fix test"

This reverts commit 927e88370f.

* Revert "add options to post"

This reverts commit 0523a68ef4.

* Revert "split url and searchParams allow for post option"

This reverts commit 54ab8d4ffe.

* missing retryCount in httpPlaceholder

* remove global this

* remove retry count

* remove https

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2023-12-10 16:56:42 +01:00
Alex Christoffer Rasmussen abe27d54a2 refactor: use add time in client (#636) 2023-12-08 21:46:29 +01:00
Alex Christoffer Rasmussen 1343818917 Improve change api (#628)
* fix: jsdoc comments

* more human casting of string values to boolean

* add coerceColour to get named colors to work

* cue can't pass isKeyOfType event check

* dont mutate value

* alloow cue in eventDef

* lint

* css named or hex formatting

* "sideEffects": false

* test colour hex regex

* roll eventDef back to master

* parse property

* don't export cssColour names

* remove import

* only allow string types to colour

* handle transparent colour

* mix alpha with bg colour

* only allow updating events

* descriptive names

* add test for getAccessibleColour

* readability

* move isColourHex to regex-utils

* simplify and add test
2023-12-08 12:55:04 +01:00
Carlos Valente a93cd3e9b1 style: prevent menu mirroring (#632) 2023-12-07 17:57:04 +01:00
Alex Christoffer Rasmussen 813eb9ad86 Merge pull request #604 from cpvalente/roll-back
add skippedOutOfEvent to TimerService
2023-12-04 12:53:43 +01:00
Carlos Valente 34e9b1ef07 refactor: clarify responsabilities 2023-11-30 21:35:09 +01:00
arc-alex a67b89190d guard and test midnight 2023-11-28 16:04:12 +01:00
arc-alex ecd151a0a8 use expectedFinish 2023-11-28 15:27:19 +01:00
asharonbaltazar 4cbc09864c Params Input Placeholders (#627)
* add `placeholder?: string;` to `StringField` & `NumberField`

* add `placeholder` to inputs

* move values from `defaultValue` to `placeholder`
2023-11-27 18:25:46 -05:00
arc-alex 20d5d8b129 move skip logic to timerUtils 2023-11-27 17:42:42 +01:00
Alex Christoffer Rasmussen 11db39ee73 Merge pull request #623 from cpvalente/osc-enabledOut
Osc disable/enable output
2023-11-27 16:56:54 +01:00
asharonbaltazar edb79d5819 Default Values in ParamEditor (#610)
* add `defaultvalue` to `Field` types

* add `defaultValue` to constants; turn into functions for time values

* update constant imports/calls in view components

* use `defaultValue`s in `ParamInput`

* change `Clear` to `Reset`to better reflect actions

* make `defaultValue` optional rather than `undefined`

* update forgotten constants

* add `defaultValue` to boolean input

* change `101010` to `000000`

* add `prefix` property to types

* implement `prefix` for `ParamInput`s

* change `paramField` to `prop`

* add `onEditDrawerClose` to `resetParams`

* `ViewParamsEditor` omits default values

* undo close on reset

* move `useSettings` into `ViewWrapper`

* change `settings` to include `undefined`
2023-11-26 15:57:18 -05:00
arc-alex 715fa66444 disable/enable from ui without restart 2023-11-26 20:41:33 +01:00
arc-alex 27f6d10677 actually disable/enable osc output 2023-11-26 20:41:01 +01:00
Carlos Valente f2504072ce feat: add change endpoint to ws (#618)
* feat: add change endpoint to ws
2023-11-26 19:02:16 +01:00
Carlos Valente 9e285ee8f3 chore: version bump (#616) 2023-11-25 22:31:22 +01:00
Carlos Valente 1ccf2108eb style: tweaks on info data (#622) 2023-11-25 22:31:09 +01:00
Carlos Valente db56ac8049 style: separe arguments in copy fields (#621) 2023-11-25 22:28:54 +01:00
Carlos Valente 0660f014c8 fix: prevent autocomplete (#620) 2023-11-25 22:04:47 +01:00
Carlos Valente 41c26778cb fix: prevent shortcut collision with menu (#619) 2023-11-25 21:55:27 +01:00
Carlos Valente 804e4ad33e chore: disable save params feature (#615) 2023-11-24 18:29:37 +01:00
arc-alex b11041938d self documenting 2023-11-24 14:05:12 +01:00
Carlos Valente 5be60ff6c3 feat: show progress in op and cuesheet (#605) 2023-11-24 12:04:38 +01:00
Carlos Valente bf8ebe942e feat: allow editing field from operator (#609)
* feat: allow editing field from operator

Co-authored-by: arc-alex <ac@omnivox.dk>

* style: functional and presentation tweaks
---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2023-11-24 12:04:22 +01:00
Carlos Valente bdd216d881 feat: customise timer elements (#607)
* feat: customise timer elements
2023-11-22 21:38:35 +01:00
arc-alex e6b4f537af rollSkipLimit 2023-11-22 19:05:08 +01:00
Alex Christoffer Rasmussen 797a0edf57 External field (#580)
* feat: add external endpoint

* add external to messagecontrol

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>
2023-11-22 08:06:48 +01:00
asharonbaltazar c4886a617c remove storedViewParams from the dep array (#606) 2023-11-20 18:41:41 -05:00
Carlos Valente a79ae7e0c4 fix: cuesheet header (#600)
* `useLocalStorage` hook uses `useSyncExternalStore`
---------

Co-authored-by: asharonbaltazar <asharonbaltazar@outlook.com>
2023-11-20 21:11:52 +01:00
arc-alex 8cabb347e9 remove test log 2023-11-20 18:24:11 +01:00
arc-alex 22d89c6fbc add _startAt to all tests 2023-11-20 17:51:50 +01:00
arc-alex facce4f096 trigger doRoll if clock is less than startAt 2023-11-20 17:44:39 +01:00
Carlos Valente afa62a6e38 test: alias feature (#602) 2023-11-20 11:45:17 +01:00
Carlos Valente 1b55dbc170 style: clock period (#601)
* style: tweaks to studio override

* style: improvements to 12 hour format
2023-11-20 09:53:35 +01:00
Carlos Valente 2316bbebac chore: type improvements (#598)
* chore: type improvements

* ci: typechecking in pipeline
2023-11-18 08:35:54 +01:00
Carlos Valente 884ab0b67b refactor: rundown (#597)
* refactor: add revision number to rundown

* chore: migrate query
2023-11-17 16:18:02 +01:00
Carlos Valente 58239af8bb fix: distinguish user initiated scroll (#596) 2023-11-17 13:01:28 +01:00
Alex Christoffer Rasmussen c59e070076 Local build (#595)
* add build:electron script

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2023-11-17 13:01:08 +01:00
Carlos Valente fad8d2a933 hotfix ci (#594)
* ci: upgrade pnpm

* version bump
2023-11-16 11:26:01 +01:00
Carlos Valente 54def8b820 feat: small improvements to instance info (#591)
* refactor: add typings to backend info

* refactor: write current version to project file

* feat: show location of css override
2023-11-15 20:20:05 +01:00
Carlos Valente 536e447eaa style: export modal (#592)
* style: tweaks to export modal
2023-11-14 22:31:14 +01:00
Carlos Valente 1ca3b9c134 refactor: better errors (#590)
* refactor: improve error messages from server
2023-11-14 21:54:56 +01:00
Carlos Valente a41fe8806b configure lint staged (#588)
* chore: upgrade monorepo deps

* chore: configure lint-staged

* refactor: lenient use of any
2023-11-13 22:04:55 +01:00
Alex Christoffer Rasmussen 140daef7e7 add eventsPerPage to schedule (#583)
* add eventsPerPage to schedule

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2023-11-13 22:03:17 +01:00
Carlos Valente cbed3e4fe4 ci: remove stale bot (#587) 2023-11-12 21:41:55 +01:00
Carlos Valente 9da7613450 ci: close issues without user activity (#586)
* ci: close issues without user activity
2023-11-11 14:58:46 +01:00
Carlos Valente a7980ef2ab fix: github workflow (#585)
* fix: github workflow

* chore: update lockfile
2023-11-11 14:42:06 +01:00
Carlos Valente 45fe669f0a feat: excel import (#527)
* refactor: simplify excel import

* chore: add external deepmerge utility

* chore: create import map utilities

* chore: increase size limits on uploads

* style: small presentation tweaks

* feat: resolve times on excel import, refs #508
2023-11-11 14:28:43 +01:00
asharonbaltazar 0ce3449083 View Params Persist when Navigating Back (#581)
* add url search params to local storage

* add clearing local storage

* use `useLocation` instead of `location.pathname`
2023-11-10 08:49:25 -05:00
Carlos Valente de715b3d3e chore: upgrade pnpm (#582)
* chore: upgrade pnpm
2023-11-09 21:34:17 +01:00
Carlos Valente 6012cb7bd1 chore(lint): lenient eol (#578)
* chore(lint): lenient eol
2023-11-07 22:39:47 +01:00
Carlos Valente 2c47d90f34 chore: configure project wide linter (#577)
* chore(lint): configure project-wide linter

* chore(lint): improve linting in files

* chore(lint): hide warnings in CI
2023-11-07 22:30:39 +01:00
Carlos Valente 943dd19c09 style: wording and UI tweaks (#564)
* style: wording and UI tweaks

* style: prevent note overflow

* style: small wording changes

* soft blink (#569)

* chore: version bump


---------

Co-authored-by: Alex Christoffer Rasmussen <alex.christoffer@gmail.com>
2023-11-07 21:27:33 +01:00
Alex Christoffer Rasmussen 138be478ca Addtime in sec (#576)
* addtime endpoint

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2023-11-07 21:24:44 +01:00
Carlos Valente 98bd320cbd style: coloured row background (#571)
* style: coloured row background
2023-11-05 09:47:55 +01:00
Alex Christoffer Rasmussen f57faf1837 remove unnecessary import 2023-11-04 08:46:35 +01:00
arc-alex 44f025b359 update node-osc to v9 2023-11-04 08:46:35 +01:00
Carlos Valente 0555d0f400 feat: expand user options for views with schedule (#565)
* feat: expand user options for views with schedule

* fix: selected public id on load

* fix: load events on roll

* style: remove empty container
2023-11-03 13:47:38 +01:00
Carlos Valente 1e90ce4c1d style: sticky index column (#566)
* style: sticky index column
2023-11-02 20:59:30 +01:00
Carlos Valente 2f09d27813 fix: nullcheck for nextPublicEventId in findRoll (#567)
Co-authored-by: Alex Christoffer Rasmussen <alex.christoffer@gmail.com>
2023-11-02 10:31:05 +01:00
Alex Christoffer Rasmussen a01046b479 Feat/change event api (#553)
* feat: change attribute for given event 

---------

Co-authored-by: Ary <arylmoraesn@gmail.com>
Co-authored-by: arc-alex <ac@omnivox.dk>
2023-10-31 19:24:22 +01:00
Enubia 78d5d442cf feat: added export options (#529)
* feat: added export options

* chore: eslint console proposal

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
2023-10-30 11:41:15 +01:00
Brian Teeman 7c234466f7 typos (#562)
quick fix for some typos/spelling

Small way of saying thanks for the software
2023-10-30 11:36:54 +01:00
Carlos Valente 29e5c96d44 fix: prevent error when port is unchanged (#551)
* fix: prevent error when port is unchanged
2023-10-28 19:01:58 +02:00
Kye Lewis 36b1effaaf Clarify build before E2E steps (#556)
Co-authored-by: Kye <kye@klewis.me>
2023-10-26 14:57:11 +02:00
Alex Christoffer Rasmussen a84c0654e2 Feat resumability (#547)
* add resumability functionality

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
2023-10-24 08:33:17 +02:00
Carlos Valente b34fe71995 chore: add line end to prettier (#548) 2023-10-14 19:12:14 +02:00
Carlos Valente 2f74293505 chore: update docs (#537)
- Avoid duplicate instructions on docker and refer to documentation
- Add link to macOS docs on running an unsigned app
2023-10-08 11:47:45 +02:00
Carlos Valente e2aabe3646 chore: version bump (#528) 2023-09-17 15:04:55 +02:00
Carlos Valente 7545f6f7d0 refactor: clarify description import (#526) 2023-09-16 15:24:23 +02:00
Carlos Valente 958c68b6f6 style hover (#525)
* refactor: render if in view

* style: add hover indicator on row
2023-09-16 13:49:12 +02:00
Carlos Valente a0c5375376 refactor: project data (#523) 2023-09-15 17:33:30 +02:00
Carlos Valente 9708f0bfc6 refactor: pass events instead of derived data to titles (#493)
* refactor: pass events instead of derived data to titles
2023-09-14 22:30:23 +02:00
Carlos Valente 13eca98133 refactor: recompose and memoise (#522) 2023-09-14 21:06:48 +02:00
Carlos Valente 126e31403e style tweaks (#524)
* style: allow 2 rows in block title

* fix: accidental change to next and progress bar
2023-09-13 21:51:24 +02:00
Carlos Valente 53beea2768 refactor: prevent calling undefined (#521) 2023-09-13 21:24:49 +02:00
Carlos Valente 0bb09dd039 fix: sanitise cue import (#519)
* fix: sanitise cue import
2023-09-11 21:06:32 +02:00
Carlos Valente 93fb48ea1c feat: operator view (#440)
* feat: operator view

* chore: smoke test operator

* refactor: small improvements from deepsource

---------

Co-authored-by: arihanv <arihanvaranasi@gmail.com>
Co-authored-by: arihanv <63890951+arihanv@users.noreply.github.com>
2023-09-11 21:03:11 +02:00
Carlos Valente 1de3e01216 style: localise labels to user device (#509) 2023-09-03 09:13:56 +02:00
Carlos Valente 8d427a6bbe fix: allow spaces in title input (#504) 2023-09-01 23:26:59 +02:00
Carlos Valente 23dcca5527 fix: issue with resolving dev environment (#501)
* fix: issue with resolving dev environment

* fix: revert accidental commtit

* chore: version bump
2023-08-31 22:08:18 +02:00
Carlos Valente a3bbd74db7 chore: reduce sentry error logging (#498)
* chore: reduce sentry error logging

* chore: version bump

* chore: improve test selectors
2023-08-27 22:00:18 +02:00
Carlos Valente 5323e627fb feat: count to end (#500) 2023-08-27 19:25:40 +02:00
Carlos Valente cd9dbcdc68 fix: add event (#499)
* refactor: remove guards on event creation

* style: minimum safe block size

* fix: insert after finds previous valid cue
2023-08-26 21:45:51 +02:00
Carlos Valente af99882919 release test fixes (#496)
* refactor: handle missing type

* fix: prevent stale data on cancel delay
2023-08-24 22:53:23 +02:00
Carlos Valente 1d4dc3a26f feat: unlock changing port in UI (#476)
* refactor: unlock changing port in UI

* Change server port (#464)

* Ability to save custom port

* Launch server on custom port & pass that port to electron

* Add serverPort validation

* Prevent changing port in docker

---------

Co-authored-by: Snehanshu Phukon <snehanshu@mamboemm.com>

---------

Co-authored-by: স্নেহাংশু ফুকন <hello@snehanshu.com>
Co-authored-by: Snehanshu Phukon <snehanshu@mamboemm.com>
2023-08-23 22:31:57 +02:00
Carlos Valente e5fdf27f6c fix: apply delay (#494)
* fix: bug with applying delays

* fix: show delay data only in production screens

* chore: cover delay with feature test

* refactor: simplify type assertion
2023-08-23 22:31:15 +02:00
Carlos Valente 657cc22b44 feat: event cue (#473)
* feat: parse cue

* refactor: get delay from backend

* feat: add cue to UI

* refactor: remove deprecated delay logic

* refactor: extract studio clock specific logic

* refactor: extract utilities

* refactor: fix issue with missing key

* style: prevent cue overflow

* style: prevent whitespace wrap

* feat: add support for cues in integrations
2023-08-17 21:43:11 +02:00
asharonbaltazar 51c31adaf1 Swap Event Data (#446)
* use zustand store in `ContextMenuContext`

* add `withDivider` prop to context menu `Option`

* add `isDisabled` prop to `Option`

* create `eventIdSwapping` store

* create swapping context menu options

* fix `key` in ContextMenu

* address `tanstack-eslint` errors

* create initial `requestEventSwap` event

* create initial `swapEvents` action

* use `swapEvents` in `EventBlock`

* move from `emitError` to `logAxiosError`

* remove extra curly brace from Copy ID

* add `clearEventId` func

* finalize context menu swapping logic

* write optimistic swapping logic

* remove unused import and type out handler in `rundownController`

* create `rundownSwapValidator`

* move index increase to `EventBlock`

* move swapping logic from `id` to `index`

* create `swapEvents` endpoint

* move `useEventIdSwapping` hook into its own file

* revert to using event `id`

* logic now uses indexes to swap events

* add `todo` to `swapEvents`

* revert index increment

* create `swapOntimeEvents` and export in `index.ts`

* use `swapOntimeEvents` in frontend & server

* update import path

* remove extra `setCached`
2023-08-15 16:04:53 -04:00
Carlos Valente a46a0e1631 fix: typo in macos release (#488) 2023-08-12 11:52:05 +02:00
Carlos Valente 4f298e6fd9 version bump (#487) 2023-08-12 11:38:36 +02:00
Carlos Valente f3610059ef fix paused (#486)
* fix: prevent timer continue on paused count up

* refactor: throw if not found on delete
2023-08-12 11:24:35 +02:00
Carlos Valente 023aac4ead fix: midnight roll (#484)
* refactor: extract utilities and types

* refactor: extract and simplify progress bar logic

* refactor: duration validation handles midnight

* fix: prevent stale event loader

* refactor: consider next event in timer invalidation

* refactor: reload changes on changed roll target

* refactor: timer load accounts for midnight

* fix: issues with midnight on roll

* refactor: prevent stale secondary event
2023-08-12 10:42:43 +02:00
Carlos Valente 8c9cb908cf chore: improve demo file (#482) 2023-08-12 10:00:30 +02:00
Carlos Valente 839cee18f3 feat: add french translations (#483) 2023-08-12 10:00:14 +02:00
Olayinka Zadat O b83ebf53a9 Adding Alias as a Parameter (#471)
* redirect on alias to a new page

* move alias to a HOC wrapper
2023-08-11 14:53:36 +02:00
Carlos Valente 1b8392bba4 dx: improve local build command (#480) 2023-08-11 10:55:24 +02:00
Carlos Valente af1241bec7 feat: event description (#481)
* feat: enable configuration of <Info> panel

* feat: add description field to event data
2023-08-11 10:55:02 +02:00
Carlos Valente c361ff4b3f refactor: handle undefined (#479) 2023-08-11 10:54:24 +02:00
Cody Wilson b579a4c57e dist-mac: create separate dists for aarch64, x64 (#470)
* dist-mac: create separate dists for aarch64, x64
2023-08-11 10:51:00 +02:00
Carlos Valente e49918e8bb style: show event title in info panel (#467) 2023-07-23 15:41:58 +02:00
Carlos Valente 60799d3d88 Refactor error messages (#463)
* refactor: improve error messages to user

* refactor: remove unused
2023-07-23 15:12:25 +02:00
Carlos Valente 31fc222876 many hotfixes (#465)
* style: disable menu bar in run mode

* fix: external devices in dev mode

* fix: add missing elements to translations

* ux: improve translation strings

* refactor: improve typing

* style: blink on event change

* refactor: param options is object

---------

Co-authored-by: Hannes Rüger <hannesrueger@gmx.de>
2023-07-23 15:10:53 +02:00
Carlos Valente bb1eb2838f fix csv export (#466)
* style: cleanup formatting

* fix: prevent issues with csv export

* chore: update test snapshots
2023-07-23 15:06:25 +02:00
Carlos Valente 3603b836f6 refactor: cuesheet v2 (#435)
* refactor: typescript migration

* chore: remove prop-types package

* refactor: file structure

* refactor: migrate ontime table to tanstack table 8

* refactor: rundown controller uses service as data source

* refactor: convert to typescript

* feat: caching store

* refactor: add delay values to rundown

* feat: toggle past visibility

* chore: update tests

* refactor: add extra fields to CSV

* style: show skipped events

* chore: add route to navigation menu

* style: allow jumping to bottom

* chore: add tests
2023-07-22 09:32:40 +02:00
Carlos Valente bee7a8dcb4 fix: prevent typerror on fullscreen request (#461) 2023-07-21 23:12:15 +02:00
Carlos Valente e3444747bb fix: prevent clipboard error in secure context (#462) 2023-07-21 23:12:03 +02:00
Carlos Valente db1155ce1a feat: allow renaming connection (#457)
* feat: allow renaming connection
2023-07-21 20:15:54 +02:00
Carlos Valente 6ef6b0fdcd fix: app image cannot find resources (#458)
* fix: typo prevents linux from finding resources
2023-07-20 21:35:09 +02:00
Carlos Valente c73f7e2207 fix: issues with clock overflow on midnight (#456)
* fix: issues with clock overflow on midnight

* chore: version bump
2023-07-17 13:53:50 +02:00
Carlos Valente 4a0d83d970 fix: fullscreen permissions (#453)
attempt fixing issues with going fullscreen by configuring the Content Security Policy
2023-07-17 13:51:03 +02:00
Carlos Valente b89d0787d4 refactor: roll handover (#451)
* style: tweak active colour

* refactor: create shared playback validation

* feat: allow handover from and to roll
2023-07-15 11:06:10 +02:00
Carlos Valente 91a2d395cb style: small tweaks on code style and editor UI (#450)
* fix: notes > note

* style: improve roll visibility
2023-07-11 21:54:10 +02:00
Carlos Valente 6c9222bce3 chore: improve bug reporting data (#443) 2023-07-10 22:15:13 +02:00
Carlos Valente b273ac5254 refactor: update import fields (#433)
* refactor: update import fields

+ remove end message
+ add timer type
+ add end action

* chore: update tests

* version bump
2023-06-11 12:37:16 +02:00
Carlos Valente 971a76673b refactor: increase update rate (#430)
* refactor: remove unused components

* refactor: increase timer refresh rate
2023-06-08 22:16:15 +02:00
1014 changed files with 62297 additions and 29794 deletions
+9
View File
@@ -11,4 +11,13 @@
# Ignore git and cache folders
.git
.gitignore
.cache
# Ignore build folders
node_modules
dist
# Ignore default volumes created by running docker compose up
ontime-db
ontime-styles
+1
View File
@@ -0,0 +1 @@
"ONTIME_VERSION.js"
+39 -12
View File
@@ -1,4 +1,5 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": 2020
},
@@ -6,21 +7,47 @@
"es6": true,
"jest": true
},
"extends": [
"eslint:recommended"
],
"parser": "@typescript-eslint/parser",
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier", "eslint-config-prettier"],
"plugins": ["@typescript-eslint", "prettier"],
"overrides": [
{
"files": [
"e2e/**/**.spec.ts",
"e2e/**/**.test.ts"
],
"extends": [
"plugin:playwright/playwright-test"
]
"files": ["e2e/**/**.spec.ts", "e2e/**/**.test.ts"],
"extends": ["plugin:playwright/playwright-test"]
}
],
"rules": {
"no-console": "warn"
"no-useless-concat": "warn",
"prefer-template": "warn",
"no-throw-literal": "error",
"no-console": [
"warn",
{
"allow": ["warn", "error"]
}
],
"no-restricted-imports": [
"error",
{
"patterns": ["ontime-types/src/*", "ontime-utils/src/*"]
}
],
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"prettier/prettier": [
"warn",
{
"endOfLine": "auto"
}
]
}
}
}
+2
View File
@@ -0,0 +1,2 @@
github: cpvalente
buy_me_a_coffee: cpvalente
Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

@@ -1,4 +1,4 @@
name: Ontime build v2
name: Ontime build
on:
push:
@@ -10,16 +10,16 @@ jobs:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
uses: pnpm/action-setup@v3
with:
version: 7.26.3
version: 9
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -30,12 +30,21 @@ jobs:
run: pnpm build
- name: Electron - Build app
run: pnpm dist-mac
env:
APPLE_ID: ${{ secrets.APPLEID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLEIDPASS }}
APPLE_TEAM_ID: ${{ secrets.TEAMID }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.CSC_LINK }}
run: pnpm dist-mac --env-mode=loose
timeout-minutes: 60
- name: Release
uses: softprops/action-gh-release@v1
with:
files: './apps/electron/dist/ontime-macOS.dmg'
files: |
./apps/electron/dist/ontime-macOS-x64.dmg
./apps/electron/dist/ontime-macOS-arm64.dmg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -43,16 +52,16 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
uses: pnpm/action-setup@v3
with:
version: 7.26.3
version: 9
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -76,16 +85,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
uses: pnpm/action-setup@v3
with:
version: 7.26.3
version: 9
- name: Install dependencies
run: pnpm install --frozen-lockfile
+53
View File
@@ -0,0 +1,53 @@
name: Ontime CLI build
on:
release:
types: [published]
workflow_dispatch:
jobs:
build_cli:
permissions:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 9
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build project packages
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: pnpm build
- name: Copy server
run: mkdir -p apps/cli/server && cp apps/server/dist/index.cjs apps/cli/server/index.cjs
- name: Copy client
run: cp -R apps/client/build apps/cli/client
- name: Copy external
run: cp -R apps/server/src/external apps/cli/external
- name: Publish to NPM
run: pnpm publish --access public --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
working-directory: ./apps/cli
+48
View File
@@ -0,0 +1,48 @@
name: Docker Image CI Ontime
on:
release:
types: [published]
workflow_dispatch:
jobs:
publish_docker:
runs-on: ubuntu-latest
env:
CI: ''
steps:
- uses: actions/checkout@v4
- 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 stable release
if: github.event.release.prerelease == false
uses: docker/build-push-action@v4.0.0
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7
# Push is a shorthand for --output=type=registry
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/ontime:${{ github.event.release.tag_name }} , ${{ secrets.DOCKERHUB_USERNAME }}/ontime:latest
- name: Build and push pre-release
if: github.event.release.prerelease == true
uses: docker/build-push-action@v4.0.0
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7
# Push is a shorthand for --output=type=registry
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/ontime:${{ github.event.release.tag_name }} , ${{ secrets.DOCKERHUB_USERNAME }}/ontime:nightly
-56
View File
@@ -1,56 +0,0 @@
name: Docker Image CI Ontime V2
on:
push:
tags: [ "*" ]
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:${{ env.RELEASE_VERSION }} , ${{ secrets.DOCKERHUB_USERNAME }}/ontime:latest
@@ -1,4 +1,4 @@
name: Ontime test v2
name: Ontime test
on:
pull_request:
@@ -13,30 +13,54 @@ jobs:
CI: ''
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
uses: pnpm/action-setup@v3
with:
version: 7.26.3
version: 9
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Run code quality per package
- name: React - Run linter + TypeScript checks
if: always()
run: pnpm lint && tsc --noEmit
working-directory: ./apps/client
- name: Server - Run linter + TypeScript checks
if: always()
run: pnpm lint && tsc --noEmit
working-directory: ./apps/server
- name: Utils - Run linter + TypeScript checks
if: always()
run: pnpm lint && tsc --noEmit
working-directory: ./packages/utils
- name: Types - Run linter
if: always()
run: pnpm lint
working-directory: ./packages/types
# We choose to run tests separately
- name: React - Run unit tests
if: always()
run: pnpm test:pipeline
working-directory: ./apps/client
- name: Server - Run unit tests
if: always()
run: pnpm test:pipeline
working-directory: ./apps/server
- name: Utils - Run unit tests
if: always()
run: pnpm test:pipeline
working-directory: ./packages/utils
@@ -45,16 +69,16 @@ jobs:
timeout-minutes: 20
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
uses: pnpm/action-setup@v3
with:
version: 7.26.3
version: 9
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -68,9 +92,15 @@ jobs:
- name: Run Playwright tests
run: pnpm e2e
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
- uses: actions/upload-artifact@v4
with:
name: automated-screenshots
path: automated-screenshots/
retention-days: 14
+6 -3
View File
@@ -27,6 +27,8 @@ ontime.code-workspace
test-results
playwright-report
/playwright/.cache/
automated-screenshots
e2e/tests/fixtures/tmp/*
# production
build/
@@ -38,9 +40,10 @@ dist/
# docker utils
ontime-db
ontime-external/
# working database
apps/server/src/preloaded-db/db.json
ontime-data/
# versioning file
**/ONTIME_VERSION.js
# temporary write files
**.tmp
BIN
View File
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
build
coverage
dist
node_modules
playwright-report
**/*.toml
**/*.yml
**/*.json
+1
View File
@@ -1,4 +1,5 @@
{
"endOfLine": "lf",
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
+49 -11
View File
@@ -1,32 +1,48 @@
# GETTING STARTED
Ontime consists of 3 distinct parts
- __client__: A React app for Ontime's UI and web clients
- __client__: A React app for Ontime's UI and web clients
- __electron__: An electron app which facilitates the cross-platform distribution of Ontime
- __server__: A node application which handles the domains services and integrations
The steps below will assume you have locally installed the necessary dependencies.
The steps below will assume you have locally installed the necessary dependencies.
Other dependencies will be installed as part of the setup
- __node__ (>=16.16)
- __pnpm__ (>=7)
- __node__ (~20)
- __pnpm__ (~9)
- __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.
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`
### Debugging backend
To debug backend code in Node.js:
- Open two separate terminals and navigate to the `apps/client` and `apps/server` directories.
- In each terminal, run the command `pnpm dev` to start the development servers for both the client and server
applications.
- If you need to set breakpoints and inspect the code execution, enable Node.js inspect mode by
running `pnpm dev:inspect`.
## TESTING
Generally we have 2 types of tests.
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.
@@ -35,12 +51,22 @@ 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
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)
Before running the E2E, you should first build the project with `pnpm build:local`.
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`
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`
Some other useful commands
- `pnpm e2e --ui` open playwright UI
- `pnpm e2e --headed` run tests with a visible browser window
## CREATE AN INSTALLABLE FILE (Windows | MacOS | Linux)
@@ -48,22 +74,34 @@ 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`
- __Build the UI and server__ by running `turbo build:electron`
- __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`
Note: The MacOS build will only work in CI, locally it will fail due to notarisation issues.
Use the `turbo dist-mac:local` command to build a MacOS distribution locally.
## 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`
- __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 <process-id>`
## General Info
# APP Building
We build the app from app.js for almost all applications. The output file will still be named index.cjs. This is because of Electron.
Building the app from index.ts only applies for applications that don't use electron. index.ts will take over the initialization of the server and UI when electron isn't present.
+17 -7
View File
@@ -1,20 +1,30 @@
FROM node:16-alpine
FROM node:20-bullseye AS builder
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN npm install -g pnpm@9.5.0
COPY . /app
WORKDIR /app
RUN pnpm --filter=ontime-ui --filter=ontime-server --filter=ontime-utils install --config.dedupe-peer-dependents=false --frozen-lockfile
RUN pnpm --filter=ontime-ui --filter=ontime-server run build:docker
FROM node:20-alpine
# Set environment variables
# Environment Variable to signal that we are running production
ENV NODE_ENV=docker
# Ontime Data path
ENV ONTIME_DATA=/external/
ENV ONTIME_DATA=/data/
WORKDIR /app/
# Prepare UI
COPY /apps/client/build ./client/
COPY --from=builder /app/apps/client/build ./client/
# Prepare Backend
COPY /apps/server/dist/ ./server/
COPY /demo-db/ ./preloaded-db/
COPY /apps/server/src/external/ ./external/
COPY --from=builder /app/apps/server/dist/ ./server/
COPY --from=builder /app/apps/server/src/external/ ./external/
COPY --from=builder /app/apps/server/src/user/ ./user/
COPY --from=builder /app/apps/server/src/html/ ./html/
# Export default ports
EXPOSE 4001/tcp 8888/udp 9999/udp
@@ -24,4 +34,4 @@ CMD ["node", "server/docker.cjs"]
# 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
# docker run -p 4001:4001 -p 8888:8888/udp -p 9999:9999/udp -v ./ontime-db:/data/ getontime/ontime
+126 -148
View File
@@ -1,207 +1,185 @@
[![Ontime build v2](https://github.com/cpvalente/ontime/actions/workflows/build_v2.yml/badge.svg)](https://github.com/cpvalente/ontime/actions/workflows/build_v2.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://ontime.gitbook.io)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-green.svg)](https://www.gnu.org/licenses/gpl-3.0)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/cpvalente/ontime/total)
![Docker Pulls](https://img.shields.io/docker/pulls/getontime/ontime)
![NPM Downloads](https://img.shields.io/npm/dy/%40getontime%2Fcli)
![Homebrew Cask Version](https://img.shields.io/homebrew/cask/v/ontime)
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/cpvalente)
[![](https://img.shields.io/static/v1?label=Buy%20me%20a%20coffee&message=%E2%9D%A4&logo=buymeacoffee&color=%23fe8e86)](https://www.buymeacoffee.com/cpvalente)
## Download the latest releases here
## Download the latest release
<a href="https://www.buymeacoffee.com/cpvalente" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="32"></a>
<div style="display: flex; justify-content: space-around">
<a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-macOS.dmg"><img alt="Download MacOS" src="https://github.com/cpvalente/ontime/blob/master/.github/aux-images/mac-download.png"/></a>
<a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-win64.exe"><img alt="Download Windows" src="https://github.com/cpvalente/ontime/blob/master/.github/aux-images/win-download.png"/></a>
<a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-linux.AppImage"><img alt="Download Linux" src="https://github.com/cpvalente/ontime/blob/master/.github/aux-images/linux-download.png"/></a>
<a href="https://hub.docker.com/r/getontime/ontime"><img alt="Get from Dockerhub" src="https://github.com/cpvalente/ontime/blob/master/.github/aux-images/dockerhub.png"/></a>
</div>
- Download for <a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-win64.exe">Windows</a>
- Download for <a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-macOS-arm64.dmg">MacOS Arm</a>
- Download for <a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-macOS-x64.dmg">MacOS Intel</a>
- Download AppImage for <a href="https://github.com/cpvalente/ontime/releases/latest/download/ontime-linux.AppImage">Linux</a>
... or
- Get from <a href="https://hub.docker.com/r/getontime/ontime">Docker hub</a>
- Install from <a href="https://www.npmjs.com/package/ontime">NPM</a>
- Install from <a href="https://formulae.brew.sh/cask/ontime">Homebrew</a>
## Need help?
We do our best to have most topics covered by the documentation. However, if your question is not covered, you are welcome to [fill in a bug report in an issue](https://github.com/cpvalente/ontime/issues), [ask a question in GitHub discussions](https://github.com/cpvalente/ontime/discussions) or hop in the [discord server](https://discord.com/invite/eje3CSUEXm) for a chat.
## Using Ontime?
Let us know!
Ontime improves from the collaboration with its users. We would like to understand how you use Ontime and appreciate your feedback.
We would also like to include a testimonials section in our ✨new website✨. It would be great to showcase the diversity of users running Ontime.
# Ontime
Ontime is an application for creating and managing event running order and timers.
Ontime is a browser-based application that manages event rundowns, scheduling, and cueing.
The user inputs a list of events along with scheduling and event information.
This will then populate a series of screens which are available to be rendered by any device in the Network.
With Ontime, you can plan, track your schedule, manage automation and cross-department show information all in one place.
This makes for a simple and cheap way to distribute over a venue using a network infrastructure instead of video outputs.
Ontime is made by entertainment and broadcast engineers and used by
![App Window](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/app.png)
- Conference organisers
- Touring shows and receiving venues
- Broadcasters and streamers
- Theatres and opera houses
- Houses of worship
![Views](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/overview.png)
## Main features
- [x] **Multiplatform**: Available for Windows / MacOS, Linux. You can also self host with the docker image
- [x] **In any device**: Ontime is available in the local network to any device with a browser, eg: tablets, mobile phones, laptops, signage, media servers...
- [x] **Made for teams**: Ontime caters to different roles in your production team: directors, operators, backstage and front of house signage...
- [x] **Delay workflows**: Manage and communicate runtime delays in real-time to your team
- [x] **Automatable**: Ontime can be fully or partially controlled by an operator, or run standalone with the system clock
- [x] **Focus on integrations**: Use one of the APIs provided (OSC, HTTP, Websocket) or the available [Companion module](https://bitfocus.io/connections/getontime-ontime) to integrate into your workflow (vMix, disguise, Qlab, OBS)
... and a lot more ...
### For live environments
Ontime is designed for use in live environments. \
This guides the application into being flexible and efficiently integrating into different workflows.
### For teams
All information added in Ontime is shared with the production team and other software / hardware in your workflow. \
Ontime also improves team collaboration with dedicated views for cuesheets and operators, and for public and production
signage.
### Simple infrastructure
All the data is distributed over the network, making its distribution and infrastructure flexible and cheap. \
With the availability of the docker image, you can also leverage IT infrastructure to make Ontime available online for
your team and clients.
Ontime is made by video engineers and entertainment technicians.
![App Window](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/editor.png)
![Views](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/ontime-overview.webp)
[Read the docs to learn more](https://docs.getontime.no)
## Using Ontime
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.
Ontime can be started by downloading the latest release for your platform. \
Alternatively you can also use the docker image, available at [Docker Hub](https://hub.docker.com/r/getontime/ontime)
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`
<br />
You can then use the menu in the top left corner to select the desired view.
The menu will be initially hidden until there is mouse interaction.
Once installed and running, any device in the network has access to Ontime.
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
Ontime provides different screens which allow for different types of interactions with the data. These are called
views. \
Each view in Ontime focuses on empowering a specific role or achieving a particular task.
You can access the different views by reaching the ontime server, in your browser, at (_default port
4001_) `http://localhost:4001` or `http://192.168.1.3:4001`
```
For the presentation views
For the backstage 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/backstage > Stage Manager / Backstage view
IP.ADDRESS:4001/countdown > Countdown to anything
IP.ADDRESS:4001/studio > Studio Clock
IP.ADDRESS:4001/timeline > Timeline
```
```
For the public views
-------------------------------------------------------------
IP.ADDRESS:4001/public > Public / Foyer view
IP.ADDRESS:4001/lower > Lower Thirds
IP.ADDRESS:4001/studio > Studio Clock
```
```
For management views
For production views
-------------------------------------------------------------
IP.ADDRESS:4001/editor > the control interface, same as the app
IP.ADDRESS:4001/cuesheet > realtime cuesheets for collaboration
IP.ADDRESS:4001/operator > automated views for operators
```
More documentation is available [in our docs](https://ontime.gitbook.io)
## Feature List (in no specific order)
- [x] Distribute data over network and render it in the browser
- [x] Different screen types
- Stage Timer
- Minimal Timer
- Clock
- Backstage Info
- Public Info
- Studio Clock
- Countdown
- [Make your own?](#make-your-own-viewer)
- [x] Configurable Lower Thirds
- [x] Collaborative editing with the cuesheet view
- [x] Send live messages to different screen types
- [x] Differentiate between backstage and public data
- [x] Workflow for managing delays
- [x] Rich protocol integrations for Control and Feedback
- OSC (Open Sound Control)
- HTTP
- WebSockets
- [x] Roll mode: run standalone using the system clock
- [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 want Ontime to be unique by targeting freelancers instead of roles.
We believe most freelancers work in different fields and we want to give you a tool that you can leverage across your many environments and workflows.
We are not interested in forcing workflows and have made Ontime so, it is flexible to whichever way you would like to work.
## Rich APIs for workflow integrations
The app is currently being developed for a broad user base, from broadcast to entertainment and
conference halls.
Taking advantage of the integrations, we currently use Ontime with:
- `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**
- `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)
### Make your own viewer
Ontime broadcasts its data over WebSockets. This allows you to consume its data outside the application.
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).
<br />
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://ontime.gitbook.io/v2/control-and-feedback/ontime-apis#osc-and-websocket-api)
### Headless run
You can self-host and run Ontime in a docker image. The run command will:
- 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__
The docker image is
in [available Docker Hub at getontime/ontime](https://hub.docker.com/r/getontime/ontime)
```bash
docker pull getontime/ontime
```
and use the included docker compose to get started
```bash
docker-compose up
```
Related information available [in the docs](https://ontime.gitbook.io/v2/additional-notes/use-in-raspberry-pi)
More information is available [in our docs](https://docs.getontime.no)
## Roadmap
### Continued development
Several features are planned in the roadmap, and we continuously adjust this to match how users interact with the app.
<br />
Have an idea? Reach out via [email](mail@getontime.no) or [open an issue](https://github.com/cpvalente/ontime/issues/new)
Ontime is under active development. We continue adding and improving features in collaboration with users.
Have an idea? Reach out via [email](mail@getontime.no)
or [open an issue](https://github.com/cpvalente/ontime/issues/new)
### Issues
We use Github's issue tracking for bug reporting and feature requests. <br />
Found a bug? [Open an issue](https://github.com/cpvalente/ontime/issues/new).
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
When installing the app you would see warning screens from the Operating System like:
```Microsoft Defender SmartScreen prevented an unrecognised app from starting. Running this app might put your PC at risk.```
in Windows
or
```Ontime can't be opened because it is from an unidentified developer```
`Microsoft Defender SmartScreen prevented an unrecognised app from starting. Running this app might put your PC at risk.`
or in Linux
```Could Not Display "ontime-linux.AppImage```
`Could Not Display "ontime-linux.AppImage`
We currently only sign MacOS releases. \
Purchasing the certificates for both Mac and Windows would mean a recurrent expense which we are not able to cover.
You can circumvent this by allowing the execution of the app manually.
- In Windows: click more and select "Run Anyway"
- in macOS: after attempting to run the installer, navigate to System Preferences -> Security &
Privacy and allow the execution of the app
- In Linux: right-click the AppImage file -> Properties -> Permissions -> select Allow Executing
File as a Program
- In Windows: click `more` -> `Run Anyway`
- In Linux: right-click the AppImage file: `Properties` -> `Permissions` -> `Allow Executing File as a Program`
Long story short: Ontime app is unsigned. </br>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,
If you 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 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.
# Contributing
## Contributing
Looking to contribute? All types of help are appreciated, from coding to testing and feature specification.
<br /><br />
If you are a developer and would like to contribute with some code, please open an issue to discuss before opening a Pull Request.
<br />
If you are a developer and would like to contribute with 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
## Links
- [Ontime website](https://getontime.no)
- [Documentation](https://docs.getontime.no)
- [Ontime discord server](https://discord.com/invite/eje3CSUEXm)
Help is underway! ... and can be found [here](https://ontime.gitbook.io)
# License
## License
This project is licensed under the terms of the GNU GPL v3
## Sponsor
You can help the development of this project or say thank you with a one time donation. \
See [the terms of donations](https://github.com/cpvalente/ontime/blob/master/.github/FUNDING.md).
<p align="center">
<br>
<a href="https://www.buymeacoffee.com/cpvalente" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" width="200"></a>
</p>
+19
View File
@@ -0,0 +1,19 @@
# Terms of sponsorship
Ontime does not exist as a fiscal entity. The sponsorship recipient is the project owner. In this light, contributors are funding the project owner's capacity to work on the project, not the project itself. As a contribution recipient, the code owner reserves the right to redistribute.
## Why sponsor
Ontime is and will remain free, regardless of your decision to contribute.
Regardless, you may choose to provide a monetary contribution:
### Improve user experience
Certain parts of the application user experience are tied to our capacity to pay for services. App signing and Google Sheets integration are good examples of this.
### Cool stuff
We may choose not to implement some features. This could be related to the complexity required, to the skill set, or to the fact that we just feel it doesn't improve the app for a significant percentage of users. In those cases, a feature may be considered "not worth it," regardless of its pertinence.
As a user, you can choose to sponsor a particular feature or donate to the app so that we can create bounties for features.
### Priorities
Monetary contributions are most immediately needed to offset the costs of presenting and distributing Ontime, i.e., hosting, domains, and certificates.
Additional funding will be considered according to the needs at the time.
+16
View File
@@ -0,0 +1,16 @@
{
"parserOptions": {
"sourceType": "module"
},
"env": {
"browser": true,
"node": true
},
"extends": [
"eslint:recommended"
],
"plugins": [],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
}
+3
View File
@@ -0,0 +1,3 @@
server
external
client
+9
View File
@@ -0,0 +1,9 @@
{
"endOfLine": "lf",
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"printWidth": 120
}
+44
View File
@@ -0,0 +1,44 @@
# Ontime CLI
![Ontime](https://github.com/cpvalente/ontime/blob/9e63261b350e5b7b61c7ffb17c9e75a6c5a8c711/.github/aux-images/editor.png)
> Ontime is an application for managing rundown and event timers.
Congratulations! You got this far into Ontime's rabbit hole and want to manage your installation.
The CLI tool is a fast and lightweight way of installing Ontime and is perfect for self-hosting and headless installs.
## Getting started
### Prerequisites
You will need to have installed the correct version of node.js
Please check [the app engines declaration](https://github.com/cpvalente/ontime/blob/master/package.json) for the correct version.
### Running Ontime
To get Ontime running, all you need to do is install it in your system using your package manager of choice:
Install globally in your system
```bash
npm install -g @getontime/cli
```
... and run using the installed script
```bash
ontime
```
Or install and run ontime (the installation here is temporary for the duration of the session)
```bash
npx install @getontime/cli
```
## Links
- [Ontime's repository](https://github.com/cpvalente/ontime)
- [Ontime's documentation](https://docs.getontime.no/)
- [Ontime's website](https://getontime.no/)
## Sponsoring
You can help the development of this project or say thank you with a one time donation. \
See the [terms of donations](https://github.com/cpvalente/ontime/blob/master/SPONSOR.md)
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/cpvalente)
[![](https://img.shields.io/static/v1?label=Buy%20me%20a%20coffee&message=%E2%9D%A4&logo=buymeacoffee&color=%23fe8e86)](https://www.buymeacoffee.com/cpvalente)
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env node
// NOTE: for now the following needs to be in place: ./server/index.cjs, ./client, ./external
const ontimeServer = require('./server/index.cjs');
const { initAssets, startServer, startIntegrations, shutdown } = ontimeServer;
async function startOntime() {
await initAssets();
await startServer();
await startIntegrations();
}
startOntime();
process.on(['SIGHUP', 'SIGINT', 'SIGTERM'], () => {
shutdown();
});
+27
View File
@@ -0,0 +1,27 @@
{
"name": "@getontime/cli",
"version": "3.13.1",
"author": "Carlos Valente",
"description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime",
"keywords": [
"lighdev",
"ontime",
"timer"
],
"license": "AGPL-3.0-only",
"main": "main.js",
"bin": {
"ontime": "main.js"
},
"files": [
"client",
"external",
"server"
],
"devDependencies": {
"eslint": "catalog:",
"eslint-config-prettier": "catalog:",
"prettier": "catalog:"
}
}
+2 -19
View File
@@ -8,34 +8,17 @@
"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",
"plugin:@tanstack/eslint-plugin-query/recommended",
"prettier"
"plugin:@tanstack/eslint-plugin-query/recommended"
],
"plugins": [
"react",
"testing-library",
"simple-import-sort",
"@tanstack/query",
"@typescript-eslint",
"prettier"
"@tanstack/query"
],
"rules": {
"@typescript-eslint/no-non-null-assertion": "warn",
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
],
"no-useless-concat": "warn",
"prefer-template": "warn",
"react/jsx-no-bind": [
"error",
{
+1
View File
@@ -1,4 +1,5 @@
{
"endOfLine": "lf",
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
-6
View File
@@ -1,6 +0,0 @@
{
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-prettier"
]
}
+26 -35
View File
@@ -1,37 +1,28 @@
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<link rel='icon' href='/favicon.ico' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<meta name='theme-color' content='#121212' />
<meta name='ontime' content='ontime - event timer manager' />
<link rel='apple-touch-icon' href='/logo192.png' />
<link
rel='icon'
type='image/png'
sizes='32x32'
href='/favicon-32x32.png'
/>
<link
rel='icon'
type='image/png'
sizes='16x16'
href='/favicon-16x16.png'
/>
<link rel='manifest' href='/site.webmanifest' />
<link rel='manifest' href='/manifest.json' />
<title>ontime</title>
<style>
body,
html {
background-color: rgba(0, 0, 0, 0) !important;
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id='root'></div>
<script type='module' src='/src/index.tsx'></script>
</body>
<html lang="en">
<head>
<meta charset="utf-8" />
<base href="/" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#101010" />
<meta name="ontime" content="ontime - time keeping for live events" />
<link rel="apple-touch-icon" href="/ontime-logo.png" />
<link rel="icon" type="image/png" href="/ontime-logo.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="manifest" href="/manifest.json" />
<meta name="robots" content="noindex" />
<title>ontime</title>
<style>
body,
html {
background-color: rgba(0, 0, 0, 0) !important;
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
+44 -52
View File
@@ -1,36 +1,37 @@
{
"name": "ontime-ui",
"version": "2.0.0",
"version": "3.13.1",
"private": true,
"type": "module",
"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",
"@chakra-ui/react": "^2.7.0",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@emotion/is-prop-valid": "^1.3.1",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@fontsource/open-sans": "^5.0.28",
"@mantine/hooks": "^7.13.3",
"@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",
"@sentry/react": "^8.43.0",
"@tanstack/react-query": "^5.62.7",
"@tanstack/react-query-devtools": "^5.62.7",
"@tanstack/react-table": "^8.20.5",
"autosize": "^6.0.1",
"axios": "^1.2.0",
"color": "^4.2.3",
"csv-stringify": "^6.2.3",
"deepmerge": "^4.3.0",
"csv-stringify": "^6.4.5",
"framer-motion": "^10.10.0",
"react": "^18.2.0",
"react": "^18.3.1",
"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-dom": "^18.3.1",
"react-fast-compare": "^3.2.2",
"react-hook-form": "^7.53.1",
"react-qr-code": "^2.0.12",
"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"
"zustand": "^5.0.3"
},
"scripts": {
"addversion": "node -p \"'export const ONTIME_VERSION = ' + JSON.stringify(require('../../package.json').version) + ';'\" > src/ONTIME_VERSION.js",
@@ -38,12 +39,14 @@
"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",
"build:electron": "cross-env NODE_ENV=local vite build",
"build:docker": "cross-env VITE_IS_DOCKER=true vite build",
"build:localdocker": "cross-env NODE_ENV=local vite build",
"lint": "eslint . --quiet",
"test": "vitest",
"test:pipeline": "vitest run",
"cleanup": "rm -rf .turbo && rm -rf node_modules && rm -rf build"
"cleanup": "rm -rf .turbo && rm -rf node_modules && rm -rf build",
"analyse": "npx vite-bundle-visualizer"
},
"browserslist": {
"production": [
@@ -58,42 +61,31 @@
]
},
"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",
"@sentry/vite-plugin": "^2.16.1",
"@tanstack/eslint-plugin-query": "^5.8.4",
"@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",
"@typescript-eslint/eslint-plugin": "catalog:",
"@typescript-eslint/parser": "catalog:",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "catalog:",
"eslint-config-prettier": "catalog:",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-prettier": "catalog:",
"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",
"happy-dom": "^16.7.2",
"ontime-types": "workspace:*",
"ontime-utils": "workspace:*",
"prettier": "^2.8.3",
"prop-types": "^15.8.1",
"prettier": "catalog:",
"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"
"typescript": "catalog:",
"vite": "^5.2.11",
"vite-plugin-compression2": "^1.3.3",
"vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "catalog:"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

+2 -9
View File
@@ -4,18 +4,11 @@
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
"src": "ontime-logo.png",
"type": "image/png"
}
],
"scope": "/",
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+10 -1
View File
@@ -1 +1,10 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
{
"name": "",
"short_name": "",
"icons": [
{ "src": "/ontime-logo.png", "sizes": "295x295", "type": "image/png" }
],
"theme_color": "#2B5ABC",
"background_color": "#101010",
"display": "standalone"
}
+17 -45
View File
@@ -1,67 +1,39 @@
import { useEffect } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { ChakraProvider } from '@chakra-ui/react';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import ErrorBoundary from './common/components/error-boundary/ErrorBoundary';
import IdentifyOverlay from './common/components/identify-overlay/IdentifyOverlay';
import { AppContextProvider } from './common/context/AppContext';
import { ContextMenuProvider } from './common/context/ContextMenuContext';
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');
import { baseURI } from './externals';
connectSocket();
function App() {
const { isElectron, sendToElectron } = useElectronEvent();
useEffect(() => {
const handleKeyPress = (event: KeyboardEvent) => {
// handle held key
if (event.repeat) return;
// check if the alt key is pressed
if (event.altKey) {
if (event.code === 'KeyT') {
// ask to see debug
sendToElectron('set-window', 'show-dev');
}
}
};
if (isElectron) {
document.addEventListener('keydown', handleKeyPress);
}
return () => {
if (isElectron) {
document.removeEventListener('keydown', handleKeyPress);
}
};
}, [isElectron, sendToElectron]);
return (
<ChakraProvider resetCSS theme={theme}>
<ChakraProvider disableGlobalStyle resetCSS theme={theme}>
<QueryClientProvider client={ontimeQueryClient}>
<AppContextProvider>
<ContextMenuProvider>
<BrowserRouter>
<div className='App'>
<ErrorBoundary>
<TranslationProvider>
<AppRouter />
</TranslationProvider>
</ErrorBoundary>
<ReactQueryDevtools initialIsOpen={false} />
</div>
</BrowserRouter>
</ContextMenuProvider>
<BrowserRouter basename={baseURI}>
<div className='App'>
<ErrorBoundary>
<TranslationProvider>
<IdentifyOverlay />
<AppRouter />
</TranslationProvider>
</ErrorBoundary>
<ReactQueryDevtools initialIsOpen={false} />
</div>
<ErrorBoundary>
<div id='identify-portal' />
</ErrorBoundary>
</BrowserRouter>
</AppContextProvider>
</QueryClientProvider>
</ChakraProvider>
+149 -69
View File
@@ -1,84 +1,164 @@
import { lazy, Suspense, useEffect } from 'react';
import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
import React from 'react';
import {
createRoutesFromChildren,
matchRoutes,
Navigate,
Route,
Routes,
useLocation,
useNavigationType,
} from 'react-router-dom';
import * as Sentry from '@sentry/react';
import useAliases from './common/hooks-query/useAliases';
import { useClientPath } from './common/hooks/useClientPath';
import Log from './features/log/Log';
import withPreset from './features/PresetWrapper';
import withData from './features/viewers/ViewWrapper';
import ViewLoader from './views/ViewLoader';
import { ONTIME_VERSION } from './ONTIME_VERSION';
import { sentryDsn, sentryRecommendedIgnore } from './sentry.config';
const Editor = lazy(() => import('./features/editors/ProtectedEditor'));
const Table = lazy(() => import('./features/table/ProtectedTable'));
const Editor = React.lazy(() => import('./features/editors/ProtectedEditor'));
const Cuesheet = React.lazy(() => import('./views/cuesheet/ProtectedCuesheet'));
const Operator = React.lazy(() => import('./features/operator/OperatorExport'));
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 TimerView = React.lazy(() => import('./views/timer/Timer'));
const MinimalTimerView = React.lazy(() => import('./features/viewers/minimal-timer/MinimalTimer'));
const ClockView = React.lazy(() => import('./features/viewers/clock/Clock'));
const Countdown = React.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 Backstage = React.lazy(() => import('./views/backstage/Backstage'));
const Timeline = React.lazy(() => import('./views/timeline/TimelinePage'));
const Public = React.lazy(() => import('./views/public/Public'));
const Lower = React.lazy(() => import('./features/viewers/lower-thirds/LowerThird'));
const StudioClock = React.lazy(() => import('./features/viewers/studio/StudioClock'));
const ProjectInfo = React.lazy(() => import('./views/project-info/ProjectInfo'));
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 STimer = withPreset(withData(TimerView));
const SMinimalTimer = withPreset(withData(MinimalTimerView));
const SClock = withPreset(withData(ClockView));
const SCountdown = withPreset(withData(Countdown));
const SBackstage = withPreset(withData(Backstage));
const SProjectInfo = withPreset(withData(ProjectInfo));
const SPublic = withPreset(withData(Public));
const SLowerThird = withPreset(withData(Lower));
const SStudio = withPreset(withData(StudioClock));
const STimeline = withPreset(withData(Timeline));
const PCuesheet = withPreset(Cuesheet);
const POperator = withPreset(Operator);
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'));
const EditorFeatureWrapper = React.lazy(() => import('./features/EditorFeatureWrapper'));
const RundownPanel = React.lazy(() => import('./features/rundown/RundownExport'));
const TimerControl = React.lazy(() => import('./features/control/playback/TimerControlExport'));
const MessageControl = React.lazy(() => import('./features/control/message/MessageControlExport'));
Sentry.init({
dsn: sentryDsn,
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
}),
],
tracesSampleRate: 0.3,
release: ONTIME_VERSION,
enabled: import.meta.env.PROD,
ignoreErrors: [...sentryRecommendedIgnore, /Unable to preload CSS/i, /dynamically imported module/i],
denyUrls: [/extensions\//i, /^chrome:\/\//i, /^chrome-extension:\/\//i],
});
const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes);
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]);
// handle client path changes
useClientPath();
return (
<Suspense fallback={null}>
<Routes>
<React.Suspense fallback={null}>
<SentryRoutes>
<Route path='/' element={<Navigate to='/timer' />} />
<Route path='/speaker' element={<STimer />} />
<Route path='/presenter' element={<STimer />} />
<Route path='/stage' element={<STimer />} />
<Route path='/timer' element={<STimer />} />
<Route path='/minimal' element={<SMinimalTimer />} />
<Route path='/minimalTimer' element={<SMinimalTimer />} />
<Route path='/simpleTimer' element={<SMinimalTimer />} />
<Route path='/clock' element={<SClock />} />
<Route path='/countdown' element={<SCountdown />} />
<Route path='/sm' element={<SBackstage />} />
<Route path='/backstage' element={<SBackstage />} />
<Route path='/public' element={<SPublic />} />
<Route path='/studio' element={<SStudio />} />
{/*/!* Lower cannot have fallback *!/*/}
<Route
path='/timer'
element={
<ViewLoader>
<STimer />
</ViewLoader>
}
/>
<Route
path='/public'
element={
<ViewLoader>
<SPublic />
</ViewLoader>
}
/>
<Route
path='/minimal'
element={
<ViewLoader>
<SMinimalTimer />
</ViewLoader>
}
/>
<Route
path='/clock'
element={
<ViewLoader>
<SClock />
</ViewLoader>
}
/>
<Route
path='/countdown'
element={
<ViewLoader>
<SCountdown />
</ViewLoader>
}
/>
<Route
path='/backstage'
element={
<ViewLoader>
<SBackstage />
</ViewLoader>
}
/>
<Route
path='/studio'
element={
<ViewLoader>
<SStudio />
</ViewLoader>
}
/>
{/*/!* Lower third cannot have a loading screen *!/*/}
<Route path='/lower' element={<SLowerThird />} />
<Route
path='/timeline'
element={
<ViewLoader>
<STimeline />
</ViewLoader>
}
/>
<Route
path='/info'
element={
<ViewLoader>
<SProjectInfo />
</ViewLoader>
}
/>
{/*/!* Protected Routes *!/*/}
<Route path='/editor' element={<Editor />} />
<Route path='/cuesheet' element={<Table />} />
<Route path='/cuelist' element={<Table />} />
<Route path='/table' element={<Table />} />
<Route path='/cuesheet' element={<PCuesheet />} />
<Route path='/op' element={<POperator />} />
{/*/!* Protected Routes - Elements *!/*/}
<Route
@@ -106,16 +186,16 @@ export default function AppRouter() {
}
/>
<Route
path='/info'
path='/log'
element={
<EditorFeatureWrapper>
<Info />
<Log />
</EditorFeatureWrapper>
}
/>
{/*/!* Send to default if nothing found *!/*/}
<Route path='*' element={<STimer />} />
</Routes>
</Suspense>
</SentryRoutes>
</React.Suspense>
);
}
@@ -1,9 +0,0 @@
import { QueryClient } from '@tanstack/react-query';
export const queryClientMock = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
-22
View File
@@ -1,22 +0,0 @@
// 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' },
];
@@ -1,24 +0,0 @@
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 = `${window.location.protocol === "https:" ? "wss" : "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}`;
+85
View File
@@ -0,0 +1,85 @@
import axios from 'axios';
import type {
Automation,
AutomationDTO,
AutomationOutput,
AutomationSettings,
Trigger,
TriggerDTO,
} from 'ontime-types';
import { apiEntryUrl } from './constants';
const automationsPath = `${apiEntryUrl}/automations`;
/**
* HTTP request to get the automations settings
*/
export async function getAutomationSettings(): Promise<AutomationSettings> {
const res = await axios.get(automationsPath);
return res.data;
}
/**
* HTTP request to edit the automations settings
*/
export async function editAutomationSettings(
automationSettings: Partial<AutomationSettings>,
): Promise<AutomationSettings> {
const res = await axios.post(automationsPath, automationSettings);
return res.data;
}
/**
* HTTP request to create a new automation trigger
*/
export async function addTrigger(trigger: TriggerDTO): Promise<Trigger> {
const res = await axios.post(`${automationsPath}/trigger`, trigger);
return res.data;
}
/**
* HTTP request to update an automation trigger
*/
export async function editTrigger(id: string, trigger: Trigger): Promise<Trigger> {
const res = await axios.put(`${automationsPath}/trigger/${id}`, trigger);
return res.data;
}
/**
* HTTP request to delete an automation trigger
*/
export function deleteTrigger(id: string): Promise<void> {
return axios.delete(`${automationsPath}/trigger/${id}`);
}
/**
* HTTP request to create a new automation
*/
export async function addAutomation(automation: AutomationDTO): Promise<Automation> {
const res = await axios.post(`${automationsPath}/automation`, automation);
return res.data;
}
/**
* HTTP request to update a automation
*/
export async function editAutomation(id: string, automation: Automation): Promise<Automation> {
const res = await axios.put(`${automationsPath}/automation/${id}`, automation);
return res.data;
}
/**
* HTTP request to delete a automation
*/
export function deleteAutomation(id: string): Promise<void> {
return axios.delete(`${automationsPath}/automation/${id}`);
}
/**
* HTTP request to test automation output
* The return is irrelevant as we care for the resolution of the promise
*/
export function testOutput(output: AutomationOutput): Promise<void> {
return axios.post(`${automationsPath}/test`, output);
}
+29
View File
@@ -0,0 +1,29 @@
import { serverURL } from '../../externals';
// keys in tanstack store
export const APP_INFO = ['appinfo'];
export const APP_SETTINGS = ['appSettings'];
export const APP_VERSION = ['appVersion'];
export const AUTOMATION = ['automation'];
export const CUSTOM_FIELDS = ['customFields'];
export const PROJECT_DATA = ['project'];
export const PROJECT_LIST = ['projectList'];
export const RUNDOWN = ['rundown'];
export const RUNTIME = ['runtimeStore'];
export const SHEET_STATE = ['sheetState'];
export const URL_PRESETS = ['urlpresets'];
export const VIEW_SETTINGS = ['viewSettings'];
export const CLIENT_LIST = ['clientList'];
export const REPORT = ['report'];
// API URLs
export const apiEntryUrl = `${serverURL}/data`;
export const projectDataURL = `${serverURL}/project`;
export const rundownURL = `${serverURL}/events`;
export const ontimeURL = `${serverURL}/ontime`;
export const userAssetsPath = 'user';
export const cssOverridePath = 'styles/override.css';
export const overrideStylesURL = `${serverURL}/${userAssetsPath}/${cssOverridePath}`;
export const projectLogoPath = `${serverURL}/${userAssetsPath}/logo`;
@@ -0,0 +1,38 @@
import axios from 'axios';
import { CustomField, CustomFieldLabel, CustomFields } from 'ontime-types';
import { apiEntryUrl } from './constants';
const customFieldsPath = `${apiEntryUrl}/custom-fields`;
/**
* Requests list of known custom fields
*/
export async function getCustomFields(): Promise<CustomFields> {
const res = await axios.get(customFieldsPath);
return res.data;
}
/**
* Sets list of known custom fields
*/
export async function postCustomField(newField: CustomField): Promise<CustomFields> {
const res = await axios.post(customFieldsPath, { ...newField });
return res.data;
}
/**
* Edits single custom field
*/
export async function editCustomField(label: CustomFieldLabel, newField: CustomField): Promise<CustomFields> {
const res = await axios.put(`${customFieldsPath}/${label}`, { ...newField });
return res.data;
}
/**
* Deletes single custom field
*/
export async function deleteCustomField(label: CustomFieldLabel): Promise<CustomFields> {
const res = await axios.delete(`${customFieldsPath}/${label}`);
return res.data;
}
+177
View File
@@ -0,0 +1,177 @@
import axios, { AxiosResponse } from 'axios';
import { DatabaseModel, MessageResponse, ProjectData, ProjectFileListResponse, QuickStartData } from 'ontime-types';
import { makeTable } from '../../views/cuesheet/cuesheet.utils';
import { makeCSVFromArrayOfArrays } from '../utils/csv';
import { apiEntryUrl } from './constants';
import { createBlob, downloadBlob } from './utils';
const dbPath = `${apiEntryUrl}/db`;
/**
* HTTP request to the current DB
*/
export function getDb(filename: string): Promise<AxiosResponse<DatabaseModel>> {
return axios.post(`${dbPath}/download`, { filename });
}
/**
* Request download of the current project file
* @param fileName
*/
export async function downloadProject(fileName: string) {
try {
const { data, name } = await fileDownload(fileName);
const fileContent = JSON.stringify(data, null, 2);
const blob = createBlob(fileContent, 'application/json;charset=utf-8;');
downloadBlob(blob, `${name}.json`);
} catch (error) {
console.error(error);
}
}
/**
* Request download of the current rundown as a CSV file
* @param fileName
*/
export async function downloadCSV(fileName: string = 'rundown') {
try {
const { data, name } = await fileDownload(fileName);
const { project, rundown, customFields } = data;
const sheetData = makeTable(project, rundown, customFields);
const fileContent = makeCSVFromArrayOfArrays(sheetData);
const blob = createBlob(fileContent, 'text/csv;charset=utf-8;');
downloadBlob(blob, `${name}.csv`);
} catch (error) {
console.error(error);
}
}
/**
* HTTP request to upload project file
*/
export async function uploadProjectFile(file: File): Promise<MessageResponse> {
const formData = new FormData();
formData.append('project', file);
const response = await axios.post(`${dbPath}/upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
}
/**
* Make patch changes to the objects in the db
*/
export async function patchData(patchDb: Partial<DatabaseModel>): Promise<AxiosResponse<DatabaseModel>> {
return await axios.patch(dbPath, patchDb);
}
/**
* HTTP request to create a project file
*/
export async function createProject(
project: Partial<
ProjectData & {
filename: string;
}
>,
): Promise<MessageResponse> {
const res = await axios.post(`${dbPath}/new`, project);
return res.data;
}
/**
* HTTP request to create a project file
*/
export async function quickProject(data: QuickStartData): Promise<MessageResponse> {
const res = await axios.post(`${dbPath}/quick`, data);
return res.data;
}
/**
* HTTP request to get the list of available project files
*/
export async function getProjects(): Promise<ProjectFileListResponse> {
const res = await axios.get(`${dbPath}/all`);
return res.data;
}
/**
* HTTP request to load a project file
*/
export async function loadProject(filename: string): Promise<MessageResponse> {
const res = await axios.post(`${dbPath}/load`, {
filename,
});
return res.data;
}
/**
* HTTP request to load the demo project file
*/
export async function loadDemo(): Promise<MessageResponse> {
const res = await axios.post(`${dbPath}/demo`);
return res.data;
}
/**
* HTTP request to duplicate a project file
*/
export async function duplicateProject(filename: string, newFilename: string): Promise<MessageResponse> {
const url = `${dbPath}/${filename}/duplicate`;
const decodedUrl = decodeURIComponent(url);
const res = await axios.post(decodedUrl, {
newFilename,
});
return res.data;
}
/**
* HTTP request to rename a project file
*/
export async function renameProject(filename: string, newFilename: string): Promise<MessageResponse> {
const url = `${dbPath}/${filename}/rename`;
const decodedUrl = decodeURIComponent(url);
const res = await axios.put(decodedUrl, {
newFilename,
});
return res.data;
}
/**
* HTTP request to delete a project file
*/
export async function deleteProject(filename: string): Promise<MessageResponse> {
const url = `${dbPath}/${filename}`;
const decodedUrl = decodeURIComponent(url);
const res = await axios.delete(decodedUrl);
return res.data;
}
/**
* Utility function gets project from db
* @param fileName
* @returns
*/
async function fileDownload(fileName: string): Promise<{ data: DatabaseModel; name: string }> {
const response = await getDb(fileName);
const headerLine = response.headers['Content-Disposition'];
// try and get the filename from the response
let name = fileName;
if (headerLine != null) {
const startFileNameIndex = headerLine.indexOf('"') + 1;
const endFileNameIndex = headerLine.lastIndexOf('"');
name = headerLine.substring(startFileNameIndex, endFileNameIndex);
}
return { data: response.data, name };
}
@@ -1,21 +0,0 @@
import axios from 'axios';
import { EventData } from 'ontime-types';
import { eventURL } from './apiConstants';
/**
* @description HTTP request to fetch event data
* @return {Promise}
*/
export async function fetchEventData(): Promise<EventData> {
const res = await axios.get(eventURL);
return res.data;
}
/**
* @description HTTP request to mutate event data
* @return {Promise}
*/
export async function postEventData(data: EventData) {
return axios.post(eventURL, data);
}
-75
View File
@@ -1,75 +0,0 @@
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<OntimeRundown> {
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<OntimeRundownEntry>) {
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`);
}
+42
View File
@@ -0,0 +1,42 @@
import axios, { AxiosResponse } from 'axios';
import { CustomFields, OntimeRundown } from 'ontime-types';
import { ImportMap } from 'ontime-utils';
import { apiEntryUrl } from './constants';
const excelPath = `${apiEntryUrl}/excel`;
type PreviewSpreadsheetResponse = {
rundown: OntimeRundown;
customFields: CustomFields;
};
/**
* upload Excel file to server
* @return string - file ID op the uploaded file
*/
export async function upload(file: File) {
const formData = new FormData();
formData.append('excel', file);
await axios.post(`${excelPath}/upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
}
/**
* Get Worksheet names
* @return string[] - array of available worksheets
*/
export async function getWorksheetNames(): Promise<string[]> {
const response: AxiosResponse<string[]> = await axios.get(`${excelPath}/worksheets`);
return response.data;
}
export async function importRundownPreview(options: ImportMap): Promise<PreviewSpreadsheetResponse> {
const response: AxiosResponse<PreviewSpreadsheetResponse> = await axios.post(`${excelPath}/preview`, {
options,
});
return response.data;
}
+19
View File
@@ -0,0 +1,19 @@
import axios from 'axios';
import { apiRepoLatest } from '../../externals';
export type HasUpdate = {
url: string;
version: string;
};
/**
* HTTP request to get the latest version and url from github
*/
export async function getLatestVersion(): Promise<HasUpdate> {
const res = await axios.get(`${apiRepoLatest}`);
return {
url: res.data.html_url as string,
version: res.data.tag_name as string,
};
}
-191
View File
@@ -1,191 +0,0 @@
import axios from 'axios';
import {
Alias,
EventData,
OSCSettings,
OscSubscription,
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<Settings> {
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<InfoType> {
const res = await axios.get(`${ontimeURL}/info`);
return res.data;
}
/**
* @description HTTP request to retrieve view settings
* @return {Promise}
*/
export async function getView(): Promise<ViewSettings> {
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<Alias[]> {
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<UserFields> {
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<OSCSettings> {
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 mutate osc subscriptions
* @return {Promise}
*/
export async function postOscSubscriptions(data: OscSubscription) {
return axios.post(`${ontimeURL}/osc-subscriptions`, 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<HasUpdate> {
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<EventData>) {
return axios.post(`${ontimeURL}/new`, initialData);
}
+36
View File
@@ -0,0 +1,36 @@
import axios, { AxiosResponse } from 'axios';
import { ProjectData, ProjectLogoResponse } from 'ontime-types';
import { apiEntryUrl } from './constants';
const projectPath = `${apiEntryUrl}/project`;
/**
* HTTP request to fetch project data
*/
export async function getProjectData(): Promise<ProjectData> {
const res = await axios.get(projectPath);
return res.data;
}
/**
* HTTP request to mutate project data
*/
export async function postProjectData(data: ProjectData): Promise<AxiosResponse<ProjectData>> {
return axios.post(projectPath, data);
}
/**
* HTTP request to upload a project logo
*/
export async function uploadProjectLogo(file: File): Promise<AxiosResponse<ProjectLogoResponse>> {
const formData = new FormData();
formData.append('image', file);
const response = await axios.post(`${projectPath}/upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response;
}
+26
View File
@@ -0,0 +1,26 @@
import axios from 'axios';
import { OntimeReport } from 'ontime-types';
import { ontimeQueryClient } from '../../common/queryClient';
import { apiEntryUrl, REPORT } from './constants';
export const reportUrl = `${apiEntryUrl}/report`;
/**
* HTTP request to fetch all reports
*/
export async function fetchReport(): Promise<OntimeReport> {
const res = await axios.get(`${reportUrl}/`);
return res.data;
}
export async function deleteReport(id: string) {
await axios.delete(`${reportUrl}/${id}`);
await ontimeQueryClient.invalidateQueries({ queryKey: REPORT });
}
export async function deleteAllReport() {
await axios.delete(`${reportUrl}/all`);
await ontimeQueryClient.invalidateQueries({ queryKey: REPORT });
}
+86
View File
@@ -0,0 +1,86 @@
import axios, { AxiosResponse } from 'axios';
import { MessageResponse, OntimeEvent, OntimeRundownEntry, RundownCached, TransientEventPayload } from 'ontime-types';
import { apiEntryUrl } from './constants';
const rundownPath = `${apiEntryUrl}/rundown`;
/**
* HTTP request to fetch all events
*/
export async function fetchNormalisedRundown(): Promise<RundownCached> {
const res = await axios.get(`${rundownPath}/normalised`);
return res.data;
}
/**
* HTTP request to post new event
*/
export async function requestPostEvent(data: TransientEventPayload): Promise<AxiosResponse<OntimeRundownEntry>> {
return axios.post(rundownPath, data);
}
/**
* HTTP request to put new event
*/
export async function requestPutEvent(data: Partial<OntimeRundownEntry>): Promise<AxiosResponse<OntimeRundownEntry>> {
return axios.put(rundownPath, data);
}
type BatchEditEntry = {
data: Partial<OntimeEvent>;
ids: string[];
};
/**
* HTTP request to put multiple events
*/
export async function requestBatchPutEvents(data: BatchEditEntry): Promise<AxiosResponse<MessageResponse>> {
return axios.put(`${rundownPath}/batch`, data);
}
export type ReorderEntry = {
eventId: string;
from: number;
to: number;
};
/**
* HTTP request to reorder events
*/
export async function requestReorderEvent(data: ReorderEntry): Promise<AxiosResponse<OntimeRundownEntry>> {
return axios.patch(`${rundownPath}/reorder`, data);
}
export type SwapEntry = {
from: string;
to: string;
};
/**
* HTTP request to swap two events
*/
export async function requestEventSwap(data: SwapEntry): Promise<AxiosResponse<MessageResponse>> {
return axios.patch(`${rundownPath}/swap`, data);
}
/**
* HTTP request to request application of delay
*/
export async function requestApplyDelay(eventId: string): Promise<AxiosResponse<MessageResponse>> {
return axios.patch(`${rundownPath}/applydelay/${eventId}`);
}
/**
* HTTP request to delete given event
*/
export async function requestDelete(eventIds: string[]): Promise<AxiosResponse<MessageResponse>> {
return axios.delete(rundownPath, { data: { ids: eventIds } });
}
/**
* HTTP request to delete all events
*/
export async function requestDeleteAll(): Promise<AxiosResponse<MessageResponse>> {
return axios.delete(`${rundownPath}/all`);
}
+27
View File
@@ -0,0 +1,27 @@
import axios from 'axios';
import { GetInfo } from 'ontime-types';
import { apiEntryUrl } from './constants';
const sessionPath = `${apiEntryUrl}/session`;
/**
* HTTP request to retrieve application info
*/
export async function getInfo(): Promise<GetInfo> {
const res = await axios.get(`${sessionPath}/info`);
return res.data;
}
/**
* HTTP request to get a pre-authenticated URL
*/
export async function generateUrl(
baseUrl: string,
path: string,
lock: boolean,
authenticate: boolean,
): Promise<string> {
const res = await axios.post(`${sessionPath}/url`, { baseUrl, path, lock, authenticate });
return res.data.url;
}
+28
View File
@@ -0,0 +1,28 @@
import axios, { AxiosResponse } from 'axios';
import { Settings } from 'ontime-types';
import { apiEntryUrl } from './constants';
const settingsPath = `${apiEntryUrl}/settings`;
/**
* HTTP request to retrieve application settings
*/
export async function getSettings(): Promise<Settings> {
const res = await axios.get(settingsPath);
return res.data;
}
/**
* HTTP request to mutate application settings
*/
export async function postSettings(data: Settings): Promise<AxiosResponse<Settings>> {
return axios.post(settingsPath, data);
}
/**
* Allows setting the welcome modal dialog state from the clients
*/
export async function postShowWelcomeDialog(show: boolean) {
axios.post(`${settingsPath}/welcomedialog`, { show });
}
+75
View File
@@ -0,0 +1,75 @@
import axios, { AxiosResponse } from 'axios';
import { AuthenticationStatus, CustomFields, OntimeRundown } from 'ontime-types';
import { ImportMap } from 'ontime-utils';
import { apiEntryUrl } from './constants';
const sheetsPath = `${apiEntryUrl}/sheets`;
/**
* HTTP request to verify whether we are authenticated with Google Sheet service
*/
export const verifyAuthenticationStatus = async (): Promise<{
authenticated: AuthenticationStatus;
sheetId: string;
}> => {
const response = await axios.get(`${sheetsPath}/connect`);
return response.data;
};
/**
* HTTP request to initiate the authentication service with google
*/
export const requestConnection = async (
file: File,
sheetId: string,
): Promise<{
verification_url: string;
user_code: string;
}> => {
const formData = new FormData();
formData.append('client_secret', file);
const response = await axios.post(`${sheetsPath}/${sheetId}/connect`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
};
/**
* HTTP request to revoke authentication to google sheet
*/
export const revokeAuthentication = async (): Promise<{ authenticated: AuthenticationStatus }> => {
const response = await axios.post(`${sheetsPath}/revoke`);
return response.data;
};
/**
* HTTP request to upload preview the contents of a google sheet as rundown
*/
export const previewRundown = async (
sheetId: string,
options: ImportMap,
): Promise<{
rundown: OntimeRundown;
customFields: CustomFields;
}> => {
const response = await axios.post(`${sheetsPath}/${sheetId}/read`, { options });
return response.data;
};
export const getWorksheetNames = async (sheetId: string): Promise<string[]> => {
const response: AxiosResponse<string[]> = await axios.post(`${sheetsPath}/${sheetId}/worksheets`);
return response.data;
};
/**
* HTTP request to upload the rundown to a google sheet
*/
export const uploadRundown = async (sheetId: string, options: ImportMap): Promise<void> => {
const response = await axios.post(`${sheetsPath}/${sheetId}/write`, { options });
return response.data;
};
+21
View File
@@ -0,0 +1,21 @@
import axios from 'axios';
import { URLPreset } from 'ontime-types';
import { apiEntryUrl } from './constants';
const urlPresetsPath = `${apiEntryUrl}/url-presets`;
/**
* HTTP request to retrieve aliases
*/
export async function getUrlPresets(): Promise<URLPreset[]> {
const res = await axios.get(urlPresetsPath);
return res.data;
}
/**
* HTTP request to mutate aliases
*/
export async function postUrlPresets(data: URLPreset[]): Promise<URLPreset[]> {
return axios.post(urlPresetsPath, data);
}
+85
View File
@@ -0,0 +1,85 @@
import axios, { AxiosError } from 'axios';
import { LogLevel } from 'ontime-types';
import { generateId, millisToString } from 'ontime-utils';
import { ontimeQueryClient } from '../queryClient';
import { addLog } from '../stores/logger';
import { nowInMillis } from '../utils/time';
/**
* Utility unrwap a potential axios error
* @param error
* @returns
*/
export function maybeAxiosError(error: unknown) {
if (axios.isAxiosError(error)) {
const statusText = (error as AxiosError).response?.statusText ?? '';
let data = (error as AxiosError).response?.data ?? '';
if (typeof data === 'object') {
if ('message' in data) {
data = JSON.stringify(data.message);
} else {
data = JSON.stringify(data);
}
}
return `${statusText}: ${data}`;
} else if (error instanceof Error) {
return error.message;
} else {
if (typeof error !== 'string') {
return JSON.stringify(error);
}
return error;
}
}
/**
* Utility unrwaps a potential axios error and sends to logger
* @param prepend
* @param error
*/
export function logAxiosError(prepend: string, error: unknown) {
const message = `${prepend}: ${maybeAxiosError(error)}`;
addLog({
id: generateId(),
origin: 'SERVER',
time: millisToString(nowInMillis()),
level: LogLevel.Error,
text: message,
});
}
/**
* Utility function invalidates react-query caches
*/
export async function invalidateAllCaches() {
await ontimeQueryClient.invalidateQueries();
}
/**
* Creates blob from content
* @param fileContent
* @param type
* @returns
*/
export function createBlob(fileContent: string, type: string): Blob {
return new Blob([fileContent], { type });
}
/**
* downloads a blob
* @param downloadUrl
* @param fileName
*/
export function downloadBlob(blob: Blob, fileName: string) {
const downloadUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', downloadUrl);
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
// Clean up the URL.createObjectURL to release resources
URL.revokeObjectURL(downloadUrl);
}
@@ -0,0 +1,21 @@
import axios from 'axios';
import { ViewSettings } from 'ontime-types';
import { apiEntryUrl } from './constants';
const viewSettingsPath = `${apiEntryUrl}/view-settings`;
/**
* HTTP request to retrieve view settings
*/
export async function getView(): Promise<ViewSettings> {
const res = await axios.get(viewSettingsPath);
return res.data;
}
/**
* HTTP request to mutate view settings
*/
export async function postViewSettings(data: ViewSettings) {
return axios.post(viewSettingsPath, data);
}
@@ -1,26 +0,0 @@
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';
export default function EnableBtn(props) {
const { active, text, actionHandler, size = 'xs' } = props;
return (
<Button
size={size}
leftIcon={active ? <IoCheckmarkSharp /> : <IoCloseSharp />}
colorScheme='blue'
variant={active ? 'solid' : 'outline'}
onClick={actionHandler}
>
{text}
</Button>
);
}
EnableBtn.propTypes = {
active: PropTypes.bool,
text: PropTypes.string,
actionHandler: PropTypes.func,
size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
}
@@ -0,0 +1,26 @@
.subtle {
aspect-ratio: 1;
height: 2rem;
height: 2rem;
display: grid;
place-content: center;
background: $gray-1050;
color: $blue-400;
border: 1px solid transparent;
border-radius: 3px;
&:hover:not(:disabled):not(:active) {
background: $gray-1000;
color: $blue-500;
}
&:active {
background: $gray-1100;
border-color: $gray-1250;
}
&:disabled {
background: $gray-1050;
}
}
@@ -0,0 +1,14 @@
import { ButtonHTMLAttributes } from 'react';
import { cx } from '../../utils/styleUtils';
import style from './IconButton.module.scss';
export default function IconButton(props: ButtonHTMLAttributes<HTMLButtonElement>) {
const { className, children, ...buttonProps } = props;
return (
<button className={cx([style.subtle, className])} {...buttonProps}>
{children}
</button>
);
}
@@ -1,28 +0,0 @@
import { IconButton, Tooltip } from '@chakra-ui/react';
import { IoPause } from '@react-icons/all-files/io5/IoPause';
import { tooltipDelayMid } from '../../../ontimeConfig';
interface PauseIconBtnProps {
clickhandler: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
active: boolean;
disabled: boolean;
}
export default function PauseIconBtn(props: PauseIconBtnProps) {
const { clickhandler, active, disabled, ...rest } = props;
return (
<Tooltip label='Pause timer' openDelay={tooltipDelayMid} shouldWrapChildren={disabled}>
<IconButton
icon={<IoPause size='24px' />}
colorScheme='orange'
variant={active ? 'solid' : 'outline'}
onClick={clickhandler}
width={120}
disabled={disabled}
aria-label='Pause playback'
{...rest}
/>
</Tooltip>
);
}
@@ -1,25 +0,0 @@
import { IconButton, Tooltip } from '@chakra-ui/react';
import { FiUsers } from '@react-icons/all-files/fi/FiUsers';
import PropTypes from 'prop-types';
export default function PublicIconBtn(props) {
const { actionHandler, active, size = 'xs', ...rest } = props;
return (
<Tooltip label={active ? 'Make event private' : 'Make event public'}>
<IconButton
size={size}
icon={<FiUsers />}
colorScheme='blue'
variant={active ? 'solid' : 'outline'}
onClick={() => actionHandler('update', { field: 'isPublic', value: !active })}
{...rest}
/>
</Tooltip>
);
}
PublicIconBtn.propTypes = {
actionHandler: PropTypes.func,
active: PropTypes.bool,
size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
};
@@ -1,98 +0,0 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
Button,
IconButton,
Tooltip,
} from '@chakra-ui/react';
import { FiPower } from '@react-icons/all-files/fi/FiPower';
import { Size } from '../../models/Util.type';
import { useEmitLog } from '../../stores/logger';
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 } = useEmitLog();
const onClose = () => setIsOpen(false);
const cancelRef = useRef<HTMLButtonElement | null>(null);
useEffect(() => {
if (window.process?.type === 'renderer') {
window.ipcRenderer.on('user-request-shutdown', () => {
emitInfo('Shutdown request');
setIsOpen(true);
});
}
}, [emitInfo]);
const handleShutdown = useCallback(() => {
onClose();
clickHandler();
}, [clickHandler]);
return (
<>
<Tooltip label='Quit Application'>
<IconButton
aria-label='Quit Application'
size={size}
icon={<FiPower />}
onClick={() => setIsOpen(true)}
isDisabled={disabled}
{...quitBtnStyle}
{...rest}
/>
</Tooltip>
<AlertDialog isOpen={isOpen} leastDestructiveRef={cancelRef} onClose={onClose}>
<AlertDialogOverlay>
<AlertDialogContent>
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
Ontime Shutdown
</AlertDialogHeader>
<AlertDialogBody>This will shutdown the program and all running servers. Are you sure?</AlertDialogBody>
<AlertDialogFooter>
<Button ref={cancelRef} onClick={onClose} variant='ghost'>
Cancel
</Button>
<Button colorScheme='red' onClick={handleShutdown} ml={3}>
Shutdown
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
</>
);
}
@@ -1,28 +0,0 @@
import { IconButton, Tooltip } from '@chakra-ui/react';
import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
import PropTypes from 'prop-types';
import { tooltipDelayMid } from '../../../ontimeConfig';
export default function RollIconBtn(props) {
const { clickhandler, active, disabled, ...rest } = props;
return (
<Tooltip label='Roll mode' openDelay={tooltipDelayMid} shouldWrapChildren={disabled}>
<IconButton
icon={<IoTimeOutline size='24px' />}
colorScheme='blue'
variant={active ? 'solid' : 'outline'}
onClick={clickhandler}
width={120}
disabled={disabled}
{...rest}
/>
</Tooltip>
);
}
RollIconBtn.propTypes = {
clickhandler: PropTypes.func,
active: PropTypes.bool,
disabled: PropTypes.bool,
};
@@ -1,28 +0,0 @@
import { IconButton, Tooltip } from '@chakra-ui/react';
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
import PropTypes from 'prop-types';
import { tooltipDelayMid } from '../../../ontimeConfig';
export default function StartIconBtn(props) {
const { clickhandler, active, disabled, ...rest } = props;
return (
<Tooltip label='Start timer' openDelay={tooltipDelayMid} shouldWrapChildren={disabled}>
<IconButton
icon={<IoPlay size='24px' />}
colorScheme='green'
variant={active ? 'solid' : 'outline'}
onClick={clickhandler}
width={120}
disabled={disabled}
{...rest}
/>
</Tooltip>
);
}
StartIconBtn.propTypes = {
clickhandler: PropTypes.func,
active: PropTypes.bool,
disabled: PropTypes.bool
}
@@ -2,7 +2,7 @@ import { MouseEvent } from 'react';
import { IconButton, IconButtonProps, Tooltip } from '@chakra-ui/react';
interface TooltipActionBtnProps extends IconButtonProps {
clickHandler: (event?: MouseEvent) => void | Promise<void>;
clickHandler: (event: MouseEvent) => void | Promise<void>;
tooltip: string;
openDelay?: number;
}
@@ -1,29 +0,0 @@
import { IconButton, Tooltip } from '@chakra-ui/react';
import PropTypes from 'prop-types';
import { tooltipDelayMid } from '../../../ontimeConfig';
export default function TransportIconBtn(props) {
const { clickHandler, icon, tooltip, disabled, ...rest } = props;
return (
<Tooltip label={tooltip} openDelay={tooltipDelayMid} shouldWrapChildren={disabled}>
<IconButton
icon={icon}
colorScheme='white'
variant='outline'
_hover={!disabled && { bg: '#ebedf0', color: '#333' }}
onClick={clickHandler}
width={90}
disabled={disabled}
{...rest}
/>
</Tooltip>
);
}
TransportIconBtn.propTypes = {
clickHandler: PropTypes.func,
icon: PropTypes.element,
tooltip: PropTypes.string,
disabled: PropTypes.bool,
};
@@ -1,27 +0,0 @@
import { IconButton, Tooltip } from '@chakra-ui/react';
import { IoStop } from '@react-icons/all-files/io5/IoStop';
import PropTypes from 'prop-types';
import { tooltipDelayMid } from '../../../ontimeConfig';
export default function UnloadIconBtn(props) {
const { clickHandler, disabled, ...rest } = props;
return (
<Tooltip label='Unload event' openDelay={tooltipDelayMid} shouldWrapChildren={disabled}>
<IconButton
icon={<IoStop size='22px' />}
colorScheme='red'
variant='outline'
onClick={clickHandler}
width={90}
disabled={disabled}
{...rest}
/>
</Tooltip>
);
}
UnloadIconBtn.propTypes = {
clickHandler: PropTypes.func,
disabled: PropTypes.bool,
};
@@ -0,0 +1,24 @@
.textEntry {
grid-area: input;
display: flex;
align-items: center;
gap: 0.5rem;
color: $label-gray;
}
.inlineEntry {
display: grid;
grid-template-areas:
'label label'
'input btn';
grid-template-columns: 1fr auto;
column-gap: 0.5rem;
}
.redirect {
grid-area: btn;
}
.label {
color: $label-gray;
}
@@ -0,0 +1,126 @@
import { useState } from 'react';
import {
IconButton,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
Select,
} from '@chakra-ui/react';
import { IoArrowForward } from '@react-icons/all-files/io5/IoArrowForward';
import { navigatorConstants } from '../../../viewerConfig';
import { setClientRemote } from '../../hooks/useSocket';
import useUrlPresets from '../../hooks-query/useUrlPresets';
import Info from '../info/Info';
import AppLink from '../link/app-link/AppLink';
import style from './RedirectClientModal.module.scss';
interface RedirectClientModalProps {
id: string;
name: string;
currentPath: string;
origin: string;
isOpen: boolean;
onClose: () => void;
}
export function RedirectClientModal(props: RedirectClientModalProps) {
const { id, isOpen, name, currentPath, origin, onClose } = props;
const { data } = useUrlPresets();
const [path, setPath] = useState(currentPath);
const [selected, setSelected] = useState('/');
const { setRedirect } = setClientRemote;
const handleRedirect = (newPath: string) => {
if (newPath === '/' || newPath === currentPath) {
return;
}
setRedirect({ target: id, redirect: newPath });
onClose();
};
const enabledPresets = data.filter((preset) => preset.enabled);
return (
<Modal isOpen={isOpen} onClose={onClose} variant='ontime'>
<ModalOverlay />
<ModalContent maxWidth='max(480px, 35vw)'>
<ModalHeader>Redirect: {name}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Info>
Remotely redirect the client to a different URL. <br />
Either by selecting a URL Preset or entering a custom path.
<br />
<br />
<AppLink search='settings=feature_settings__urlpresets'>Manage URL Presets</AppLink>
</Info>
<div>
<span className={style.label}>Select View or URL Preset</span>
<div className={style.textEntry}>
<Select
size='md'
variant='ontime'
isDisabled={enabledPresets.length === 0}
onChange={(event) => setSelected(event.target.value)}
>
<option value='/'>Select view or preset</option>
{navigatorConstants.map((view) => {
return (
<option key={view.url} value={`/${view.url}`}>
{view.label}
</option>
);
})}
{enabledPresets.map((preset) => {
return (
<option key={preset.pathAndParams} value={preset.pathAndParams}>
{`Preset: ${preset.alias}`}
</option>
);
})}
</Select>
<IconButton
variant='ontime-filled'
size='md'
aria-label='Redirect to preset'
className={style.redirect}
icon={<IoArrowForward />}
isDisabled={enabledPresets.length === 0 || selected === '/'}
onClick={() => handleRedirect(selected)}
/>
</div>
</div>
<div className={style.inlineEntry}>
<span className={style.label}>Enter custom path</span>
<label className={style.textEntry}>
{origin}
<Input
variant='ontime-filled'
size='md'
placeholder='eg. /minimal?key=0000ffff'
value={path}
onChange={(event) => setPath(event.target.value)}
/>
</label>
<IconButton
variant='ontime-filled'
size='md'
aria-label='Redirect'
isDisabled={path === currentPath || path === ''}
className={style.redirect}
icon={<IoArrowForward />}
onClick={() => handleRedirect(path)}
/>
</div>
</ModalBody>
</ModalContent>
</Modal>
);
}
@@ -0,0 +1,64 @@
import { useState } from 'react';
import {
Button,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
} from '@chakra-ui/react';
import { setClientRemote } from '../../hooks/useSocket';
interface RenameClientModalProps {
id: string;
name?: string;
isOpen: boolean;
onClose: () => void;
}
export function RenameClientModal(props: RenameClientModalProps) {
const { id, name: currentName = '', isOpen, onClose } = props;
const [name, setName] = useState(currentName);
const { setClientName } = setClientRemote;
const handleRename = () => {
if (name !== currentName && name !== '') {
setClientName({ target: id, rename: name });
}
onClose();
};
const canSubmit = name !== currentName && name !== '';
return (
<Modal isOpen={isOpen} onClose={onClose} variant='ontime'>
<ModalOverlay />
<ModalContent>
<ModalHeader>Rename: {currentName}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Input
variant='ontime-filled'
size='md'
placeholder='new name'
value={name}
onChange={(event) => setName(event.target.value)}
/>
</ModalBody>
<ModalFooter>
<Button size='md' variant='ontime-subtle' onClick={onClose}>
Cancel
</Button>
<Button size='md' variant='ontime-filled' onClick={handleRename} isDisabled={!canSubmit}>
Submit
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
@@ -1,24 +0,0 @@
@use '../../../theme/v2Styles' as *;
.header {
font-size: $inner-section-text-size;
font-weight: 600;
display: flex;
justify-content: space-between;
color: $section-white;
margin-top: $main-spacing;
border-bottom: 1px solid $border-color-ondark;
padding-bottom: $element-inner-spacing;
margin-bottom: $element-spacing;
cursor: pointer;
}
.moreExpanded {
transform: scaleY(-1);
transition: transform $transition-time-feedback;
}
.moreCollapsed {
transform: scaleY(1);
transition: transform $transition-time-feedback;
}
@@ -1,20 +0,0 @@
import { FiChevronUp } from '@react-icons/all-files/fi/FiChevronUp';
import style from './CollapseBar.module.scss';
interface CollapseBarProps {
title: string;
isCollapsed: boolean;
onClick: () => void;
}
export default function CollapseBar(props: CollapseBarProps) {
const { title = 'Collapse bar', isCollapsed, onClick } = props;
return (
<div className={style.header} onClick={onClick}>
{title}
<FiChevronUp className={isCollapsed ? style.moreCollapsed : style.moreExpanded} />
</div>
);
}
@@ -1,6 +1,5 @@
.contextMenuButton {
position: absolute;
cursor: pointer;
}
.contextMenuBackdrop {
@@ -0,0 +1,99 @@
// logic (with some modifications) culled from:
// https://github.com/lukasbach/chakra-ui-contextmenu/blob/main/src/ContextMenu.tsx
import { ReactElement } from 'react';
import { Menu, MenuButton, MenuGroup, MenuList } from '@chakra-ui/react';
import { IconType } from '@react-icons/all-files';
import { create } from 'zustand';
import { ContextMenuOption } from './ContextMenuOption';
import style from './ContextMenu.module.scss';
type ContextMenuCoords = {
x: number;
y: number;
};
export type OptionWithoutGroup = {
label: string;
isDisabled?: boolean;
icon: IconType;
onClick: () => void;
withDivider?: boolean;
};
export type OptionWithGroup = {
label: string;
group: Omit<OptionWithoutGroup, 'isGroup'>[];
};
export type Option = OptionWithoutGroup | OptionWithGroup;
const isOptionWithGroup = (option: Option): option is OptionWithGroup => 'group' in option;
type ContextMenuStore = {
coords: ContextMenuCoords;
options: Option[];
isOpen: boolean;
setContextMenu: (coords: ContextMenuCoords, options: Option[]) => void;
setIsOpen: (newIsOpen: boolean) => void;
};
export const useContextMenuStore = create<ContextMenuStore>((set) => ({
coords: { x: 0, y: 0 },
options: [],
isOpen: false,
setContextMenu: (coords, options) => set(() => ({ coords, options, isOpen: true })),
setIsOpen: (newIsOpen) => set(() => ({ isOpen: newIsOpen })),
}));
interface ContextMenuProps {
// ReactElement type required due to early `return` (line 51) returning {children}
children: ReactElement;
}
export const ContextMenu = ({ children }: ContextMenuProps) => {
const { coords, options, isOpen, setIsOpen } = useContextMenuStore();
const onClose = () => {
return setIsOpen(false);
};
if (!isOpen) {
return children;
}
return (
<>
{children}
<div className={style.contextMenuBackdrop} />
<Menu isOpen size='sm' gutter={0} onClose={onClose} isLazy lazyBehavior='unmount' variant='ontime-on-dark'>
<MenuButton
className={style.contextMenuButton}
aria-hidden
w={1}
h={1}
style={{
position: 'fixed',
left: coords.x,
top: coords.y,
}}
/>
<MenuList>
{options.map((option) =>
isOptionWithGroup(option) ? (
<MenuGroup key={option.label} title={option.label}>
{option.group.map((groupOption) => (
<ContextMenuOption key={groupOption.label} {...groupOption} />
))}
</MenuGroup>
) : (
<ContextMenuOption key={option.label} {...option} />
),
)}
</MenuList>
</Menu>
</>
);
};
@@ -0,0 +1,12 @@
import { MenuDivider, MenuItem } from '@chakra-ui/react';
import { OptionWithoutGroup } from './ContextMenu';
export const ContextMenuOption = ({ label, onClick, isDisabled, icon: Icon, withDivider }: OptionWithoutGroup) => (
<>
{withDivider && <MenuDivider />}
<MenuItem icon={<Icon style={{ fontSize: '1rem' }} />} onClick={onClick} isDisabled={isDisabled}>
{label}
</MenuItem>
</>
);
@@ -1,5 +1,6 @@
import { PropsWithChildren } from 'react';
import { PropsWithChildren, useState } from 'react';
import { Button, ButtonGroup, IconButton, Tooltip } from '@chakra-ui/react';
import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark';
import { IoCopy } from '@react-icons/all-files/io5/IoCopy';
import { tooltipDelayFast } from '../../../ontimeConfig';
@@ -7,23 +8,39 @@ import { Size } from '../../models/Util.type';
import copyToClipboard from '../../utils/copyToClipboard';
interface CopyTagProps {
copyValue: string;
label: string;
className?: string;
size?: Size;
disabled?: boolean;
onClick?: () => void;
}
export default function CopyTag(props: PropsWithChildren<CopyTagProps>) {
const { label, className, size = 'xs', children } = props;
const { copyValue, label, size = 'xs', disabled, children, onClick } = props;
const [copied, setCopied] = useState(false);
const handleClick = () => copyToClipboard(children as string);
const handleClick = () => {
copyToClipboard(copyValue);
setCopied(true);
// reset copied state
setTimeout(() => setCopied(false), 1000);
};
return (
<Tooltip label={label} openDelay={tooltipDelayFast}>
<ButtonGroup size={size} isAttached className={className}>
<Button variant='ontime-subtle' tabIndex={-1}>
<ButtonGroup size={size} isAttached>
<Button variant='ontime-subtle' tabIndex={-1} onClick={onClick} isDisabled={disabled}>
{children}
</Button>
<IconButton aria-label={label} icon={<IoCopy />} variant='ontime-filled' tabIndex={-1} onClick={handleClick} />
<IconButton
aria-label={label}
icon={copied ? <IoCheckmark /> : <IoCopy />}
variant='ontime-filled'
tabIndex={-1}
onClick={handleClick}
isDisabled={disabled}
/>
</ButtonGroup>
</Tooltip>
);
@@ -0,0 +1,7 @@
.delaySymbol {
svg {
font-size: 1.5rem;
color: $ontime-delay;
margin: 0 auto;
}
}
@@ -0,0 +1,31 @@
import { Tooltip } from '@chakra-ui/react';
import { IoChevronDown } from '@react-icons/all-files/io5/IoChevronDown';
import { IoChevronUp } from '@react-icons/all-files/io5/IoChevronUp';
import { tooltipDelayFast } from '../../../ontimeConfig';
import { millisToDelayString } from '../../utils/dateConfig';
import style from './DelayIndicator.module.scss';
interface DelayIndicatorProps {
delayValue?: number;
tooltipPrefix?: string;
}
export default function DelayIndicator(props: DelayIndicatorProps) {
const { delayValue, tooltipPrefix } = props;
if (typeof delayValue !== 'number' || delayValue === 0) {
return null;
}
const delayString = tooltipPrefix
? `${tooltipPrefix} ${millisToDelayString(delayValue)}`
: millisToDelayString(delayValue);
return (
<Tooltip openDelay={tooltipDelayFast} label={delayString}>
<span className={style.delaySymbol}>{delayValue < 0 ? <IoChevronDown /> : <IoChevronUp />}</span>
</Tooltip>
);
}
@@ -3,6 +3,9 @@ import React from 'react';
// skipcq: JS-C1003 - sentry does not expose itself as an ES Module.
import * as Sentry from '@sentry/react';
import { runtimeStore } from '@/common/stores/runtime';
import { hasConnected, reconnectAttempts, shouldReconnect } from '@/common/utils/socket';
import style from './ErrorBoundary.module.scss';
class ErrorBoundary extends React.Component {
@@ -20,12 +23,16 @@ class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
this.setState({
error: error,
error,
errorInfo: info,
});
Sentry.withScope((scope) => {
scope.setExtras(error);
scope.setExtras({
error,
store: runtimeStore.getState(),
hasSocket: { hasConnected, shouldReconnect, reconnectAttempts },
});
const eventId = Sentry.captureException(error);
this.setState({ eventId, info });
});
@@ -1,5 +1,3 @@
@use '../../../theme/v2Styles' as *;
.errorContainer {
width: 100%;
height: 100%;
@@ -0,0 +1,63 @@
/**
* Copied from
* https://github.com/namhong2001/react-textfit/blob/master/index.tsx
*/
import { HTMLAttributes, PropsWithChildren, useCallback, useEffect, useRef } from 'react';
import { bsearch } from './fitText.utils';
interface FitTextProps extends HTMLAttributes<HTMLDivElement> {
mode?: 'single' | 'multi';
min?: number; // inclusive
max?: number; // inclusive
}
export function FitText(props: PropsWithChildren<FitTextProps>) {
const { children, mode = 'multi', min = 16, max = 256, ...elementProps } = props;
const ref = useRef<HTMLDivElement>(null);
const isOverflown = useCallback(() => {
const el = ref.current;
if (!el) return false;
return el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;
}, []);
const setFontSize = useCallback(() => {
const el = ref.current;
if (!el) return;
const originVisibility = el.style.visibility;
el.style.visibility = 'hidden';
const fontSize = bsearch(min, max + 1, (mid) => {
el.style.fontSize = `${mid}px`;
return !isOverflown();
});
el.style.fontSize = `${fontSize}px`;
el.style.visibility = originVisibility;
}, [isOverflown, min, max]);
useEffect(() => {
const el = ref.current;
if (!el) return;
setFontSize();
const observer = new ResizeObserver(setFontSize);
observer.observe(el);
return () => observer.disconnect();
}, [children, mode, setFontSize]);
return (
<div
ref={ref}
style={{
whiteSpace: mode === 'single' ? 'nowrap' : 'normal',
}}
{...elementProps}
>
{children}
</div>
);
}
@@ -0,0 +1,18 @@
/**
* @param low inclusive, must be true on predicate function
* @param high exclusive,
* @param predicate predicate function
*/
export const bsearch = (low: number, high: number, predicate: (mid: number) => boolean): number => {
while (low < high) {
const mid = Math.floor((low + high) / 2);
if (mid === low) break;
if (predicate(mid)) {
low = mid;
} else {
high = mid;
}
}
return low;
};
@@ -0,0 +1,34 @@
.overlay {
position: absolute;
top: 0;
left: 0;
margin: 0;
width: 100vw;
height: 100vh;
padding: 0;
box-sizing: border-box;
border: 10px solid $ui-white;
background-color: $ui-black;
color: $ui-white;
display: grid;
place-content: center;
text-align: center;
z-index: 100;
cursor: pointer;
}
.name {
font-weight: 600;
margin-top: -10vh;
line-height: 1em;
font-size: 12vw;
text-transform: uppercase;
}
.message {
color: $label-gray;
line-height: 2em;
font-size: 3vw;
}
@@ -0,0 +1,63 @@
import { useCallback, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import { MILLIS_PER_MINUTE } from 'ontime-utils';
import { setClientRemote } from '../../hooks/useSocket';
import { useClientStore } from '../../stores/clientStore';
import style from './IdentifyOverlay.module.scss';
export default function IdentifyOverlay() {
const clients = useClientStore((store) => store.clients);
const id = useClientStore((store) => store.id);
const showOverlay = clients[id]?.identify;
if (!showOverlay) {
return null;
}
const portalRoot = document.getElementById('identify-portal');
if (!portalRoot) {
return null;
}
return createPortal(<Overlay />, portalRoot);
}
function Overlay() {
const clients = useClientStore((store) => store.clients);
const id = useClientStore((store) => store.id);
const name = useClientStore((store) => store.name);
const timerRef = useRef<NodeJS.Timeout | null>(null);
const { setIdentify } = setClientRemote;
const showOverlay = clients[id]?.identify;
const handleClose = useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
setIdentify({ target: id, identify: false });
}, [id, setIdentify]);
// start a timer that will close the overlay after some time
useEffect(() => {
if (showOverlay) {
timerRef.current = setTimeout(handleClose, MILLIS_PER_MINUTE);
}
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [showOverlay, id, setIdentify, handleClose]);
return (
<div className={style.overlay} data-testid='identify-overlay' onClick={handleClose}>
<div className={style.name}>{name}</div>
<div className={style.message}>Click to close</div>
</div>
);
}

Some files were not shown because too many files have changed in this diff Show More