V2 monorepo (#285)

* refactor(project structure): UI

* refactor(project structure): extract utilities

* refactor(project structure): remove unused

* refactor(project structure): electron

* refactor(project structure): server

refactor: migrate to vitest

refactor: monorepo config

* refactor: extract application menu

* refactor: exit process

* refactor: extract tray menu

* chore: electron build

* Added Seconds in studio clock #282
---------

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

---------

Co-authored-by: Fabian Posenau <fabian.p99@gmx.de>
Co-authored-by: Fabian Posenau <fabian@fphome.de>
This commit is contained in:
Carlos Valente
2023-02-14 22:02:15 +01:00
committed by GitHub
parent 3918758d32
commit de9a7a87fd
439 changed files with 11381 additions and 14294 deletions
-1
View File
@@ -3,7 +3,6 @@ version = 1
test_patterns = [
"__mocks__/**",
"__tests__/**",
"cypress/**",
"*.test.*",
"*.mock.*",
"*.spec.*"
+7 -22
View File
@@ -9,26 +9,11 @@
"extends": [
"eslint:recommended"
],
"rules": {
// disallow certain object properties
// https://eslint.org/docs/rules/no-restricted-properties
"no-restricted-properties": [
"error",
{
"object": "global",
"property": "isNaN",
"message": "Please use Number.isNaN instead"
},
{
"object": "self",
"property": "isNaN",
"message": "Please use Number.isNaN instead"
},
{
"object": "window",
"property": "isNaN",
"message": "Please use Number.isNaN instead"
}
]
}
"overrides": [
{
"files": ["e2e/**/**.spec.ts", "e2e/**/**.test.ts"],
"extends": ["plugin:playwright/playwright-test"]
}
],
"rules": {}
}

Before

Width:  |  Height:  |  Size: 285 KiB

After

Width:  |  Height:  |  Size: 285 KiB

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 250 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

+25 -72
View File
@@ -21,34 +21,19 @@ jobs:
with:
node-version: 16
# React
- name: React - Install dependencies
run: yarn install --frozen-lockfile --network-timeout 300000
working-directory: ./client
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: React - Build project
run: yarn build
working-directory: ./client
- name: Build project packages
run: turbo build
# Node server
- name: Server - Install dependencies
run: yarn install --frozen-lockfile --production --network-timeout 300000
working-directory: ./server/src
# App
- name: Electron - Install dependencies
shell: bash
run: yarn install --frozen-lockfile --network-timeout 300000 && yarn setdb
working-directory: ./server
- name: Electron - Build app
run: yarn dist-mac
working-directory: ./server
run: turbo dist-mac
# Release
- name: Release
uses: softprops/action-gh-release@v1
with:
files: ./server/dist/ontime-macOS.dmg
files: ./electron/dist/ontime-macOS.dmg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -65,34 +50,20 @@ jobs:
with:
node-version: 16
# React
- name: React - Install dependencies
run: yarn install --frozen-lockfile --network-timeout 300000
working-directory: ./client
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: React - Build project
run: yarn build
working-directory: ./client
- name: Build project packages
run: turbo build
# Node server
- name: Server - Install dependencies
run: yarn install --frozen-lockfile --production --network-timeout 300000
working-directory: ./server/src
# App
- name: Electron - Install dependencies
shell: bash
run: yarn install --frozen-lockfile --network-timeout 300000 && yarn setdb
working-directory: ./server
- name: Electron - Build app
run: yarn dist-win
working-directory: ./server
run: turbo dist-win
# Release
- name: Release
uses: softprops/action-gh-release@v1
with:
files: ./server/dist/ontime-win64.exe
files: ./electron/dist/ontime-win64.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -109,34 +80,20 @@ jobs:
with:
node-version: 16
# React
- name: React - Install dependencies
run: yarn install --frozen-lockfile --network-timeout 300000
working-directory: ./client
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: React - Build project
run: yarn build
working-directory: ./client
- name: Build project packages
run: turbo build
# Node server
- name: Server - Install dependencies
run: yarn install --frozen-lockfile --production --network-timeout 300000
working-directory: ./server/src
# App
- name: Electron - Install dependencies
shell: bash
run: yarn install --frozen-lockfile --network-timeout 300000 && yarn setdb
working-directory: ./server
- name: Electron - Build app
run: yarn dist-linux
working-directory: ./server
run: turbo dist-linux
# Release
- name: Release
uses: softprops/action-gh-release@v1
with:
files: ./server/dist/ontime-linux.AppImage
files: ./electron/dist/ontime-linux.AppImage
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -145,6 +102,7 @@ jobs:
timeout-minutes: 20
env:
CI: ''
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
steps:
- uses: actions/checkout@v3
@@ -155,19 +113,14 @@ jobs:
with:
node-version: 16
# React
- name: React - Install dependencies
run: yarn install --network-timeout 300000
working-directory: ./client
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: React - Build project
run: yarn build
working-directory: ./client
- name: Build project packages
run: turbo build
# Node server
- name: Server - Install dependencies
run: yarn install --frozen-lockfile --production --network-timeout 300000
working-directory: ./server/src
- name: Electron - Build app
run: turbo dist-mac
# Login to docker
- name: Login to Docker Hub
-70
View File
@@ -1,70 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '33 02 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
+27 -23
View File
@@ -5,38 +5,42 @@ node_modules/
/.pnp
.pnp.js
# testing
coverage/
*.mp4
# production
build/
dist/
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
*.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# working stuff
_SS/
db backup.json
server/src/preloaded-db/db.json
server/src/models/db.json
TODO.md
ontime-db/
ontime-external/
# vscode stuff
.vscode/*
ontime.code-workspace
# webstorm stuff
.idea/*
.idea/*
# turborepo stuff
.turbo
# testing
test-results
playwright-report
/playwright/.cache/
# production
build/
dist/
# working stuff
**/TODO.md
# docker utils
ontime-db
ontime-external/
# working database
apps/server/src/preloaded-db/db.json
# versioning file
**/ONTIME_VERSION.js
+3 -3
View File
@@ -1,8 +1,8 @@
{
"trailingComma": "es5",
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"printWidth": 100
}
"printWidth": 120
}
+47
View File
@@ -0,0 +1,47 @@
# GETTING STARTED
Ontime consists of 3 distinct parts
- __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.
Other dependencies will be installed as part of the setup
- __node__ (>=16.16)
- __pnpm__ (>=7)
- __docker__ (only necessary to run and build docker images)
## LOCAL DEVELOPMENT
The electron app is only necessary to distribute an installable version of the app and is not required for local development.
Locally, we would need to run both the React client and the node.js server in development mode
From the project root, run the following commands
- __Install the project dependencies__ by running `pnpm i`
- __Run dev mode__ by running `turbo dev`
## CREATE AN INSTALLABLE FILE (Windows | MacOS | Linux)
Ontime uses Electron to distribute the application.
You can generate a distribution for your OS by running the following steps.
From the project root, run the following commands
- __Install the project dependencies__ by running `pnpm i`
- __Build the UI and server__ by running `turbo build`
- __Create the package__ by running `turbo dist-win`, `turbo dist-mac` or `turbo dist-linux`
The build distribution assets will be at `.apps/electron/dist`
## DOCKER
Ontime provides a docker-compose file to aid with building and running docker images.
While it should allow for a generic setup, it might need to be modified to fit your infrastructure.
From the project root, run the following commands
- __Install the project dependencies__ by running `pnpm i`
- __Build docker image from__ by running `docker build -t getontime/ontime`
- __Run docker image from compose__ by running `docker-compose up -d`
Other useful commands
- __List running processes__ by running `docker ps`
- __Kill running process__ by running `docker kill <process-id>`
+7 -6
View File
@@ -1,20 +1,21 @@
FROM node:14-alpine
FROM node:16-alpine
WORKDIR /app/server
WORKDIR /apps/server
# Prepare UI
COPY /client/build ../client/build
COPY /apps/client/build ../client/build
# Prepare Backend
COPY /server/src ./
COPY /apps/server ./
# Export default ports Main - OSC IN
EXPOSE 4001/tcp 8888/udp
ENV NODE_ENV=production
ENV ONTIME_DATA=/server/
CMD ["yarn", "start:headless"]
CMD ["npm", "start:headless"]
# Build an run commandsN
# Build and run commands
# !!! Note that this command needs pre-build versions of the UI and server apps
# docker build -t getontime/ontime .
# docker run -p 4001:4001 -p 10.0.0.12:8888:8888/udp --mount type=bind,source="$(pwd)/ontime-db",target=/server/preloaded-db getontime/ontime
+66 -71
View File
@@ -14,120 +14,114 @@
Ontime is an application for managing event rundowns and running stage timers.
It allows a center application to be able to distribute event information in the local network. This
minimises needs for using Media Server outputs or expensive video distribution while allowing easy
integration in workflows including OBS and d3.
A single, locally hosted central application distributes your event information over the local network.
This enables the distribution of the data to a series of viewers and allows integration into video and control workflows, including OBS and d3.
![App Window](https://github.com/cpvalente/ontime/blob/master/.github/app.jpg)
![App Window](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/app.jpg)
![Views](https://github.com/cpvalente/ontime/blob/master/.github/02_screentypes.png)
![Views](https://github.com/cpvalente/ontime/blob/master/.github/aux-images/02_screentypes.png)
## Using Ontime
Once installed and running, ontime starts a background server that is the heart of all processes.
The app, is used to add / edit your running order in the event list, and running the timers using
the Playback Control function.
Once installed and running, Ontime starts a background server that is the heart of all processes.
From the app, you can add / edit your running order and control the timer playback.
From here, any device in the same network with a browser is able to render the views as described.
Any device with a browser in the same network can choose one of the supported views to render the available data.
This is done by reaching the ontime server at the _default port 4001_ eg: `localhost:4001`
or `192.168.1.3:4001`
You can then use the ontime logo in the top right corner to select the desired view (event in the
lower thirds view, where it is hidden).
<br />
You can then use the Ontime logo in the top left corner to select the desired view.
The logo will be initially hidden until there is mouse interaction.
In case of unattended machines or automations, it is possible to use different URL to recall
individual views and extend with using the URL aliases feature
In the case of unattended machines or automation, it is possible to use different URL to recall
individual views and extend view settings using the URL aliases feature
```
For the presentation views...
For the presentation views
-------------------------------------------------------------
IP.ADDRESS:4001 > Web server default to presenter timer view
IP.ADDRESS:4001/timer > Presenter / Stage timer view
IP.ADDRESS:4001/minimal > Simple timer view
IP.ADDRESS:4001/clock > Simple clock view
IP.ADDRESS:4001/sm > Stage Manager / Backstage view
IP.ADDRESS:4001/public > Public / Foyer view
IP.ADDRESS:4001/pip > Picture in Picture view
IP.ADDRESS:4001/lower > Lower Thirds
IP.ADDRESS:4001/studio > Studio Clock
IP.ADDRESS:4001/cuesheet > Cue Sheet
...and for the editor (the control interface, same as the app)
```
```
For management views
-------------------------------------------------------------
IP.ADDRESS:4001/editor
IP.ADDRESS:4001/editor > the control interface, same as the app
IP.ADDRESS:4001/cuesheet > realtime cuesheets for collaboration
```
More documentation available [here](https://cpvalente.gitbook.io/ontime/)
More documentation is available [in our docs](https://cpvalente.gitbook.io/ontime/)
## Feature List (in no specific order)
- [x] Distribute Data over network and render in the browser
- [x] Distribute data over network and render it in the browser
- [x] Different screen types
- Stage Timer
- Backstage Info
- Public Info
- Picture in Picture
- Studio Clock
- [Make your own?](#make-your-own-viewer)
- [x] Configurable realtime Lower Thirds
- [x] Cuesheets with additional custom fields
- [x] Configurable Lower Thirds
- [x] Cuesheets with user definable fields
- [x] Send live messages to different screen types
- [x] Ability to differentiate between backstage and public data
- [x] Manage delays workflow
- [x] Open Sound Control (OSC) Control and Feedback
- [x] Integrate with hardware using Companion or one of the APIs
- [x] Differentiate between backstage and public data
- [x] Workflow for managing delays
- [x] Protocol integrations for Control and Feedback
- OSC (Open Sound Control)
- HTTP
- WebSockets
- [x] Roll mode: run independently using the system clock
- [x] Import event list from Excel
- [x] URL Aliases (define configurable aliases to ease onsite setup)
- [x] Logging view
- [x] Edit anywhere: run ontime in your local network and use any machine to reach the editor page (
same as app)
- [x] Multi platform (available on Windows, MacOS and Linux)
- [x] [Headless run](#headless-run) (run server only, configure from a browser locally)
- [x] [Countdown to anything!](https://cpvalente.gitbook.io/ontime/views/countdown): ability to have
- [x] [Headless run](#headless-run): run server in a separate machine, configure from a browser locally
- [x] [Countdown to anything!](https://cpvalente.gitbook.io/ontime/views/countdown): have
a countdown to any scheduled event
- [x] Multi-platform (available on Windows, MacOS and Linux)
- [x] [Companion integration](https://bitfocus.io/connections/getontime-ontime)
## Unopinionated
We are not interested in forcing workflows and have made ontime, so it is flexible to whichever way
We are not interested in forcing workflows and have made Ontime, so it is flexible to whichever way
you would like to work.
- [x] You do not need an order list to use the timer. Create an empty event and the OSC API works
just the same
- [x] If you want just the info screens, no need to use the timer!
- [x] If you want just the info screens, there is no need to use the timer!
- [x] Don't have or care for a schedule?
- [x] a single event with no data is enough to use the OSC API and get going
- [x] a single event with no data is enough to use one of the APIs and use a dynamic timer
- [x] use the order list to create a set of quick timers by setting the beginning and start
times to 00:00 and 00:10 (**BAM**! 10 minute timer). You can quickly recall this with OSC as
always
times to 00:00 and 00:10 (**BAM**! 10 minute timer). You can quickly recall this with OSC or any of the other available integrations
## Rich APIs for workflow integrations
The app is being currently developed to a wide user base, from broadcast to entertainment and
The app is currently being developed for a broad user base, from broadcast to entertainment and
conference halls.
Taking advantage of the integrations in Ontime, we currently use Ontime with:
Taking advantage of the integrations, we currently use Ontime with:
- `disguise`: trigger ontime from d3's timeline using the **OSC API**, **render views** using d3's
- `disguise`: trigger Ontime from d3's timeline using the **OSC API**, and **render views** using d3's
webmodule
- `OBS`: **render views** using the Browser Module
- `QLab`: trigger ontime using **OSC API**
- `QLab`: trigger Ontime using **OSC API**
- `Companion`: Ontime has a **companion module**. Issue report and feature requests should be done
in
the [repository getontime/ontime](https://github.com/bitfocus/companion-module-getontime-ontime)
in the [repository getontime/ontime](https://github.com/bitfocus/companion-module-getontime-ontime)
### Make your own viewer
Ontime broadcasts its data over websockets. This allows you to build your own viewers by leveranging
basic knowledge of HTML + CSS + Javascript (or any other language that can run in the browser).
Ontime broadcasts its data over WebSockets. This allows you to consume its data outside of 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) with a small template on
how to get you started and read the docs about
the [Websocket API](https://app.gitbook.com/s/-Mc0giSOToAhq0ROd0CR/control-and-feedback/websocket-api)
### Headless run
You can self host and run ontime in a docker image, the run command should:
You can self-host and run Ontime in a docker image. The run command will:
- expose the necessary ports (listen in Dockerfile)
- expose the necessary ports (listed in the Dockerfile)
- mount a local file to persist your data (in the example: ````$(pwd)/local-data````)
- the image name __getontime/ontime__
@@ -154,19 +148,14 @@ docker-compose up
### Continued development
There are several features planned in the roadmap. These will be implemented in a development
friendly order unless there is user demand to bump any of them.
- [ ] HTTP Server (vMix integration)
- [ ] Improvements in event interface
- [ ] Moderator view
- [ ] New playback mode for [cumulative time keeping](https://github.com/cpvalente/ontime/issues/100)
- [ ] Lower Third Manager
- [ ] Reach Schedule: way to speedup timer to meet a deadline
Several features are planned in the roadmap, and we continuously adjust this to match how users interact with the app.
<br />
Have an idea? Reach out via [email](mail@getontime.no) or [open an issue](https://github.com/cpvalente/ontime/issues/new)
### Issues
If you come across any bugs, [please open an issue]((https://github.com/cpvalente/ontime/issues/new)). Usually bugs get fixed pretty quickly when reported
We use Github's issue tracking for bug reporting and feature requests. <br />
Found a bug? [Open an issue](https://github.com/cpvalente/ontime/issues/new).
#### Unsigned App
@@ -192,22 +181,28 @@ You can circumvent this by allowing the execution of the app manually.
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,
please [open an issue, so we can discuss it](https://github.com/cpvalente/ontime/issues/new)
have tips on how to improve this or would like to sponsor the code signing,
please [open an issue](https://github.com/cpvalente/ontime/issues/new)
#### Safari
There are some issues with Safari versions lower than 13:
There are known issues with Safari versions lower than 13:
- Spacing and text styles might have small inconsistencies
- Table view does not work
There is no plan for any further work on this since the breaking code belongs to third party
libraries.
There is no plan for any further work on this.
# Contributing
Looking to contribute? All types of help are appreciated, from coding to testing and feature specification.
<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 />
Information about the project setup can be found in the [development documentation](./DEVELOPMENT.md)
# Help
Help is underway! ... and can be viewed [here](https://cpvalente.gitbook.io/ontime/)
Help is underway! ... and can be found [here](https://cpvalente.gitbook.io/ontime/)
# License
+12 -2
View File
@@ -8,21 +8,31 @@
"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"
"plugin:@tanstack/eslint-plugin-query/recommended",
"prettier"
],
"plugins": [
"react",
"testing-library",
"simple-import-sort",
"@tanstack/query"
"@tanstack/query",
"@typescript-eslint",
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
],
"no-useless-concat": "warn",
"prefer-template": "warn",
"react/jsx-no-bind": [
+8
View File
@@ -0,0 +1,8 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"printWidth": 120
}
@@ -1,6 +1,6 @@
{
"name": "ontime-ui",
"version": "1.9.7",
"version": "2.0.0-alpha",
"private": true,
"dependencies": {
"@chakra-ui/react": "^2.4.5",
@@ -21,6 +21,7 @@
"framer-motion": "^8.0.2",
"jotai": "^1.10.0",
"luxon": "^3.1.0",
"ontime-utils": "workspace:*",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "^18.2.0",
@@ -30,15 +31,18 @@
"react-table": "^7.7.0",
"socket.io-client": "^4.5.4",
"typeface-open-sans": "^1.1.13",
"web-vitals": "^2.1.4"
"web-vitals": "^3.1.1"
},
"scripts": {
"start": "set BROWSER=none&&vite",
"addversion": "node -p \"'export const ONTIME_VERSION = ' + JSON.stringify(require('../../package.json').version) + ';'\" > src/ONTIME_VERSION.js",
"postinstall": "pnpm addversion",
"dev": "set BROWSER=none&&vite",
"build": "vite build",
"lint": "eslint .",
"stylelint": "npx stylelint \"**/*.scss\"\n",
"test": "vitest",
"test:pipeline": "vitest run"
"test:pipeline": "vitest run",
"cleanup": "rm -rf .turbo && rm -rf node_modules && rm -rf build"
},
"browserslist": {
"production": [
@@ -55,38 +59,36 @@
"devDependencies": {
"@sentry/vite-plugin": "^0.3.0",
"@tanstack/eslint-plugin-query": "^4.15.1",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.1.1",
"@testing-library/user-event": "^14.1.1",
"@types/color": "^3.0.3",
"@types/node": "^18.11.18",
"@types/prop-types": "^15.7.5",
"@types/react": "^18.0.26",
"@types/react-beautiful-dnd": "^13.1.3",
"@types/react-dom": "^18.0.10",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"@vitejs/plugin-react": "^3.0.0",
"eslint": "^8.25.0",
"eslint-config-prettier": "^8.5.0",
"@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-react": "^7.31.11",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-simple-import-sort": "^8.0.0",
"eslint-plugin-testing-library": "^5.9.1",
"jsdom": "^20.0.3",
"prettier": "^2.8.1",
"jsdom": "^21.1.0",
"prettier": "^2.8.3",
"prop-types": "^15.8.1",
"sass": "^1.57.1",
"stylelint": "^14.16.0",
"stylelint": "^14.16.1",
"stylelint-config-prettier": "^9.0.4",
"stylelint-config-standard-scss": "^6.1.0",
"typescript": "^4.8.3",
"vite": "^4.0.3",
"typescript": "^4.9.4",
"vite": "^4.0.4",
"vite-plugin-svgr": "^2.4.0",
"vite-tsconfig-paths": "^4.0.3",
"vitest": "^0.26.2"
},
"resolutions": {
"**/@types/react": "18.0.21"
"vite-tsconfig-paths": "^4.0.3"
}
}

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 600 B

After

Width:  |  Height:  |  Size: 600 B

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

@@ -3,10 +3,10 @@ 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/errorBoundary/ErrorBoundary';
import { AppContextProvider } from 'common/context/AppContext';
import { LoggingProvider } from 'common/context/LoggingContext';
import ErrorBoundary from './common/components/error-boundary/ErrorBoundary';
import { AppContextProvider } from './common/context/AppContext';
import { LoggingProvider } from './common/context/LoggingContext';
import useElectronEvent from './common/hooks/useElectronEvent';
import { ontimeQueryClient } from './common/queryClient';
import theme from './theme/theme';
@@ -4,18 +4,18 @@ import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-
import useAliases from './common/hooks-query/useAliases';
import withSocket from './features/viewers/ViewWrapper';
const Editor = lazy(() => import('features/editors/ProtectedEditor'));
const Table = lazy(() => import('features/table/ProtectedTable'));
const Editor = lazy(() => import('./features/editors/ProtectedEditor'));
const Table = lazy(() => import('./features/table/ProtectedTable'));
const TimerView = lazy(() => import('features/viewers/timer/Timer'));
const MinimalTimerView = lazy(() => import('features/viewers/minimal-timer/MinimalTimer'));
const ClockView = lazy(() => import('features/viewers/clock/Clock'));
const Countdown = lazy(() => import('features/viewers/countdown/Countdown'));
const TimerView = lazy(() => import('./features/viewers/timer/Timer'));
const MinimalTimerView = lazy(() => import('./features/viewers/minimal-timer/MinimalTimer'));
const ClockView = lazy(() => import('./features/viewers/clock/Clock'));
const Countdown = lazy(() => import('./features/viewers/countdown/Countdown'));
const Backstage = lazy(() => import('features/viewers/backstage/Backstage'));
const Public = lazy(() => import('features/viewers/public/Public'));
const Lower = lazy(() => import('features/viewers/lower-thirds/LowerWrapper'));
const StudioClock = lazy(() => import('features/viewers/studio/StudioClock'));
const Backstage = lazy(() => import('./features/viewers/backstage/Backstage'));
const Public = lazy(() => import('./features/viewers/public/Public'));
const Lower = lazy(() => import('./features/viewers/lower-thirds/LowerWrapper'));
const StudioClock = lazy(() => import('./features/viewers/studio/StudioClock'));
const STimer = withSocket(TimerView);
const SMinimalTimer = withSocket(MinimalTimerView);
@@ -26,11 +26,11 @@ const SPublic = withSocket(Public);
const SLowerThird = withSocket(Lower);
const SStudio = withSocket(StudioClock);
const FeatureWrapper = lazy(() => import('features/FeatureWrapper'));
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 FeatureWrapper = lazy(() => import('./features/FeatureWrapper'));
const RundownPanel = lazy(() => import('./features/rundown/RundownExport'));
const TimerControl = lazy(() => import('./features/control/playback/TimerControlExport'));
const MessageControl = lazy(() => import('./features/control/message/MessageControlExport'));
const Info = lazy(() => import('./features/info/InfoExport'));
export default function AppRouter() {
const { data } = useAliases();

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -1,6 +1,7 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Input } from '@chakra-ui/react';
import { clamp } from 'common/utils/math';
import { clamp } from '../../../utils/math';
import style from './DelayInput.module.scss';
@@ -1,13 +1,17 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { vi } from 'vitest';
import TextInput from '../TextInput';
describe('TextInput component', () => {
describe('when given props', () => {
// small hack to reset DOM between tests
beforeEach(() => {
document.getElementsByTagName('html')[0].innerHTML = '';
});
it('renders correctly', () => {
const testField = 'test';
const testField = 'title';
const testText = 'Test 123';
const submitHandler = vi.fn();
render(<TextInput field={testField} initialText={testText} submitHandler={submitHandler} />);
@@ -18,11 +22,10 @@ describe('TextInput component', () => {
});
it('Handles renders as textarea', () => {
const testField = 'test';
const testField = 'title';
const testText = 'Test 123';
const submitHandler = vi.fn();
render(<TextInput field={testField} initialText={testText} isTextArea
submitHandler={submitHandler} />);
render(<TextInput field={testField} initialText={testText} isTextArea submitHandler={submitHandler} />);
const input = screen.getByTestId('input-textarea');
expect(input).toBeInTheDocument();
@@ -31,8 +34,12 @@ describe('TextInput component', () => {
});
describe('on status change', () => {
// small hack to reset DOM between tests
afterEach(() => {
document.getElementsByTagName('html')[0].innerHTML = '';
});
it('calls submitHandler on new value', async () => {
const testField = 'test';
const testField = 'title';
const testText = 'Test 123';
const myTypedString = '456';
const expectedString = testText + myTypedString;
@@ -53,7 +60,7 @@ describe('TextInput component', () => {
});
it('cleans value before submitting', async () => {
const testField = 'test';
const testField = 'title';
const myTypedString = ' 456 ';
const expectedString = '456';
const submitHandler = vi.fn();
@@ -70,25 +77,8 @@ describe('TextInput component', () => {
});
describe('handles edge cases', () => {
it('handles number values', () => {
const testField = 'test';
const testText = 123;
render(<TextInput field={testField} initialText={testText} />);
const input = screen.getByTestId('input-textfield');
expect(input).toBeInTheDocument();
expect(input).toHaveValue(`${testText}`);
});
it('handles null value', () => {
const testField = 'test';
const testText = null;
const expected = '';
render(<TextInput field={testField} initialText={testText} />);
const input = screen.getByTestId('input-textfield');
expect(input).toBeInTheDocument();
expect(input).toHaveValue(expected);
});
it('handles undefined value', () => {
const testField = 'test';
const testField = 'title';
const expected = '';
render(<TextInput field={testField} submitHandler={vi.fn()} />);
const input = screen.getByTestId('input-textfield');
@@ -1,11 +1,11 @@
import { KeyboardEvent, useCallback, useContext, useEffect, useRef, useState } from 'react';
import { Button, Input, InputGroup, InputLeftElement, Tooltip } from '@chakra-ui/react';
import { LoggingContext } from 'common/context/LoggingContext';
import { forgivingStringToMillis } from 'common/utils/dateConfig';
import { stringFromMillis } from 'common/utils/time';
import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor';
import { tooltipDelayFast } from '../../../../ontimeConfig';
import { LoggingContext } from '../../../context/LoggingContext';
import { forgivingStringToMillis } from '../../../utils/dateConfig';
import { stringFromMillis } from '../../../utils/time';
import { TimeEntryField } from '../../../utils/timesManager';
import style from './TimeInput.module.scss';
@@ -144,7 +144,7 @@ export default function TimeInput(props: TimeInputProps) {
return (
<InputGroup size='sm' className={`${style.timeInput} ${isDelayed ? style.delayed : ''}`}>
<InputLeftElement width='fit-content'>
<Tooltip label={<ButtonTooltip />} openDelay={tooltipDelayFast} variant='ontime-ondark'>
<Tooltip label={ButtonTooltip()} openDelay={tooltipDelayFast} variant='ontime-ondark'>
<Button
size='sm'
variant='ontime-subtle-white'
@@ -154,7 +154,7 @@ export default function TimeInput(props: TimeInputProps) {
borderRight='1px solid transparent'
borderRadius='2px 0 0 2px'
>
<ButtonInitial />
{ButtonInitial()}
</Button>
</Tooltip>
</InputLeftElement>
@@ -1,4 +1,4 @@
import { clamp } from 'common/utils/math';
import { clamp } from '../../utils/math';
import './ProgressBar.scss';

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