Merge branch 'master' into feat/info

This commit is contained in:
Carlos Valente
2021-06-13 14:34:20 +02:00
committed by GitHub
71 changed files with 6100 additions and 754 deletions
+98
View File
@@ -0,0 +1,98 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the action will run.
on:
push:
# Pattern matched against refs/tags
tags:
# Push events to every tag not containing /
- '*'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# build a file for windows
buildwin:
# The type of runner that the job will run on
runs-on: windows-latest
env:
CI: ''
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '14.x'
# install and build react
- name: Install React dependencies
run: yarn install
working-directory: ./client
- name: Build React App
run: yarn build
working-directory: ./client
# install and build electron
- name: Install Electron + nodejs dependencies
run: yarn install
working-directory: ./server
- name: Build Electron App
run: yarn dist-win
working-directory: ./server
# release
- name: Release
uses: softprops/action-gh-release@v1
with:
files: ./server/dist/ontime-win64.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# build a file for mac
buildmac:
# The type of runner that the job will run on
runs-on: macOS-latest
env:
CI: ''
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '14.x'
# install and build react
- name: Install React dependencies
run: yarn install
working-directory: ./client
- name: Build React App
run: yarn build
working-directory: ./client
# install and build electron
- name: Install Electron + nodejs dependencies
run: yarn install
working-directory: ./server
- name: Build Electron App
run: yarn dist-win
working-directory: ./server
# release
- name: Release
uses: softprops/action-gh-release@v1
with:
files: ./server/dist/ontime-macOS.dmg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -4
View File
@@ -28,10 +28,7 @@ TODO.md
# working stuff
_SS/
.vscode/launch.json
server/db.json
db.json
.eslintrc.json
yarn.lock
package.json
package-lock.json
db.json
db backup.json
+9
View File
@@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright © 2021 <Carlos Valente>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+1 -69
View File
@@ -1,70 +1,2 @@
# Getting Started with Create React App
# Initial page
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `yarn build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
+4
View File
@@ -0,0 +1,4 @@
# Table of contents
* [Initial page](README.md)
+4
View File
@@ -7,6 +7,10 @@ body,
html,
.App {
margin: 0px auto;
overflow: hidden;
overflow: clip;
height: 100vh;
-webkit-user-select: none;
user-select: none;
-webkit-app-region: drag;
}
+4 -1
View File
@@ -37,7 +37,6 @@ export const downloadEvents = async () => {
};
export const uploadEvents = async (file) => {
console.log('uploading', file);
const formData = new FormData();
formData.append('jsondb', file); // appending file
await axios
@@ -49,3 +48,7 @@ export const uploadEvents = async (file) => {
.then((res) => console.log(res.data))
.catch((err) => console.error(err));
};
export const uploadEventsWithPath = async (filepath) => {
await axios.post(ontimeURL + '/dbpath', { path: filepath });
};
@@ -1,16 +1,19 @@
import { IconButton } from '@chakra-ui/button';
import { Tooltip } from '@chakra-ui/tooltip';
import { FiChevronsDown } from 'react-icons/fi';
export default function ApplyIconBtn(props) {
const { clickhandler, ...rest } = props;
return (
<IconButton
size={props.size || 'xs'}
icon={<FiChevronsDown />}
colorScheme='orange'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
/>
<Tooltip label='Apply delays'>
<IconButton
size={props.size || 'xs'}
icon={<FiChevronsDown />}
colorScheme='orange'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
/>
</Tooltip>
);
}
@@ -6,13 +6,13 @@ export default function LockIconBtn(props) {
const { clickhandler, active, ref } = props;
return (
<Tooltip label='Lock cursor to current'>
<IconButton
<IconButton
ref={ref}
size={props.size || 'xs'}
icon={<FiTarget />}
color={active ? 'pink.100' : 'pink.300'}
borderColor={active ? undefined : 'pink.300'}
backgroundColor={active ? 'pink.300' : undefined}
backgroundColor={active ? 'pink.400' : undefined}
variant={active ? 'solid' : 'outline'}
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
@@ -0,0 +1,22 @@
import { IconButton } from '@chakra-ui/button';
import { Tooltip } from '@chakra-ui/tooltip';
import { FiUsers } from 'react-icons/fi';
export default function PublicIconBtn(props) {
const { actionHandler, active, ...rest } = props;
return (
<Tooltip label={active ? 'Make event private' : 'Make event public'}>
<IconButton
size={props.size || 'xs'}
icon={<FiUsers />}
colorScheme='blue'
variant={active ? 'solid' : 'outline'}
onClick={() =>
actionHandler('update', { field: 'isPublic', value: !active })
}
_focus={{ boxShadow: 'none' }}
{...rest}
/>
</Tooltip>
);
}
@@ -1,11 +0,0 @@
import { Flex, Text } from '@chakra-ui/layout';
import styles from './NumberedText.module.css';
export default function NumberedText({ number = 1, text = '' }) {
return (
<Flex>
<div className={styles.stylednumber}>{number}</div>
<Text>{text}</Text>
</Flex>
);
}
@@ -1,13 +0,0 @@
.stylednumber {
display: inline;
text-align: center;
color: white;
font-weight: 600;
background-color: #ff5b7e;
border: 1px solid rgba(255,255,255,0.17);
width: 1.5em;
border-radius: 1em;
margin-right: 0.5em;
}
@@ -8,9 +8,12 @@
.block {
display: 'block';
overflow-x: hidden;
overflow: hidden;
}
.inline {
display: inline;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
+7 -23
View File
@@ -1,3 +1,4 @@
import { lazy, useEffect } from 'react';
import { Heading } from '@chakra-ui/layout';
import { Box } from '@chakra-ui/layout';
@@ -28,50 +29,33 @@ export default function Editor() {
<div className={styles.mainContainer}>
<Box id='settings' className={styles.settings}>
<MenuBar onOpen={onOpen} onClose={onClose} />
<MenuBar onOpen={onOpen} />
</Box>
<Box className={styles.editor}>
<Heading size='lg' paddingBottom={'0.25em'}>
Event List
</Heading>
<NumberedText number={1} text={'Manage events'} />
<h1>Event List</h1>
<div className={styles.content}>
<EventListWrapper />
</div>
</Box>
<Box className={styles.messages}>
<Heading size='lg' paddingBottom={'0.25em'}>
Display Messages
</Heading>
<NumberedText
number={3}
text={'Show realtime messages on different screens'}
/>
<h1>Display Messages</h1>
<div className={styles.content}>
<MessageControl />
</div>
</Box>
<Box className={styles.playback}>
<Heading size='lg' paddingBottom={'0.25em'}>
Time Control
</Heading>
<NumberedText number={2} text={'Control timers'} />
<h1>Timer Control</h1>
<div className={styles.content}>
<PlaybackControl />
</div>
</Box>
<Box className={styles.info} borderRadius='0.5em' overflowX='auto'>
<Heading size='lg' paddingBottom={'0.25em'}>
Info
</Heading>
<NumberedText number={4} text={'Running Info'} />
<div className={styles.content}>
<Info />
</div>
<h1>Info</h1>
<div className={styles.content}></div>
</Box>
</div>
</>
@@ -69,6 +69,12 @@
}
}
h1 {
font-size: 2.5vh;
color: rgba(255, 255, 255, 0.63);
padding-bottom: 0.25em;
}
.mainContainer > div {
border-radius: 0.5em;
height: 100%;
@@ -1,6 +1,6 @@
import { Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/menu';
import { IconButton } from '@chakra-ui/button';
import { FiZap, FiPlus, FiMinusCircle, FiClock } from 'react-icons/fi';
import { FiPlus, FiMinusCircle, FiClock } from 'react-icons/fi';
export default function ActionButtons(props) {
const { showAdd, showDelay, showBlock, actionHandler } = props;
@@ -16,7 +16,7 @@ export default function ActionButtons(props) {
as={IconButton}
aria-label='Options'
size='xs'
icon={<FiZap />}
icon={<FiPlus />}
_expanded={{ bg: 'orange.300', color: 'white' }}
_focus={{ boxShadow: 'none' }}
backgroundColor={'orange.200'}
@@ -6,7 +6,7 @@ import EventTimes from 'common/components/eventTimes/EventTimes';
import EventTimesVertical from 'common/components/eventTimes/EventTimesVertical';
import EditableText from 'common/input/EditableText';
import ActionButtons from './ActionButtons';
import VisibleIconBtn from 'common/components/buttons/VisibleIconBtn';
import PublicIconBtn from 'common/components/buttons/PublicIconBtn';
import DeleteIconBtn from 'common/components/buttons/DeleteIconBtn';
import { millisToMinutes } from 'common/dateConfig';
import style from './EventBlock.module.css';
@@ -94,7 +94,7 @@ const ExpandedBlock = (props) => {
onClick={() => props.setCollapsed(true)}
/>
<div className={style.actionOverlay}>
<VisibleIconBtn actionHandler={actionHandler} active={data.isPublic} />
<PublicIconBtn actionHandler={actionHandler} active={data.isPublic} />
<ActionButtons
showAdd
showDelay
@@ -147,7 +147,7 @@ const CollapsedBlock = (props) => {
onClick={() => props.setCollapsed(false)}
/>
<div className={style.actionOverlay}>
<VisibleIconBtn actionHandler={actionHandler} active={data.isPublic} />
<PublicIconBtn actionHandler={actionHandler} active={data.isPublic} />
<ActionButtons
showAdd
showDelay
@@ -152,6 +152,8 @@
font-size: 0.8em;
float: right;
padding-right: 1em;
-webkit-user-select: text;
user-select: text;
}
/* ================ MORE ================ */
@@ -1,12 +1,6 @@
import { Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/menu';
import { IconButton } from '@chakra-ui/button';
import {
FiTrash2,
FiZap,
FiPlus,
FiClock,
FiMinusCircle,
} from 'react-icons/fi';
import { FiTrash2, FiPlus, FiClock, FiMinusCircle } from 'react-icons/fi';
import { Divider } from '@chakra-ui/layout';
export default function MenuActionButtons(props) {
@@ -20,9 +14,9 @@ export default function MenuActionButtons(props) {
<Menu isLazy lazyBehavior='unmount'>
<MenuButton
as={IconButton}
aria-label='Options'
aria-label='Create Menu'
size={props.size || 'xs'}
icon={<FiZap />}
icon={<FiPlus />}
_expanded={{ bg: 'orange.300', color: 'white' }}
_focus={{ boxShadow: 'none' }}
backgroundColor={'orange.200'}
+92 -9
View File
@@ -1,4 +1,6 @@
import { downloadEvents } from 'app/api/ontimeApi';
import { useMutation, useQueryClient } from 'react-query';
import { downloadEvents, uploadEvents } from 'app/api/ontimeApi';
import { EVENTS_TABLE } from 'app/api/apiConstants';
import DownloadIconBtn from './buttons/DownloadIconBtn';
import SettingsIconBtn from './buttons/SettingsIconBtn';
import InfoIconBtn from './buttons/InfoIconBtn';
@@ -7,24 +9,105 @@ import MinIconBtn from './buttons/MinIconBtn';
import QuitIconBtn from './buttons/QuitIconBtn';
import style from './MenuBar.module.css';
import HelpIconBtn from './buttons/HelpIconBtn';
import UploadIconBtn from './buttons/UploadIconBtn';
import { useRef } from 'react';
const { ipcRenderer } = window.require('electron');
export default function MenuBar(props) {
const { onOpen, onClose } = props;
const { onOpen } = props;
const hiddenFileInput = useRef(null);
const queryClient = useQueryClient();
const uploaddb = useMutation(uploadEvents, {
onSettled: () => {
queryClient.invalidateQueries(EVENTS_TABLE);
},
});
const handleDownload = () => {
downloadEvents();
};
const handleClick = () => {
if (hiddenFileInput && hiddenFileInput.current) {
hiddenFileInput.current.click();
}
};
const handleUpload = (event) => {
const fileUploaded = event.target.files[0];
if (fileUploaded == null) return;
try {
uploaddb.mutate(fileUploaded);
} catch (error) {
console.log(error);
}
};
const handleIPC = (action) => {
switch (action) {
case 'min':
ipcRenderer.send('set-window', 'to-tray');
break;
case 'max':
ipcRenderer.send('set-window', 'to-max');
break;
case 'shutdown':
ipcRenderer.send('shutdown', 'now');
break;
case 'help':
ipcRenderer.send('send-to-link', 'help');
break;
default:
break;
}
};
return (
<>
<QuitIconBtn size='md' />
<MaxIconBtn size='md' />
<MinIconBtn size='md' />
<QuitIconBtn size='lg' clickhandler={() => handleIPC('shutdown')} />
<MaxIconBtn
style={{ fontSize: '1.5em' }}
size='lg'
clickhandler={() => handleIPC('max')}
/>
<MinIconBtn
style={{ fontSize: '1.5em' }}
size='lg'
clickhandler={() => handleIPC('min')}
/>
<div className={style.gap} />
<HelpIconBtn size='md' disabled />
<SettingsIconBtn size='md' disabled />
<InfoIconBtn size='md' clickhandler={onOpen} />
<DownloadIconBtn size='md' clickhandler={handleDownload} />
<HelpIconBtn
style={{ fontSize: '1.5em' }}
size='lg'
clickhandler={() => handleIPC('help')}
/>
<SettingsIconBtn style={{ fontSize: '1.5em' }} size='lg' disabled />
<div className={style.gap} />
<InfoIconBtn
style={{ fontSize: '1.5em' }}
size='lg'
clickhandler={onOpen}
/>
<input
type='file'
style={{ display: 'none' }}
ref={hiddenFileInput}
onChange={handleUpload}
accept='.json'
/>
<UploadIconBtn
style={{ fontSize: '1.5em' }}
size='lg'
clickhandler={handleClick}
/>
<DownloadIconBtn
style={{ fontSize: '1.5em' }}
size='lg'
clickhandler={handleDownload}
/>
</>
);
}
@@ -10,9 +10,6 @@ export default function DownloadIconBtn(props) {
size={props.size || 'xs'}
icon={<FiDownload />}
colorScheme='white'
variant='outline'
isRound
borderColor='#fff1'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
@@ -10,9 +10,6 @@ export default function HelpIconBtn(props) {
size={props.size || 'xs'}
icon={<FiHelpCircle />}
colorScheme='white'
variant='outline'
isRound
borderColor='#fff1'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
@@ -10,9 +10,6 @@ export default function InfoIconBtn(props) {
size={props.size || 'xs'}
icon={<FiHome />}
colorScheme='white'
variant='outline'
isRound
borderColor='#fff1'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
@@ -10,9 +10,6 @@ export default function MaxIconBtn(props) {
size={props.size || 'xs'}
icon={<FiMaximize />}
colorScheme='white'
variant='outline'
isRound
borderColor='#fff1'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
@@ -10,9 +10,6 @@ export default function MinIconBtn(props) {
size={props.size || 'xs'}
icon={<FiMinimize />}
colorScheme='white'
variant='outline'
isRound
borderColor='#fff1'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
@@ -1,21 +1,68 @@
import { IconButton } from '@chakra-ui/button';
import { Button, IconButton } from '@chakra-ui/button';
import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
} from '@chakra-ui/modal';
import { Tooltip } from '@chakra-ui/tooltip';
import { useRef, useState } from 'react';
import { FiPower } from 'react-icons/fi';
export default function QuitIconBtn(props) {
const { clickhandler, ...rest } = props;
const [isOpen, setIsOpen] = useState(false);
const onClose = () => setIsOpen(false);
const cancelRef = useRef();
const handleShutdown = () => {
onClose();
clickhandler();
};
return (
<Tooltip label='Quit Application'>
<IconButton
size={props.size || 'xs'}
icon={<FiPower />}
colorScheme='red'
variant='outline'
isRound
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
/>
</Tooltip>
<>
<Tooltip label='Quit Application'>
<IconButton
size={props.size || 'xs'}
icon={<FiPower />}
colorScheme='red'
variant='outline'
isRound
onClick={() => setIsOpen(true)}
_focus={{ boxShadow: 'none' }}
{...rest}
/>
</Tooltip>
<AlertDialog
isOpen={isOpen}
leastDestructiveRef={cancelRef}
onClose={onClose}
>
<AlertDialogOverlay>
<AlertDialogContent>
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
Server Shutdown
</AlertDialogHeader>
<AlertDialogBody>
This will shutdown the program and all running servers. Are you
sure?
</AlertDialogBody>
<AlertDialogFooter>
<Button ref={cancelRef} onClick={onClose}>
Cancel
</Button>
<Button colorScheme='red' onClick={handleShutdown} ml={3}>
Shutdown
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
</>
);
}
@@ -10,9 +10,6 @@ export default function SettingsIconBtn(props) {
size={props.size || 'xs'}
icon={<FiSettings />}
colorScheme='white'
variant='outline'
isRound
borderColor='#fff1'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
@@ -0,0 +1,19 @@
import { IconButton } from '@chakra-ui/button';
import { Tooltip } from '@chakra-ui/tooltip';
import { FiUpload } from 'react-icons/fi';
export default function UploadIconBtn(props) {
const { clickhandler, ...rest } = props;
return (
<Tooltip label='Upload File'>
<IconButton
size={props.size || 'xs'}
icon={<FiUpload />}
colorScheme='white'
onClick={clickhandler}
_focus={{ boxShadow: 'none' }}
{...rest}
/>
</Tooltip>
);
}
+4
View File
@@ -0,0 +1,4 @@
{
"dependencies": {},
"devDependencies": {}
}
+70
View File
@@ -0,0 +1,70 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `yarn build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+21
View File
@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="275" height="275" fill="none" viewBox="0 0 275 275">
<path fill="#4D4D4D" d="M49.83 133.919c0-18.343 3.531-34.692 10.595-49.048 7.064-14.355 17.204-25.464 30.42-33.325 13.33-7.861 28.768-11.792 46.313-11.792 24.952 0 45.288 7.633 61.011 22.9 15.837 15.267 24.666 36.003 26.489 62.207l.342 12.647c0 28.369-7.918 51.155-23.755 68.359-15.836 17.09-37.085 25.635-63.745 25.635-26.66 0-47.965-8.545-63.916-25.635-15.836-17.09-23.755-40.332-23.755-69.726v-2.222zm49.389 3.589c0 17.545 3.304 30.989 9.912 40.332 6.608 9.228 16.064 13.843 28.369 13.843 11.963 0 21.305-4.558 28.028-13.672 6.722-9.229 10.083-23.926 10.083-44.092 0-17.204-3.361-30.534-10.083-39.99-6.723-9.457-16.179-14.185-28.37-14.185-12.076 0-21.419 4.728-28.027 14.185-6.608 9.342-9.912 23.869-9.912 43.579z"/>
<mask id="a" width="177" height="193" x="49" y="39" maskUnits="userSpaceOnUse">
<path fill="#fff" d="M49.83 133.919c0-18.343 3.531-34.692 10.595-49.048 7.064-14.355 17.204-25.464 30.42-33.325 13.33-7.861 28.768-11.792 46.313-11.792 24.952 0 45.288 7.633 61.011 22.9 15.837 15.267 24.666 36.003 26.489 62.207l.342 12.647c0 28.369-7.918 51.155-23.755 68.359-15.836 17.09-37.085 25.635-63.745 25.635-26.66 0-47.965-8.545-63.916-25.635-15.836-17.09-23.755-40.332-23.755-69.726v-2.222zm49.389 3.589c0 17.545 3.304 30.989 9.912 40.332 6.608 9.228 16.064 13.843 28.369 13.843 11.963 0 21.305-4.558 28.028-13.672 6.722-9.229 10.083-23.926 10.083-44.092 0-17.204-3.361-30.534-10.083-39.99-6.723-9.457-16.179-14.185-28.37-14.185-12.076 0-21.419 4.728-28.027 14.185-6.608 9.342-9.912 23.869-9.912 43.579z"/>
</mask>
<g mask="url(#a)">
<path fill="url(#paint0_linear)" d="M19.07 95.347c15.556-6.524 14.288-34.989 22.08-30.11 9.74 6.099 0-23.084 13.549-16.56 21.714 10.455-10.977 18.645 12.296 32.007 23.274 13.362 117.508 24.346 150.898 90.045 12.812 25.21 19.341 32.653 21.836 34.543 1.508-.13 1.78 1.349 0 0-.38.033-.838.168-1.362.476-5.516 3.245-106.876 85.867-148.54 34.124C48.162 188.129 2.25 140.221 14.31 127.463c9.648-10.205 1.393-25.103 4.76-32.116z"/>
<path fill="url(#paint1_linear)" d="M42.153 69.754c-7.791-4.88-.412 13.939-24.087 22.582-3.366 7.013 4.63 19.904-5.018 30.109-12.06 12.757 37.623 69.197 79.288 120.94 41.664 51.743 123.453-24.356 128.969-27.6 5.515-3.245 14.092 10.618-10.114-37.154-33.382-65.882-126.481-75.197-149.59-98.582-20.018-20.26 33.92-42.547 10.662-37.896-30.11 6.022-20.37 33.7-30.11 27.6z"/>
</g>
<defs>
<linearGradient id="paint0_linear" x1="93.96" x2="67.62" y1="-33.993" y2="351.251" gradientUnits="userSpaceOnUse">
<stop/>
<stop offset="1" stop-color="#414141" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="88.433" x2="62.092" y1="-37.321" y2="347.924" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF005C" stop-opacity=".74"/>
<stop offset="0"/>
<stop offset="1" stop-color="#242424" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

+1
View File
@@ -0,0 +1 @@
window.require = require;
+104
View File
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; style-src 'unsafe-inline'; script-src 'self'"
/>
<title>ontime</title>
<style>
body {
-webkit-user-select: none;
user-select: none;
-webkit-app-region: drag;
animation: fadein 0s;
background-color: #0005;
}
h1 {
font-family: Roboto, sans-serif;
font-weight: 100;
color: #fffa;
font-size: 24px;
}
.container {
margin-top: 5vh;
display: grid;
place-items: center;
}
.lds-ellipsis {
display: inline-block;
position: relative;
width: 71px;
}
.lds-ellipsis div {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff7597aa;
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.lds-ellipsis div:nth-child(1) {
left: 8px;
animation: lds-ellipsis1 0.6s infinite;
}
.lds-ellipsis div:nth-child(2) {
left: 8px;
animation: lds-ellipsis2 0.6s infinite;
}
.lds-ellipsis div:nth-child(3) {
left: 32px;
animation: lds-ellipsis2 0.6s infinite;
}
.lds-ellipsis div:nth-child(4) {
left: 56px;
animation: lds-ellipsis3 0.6s infinite;
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes lds-ellipsis1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes lds-ellipsis3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes lds-ellipsis2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(24px, 0);
}
}
</style>
</head>
<body>
<div class="container">
<img src="../../assets/logo.png" />
<h1>ontime · event timers</h1>
<div class="lds-ellipsis">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</body>
</html>
+260
View File
@@ -0,0 +1,260 @@
const {
app,
BrowserWindow,
Menu,
globalShortcut,
Tray,
dialog,
ipcMain,
shell,
Notification,
} = require('electron');
const path = require('path');
const env = process.env.NODE_ENV || 'prod';
let loaded = 'Nothing loaded';
let isQuitting = false;
const nodePath =
env != 'prod'
? path.join('file://', __dirname, 'src/app.js')
: path.join('file://', __dirname, '../', 'extraResources', 'src/app.js');
(async () => {
try {
const { startServer, startOSCServer, startOSCClient } = await import(
nodePath
);
// Start express server
loaded = startServer();
// Start OSC Server (API)
startOSCServer();
// Start OSC Client (Feedback)
startOSCClient();
} catch (error) {
loaded = error;
}
})();
// Load Icons
// TODO: Icons appear pixelated
const trayIcon = path.join(__dirname, './assets/images/logos/LOGO-512.png');
const appIcon = path.join(__dirname, './assets/images/logos/LOGO-512.png');
function showNotification(text) {
new Notification({
title: 'ontime',
body: text,
silent: true,
}).show();
}
let win;
let splash;
let tray = null;
// Ensure there isn't another instance of the app running already
const lock = app.requestSingleInstanceLock();
if (!lock) {
dialog.showErrorBox(
'Multiple instances',
'An instance if the App is already running.'
);
app.quit();
return;
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (win) {
if (win.isMinimized()) win.restore();
win.show();
}
});
}
function createWindow() {
// create a new `splash`-Window
splash = new BrowserWindow({
width: 333,
height: 333,
transparent: true,
icon: appIcon,
resizable: false,
frame: false,
alwaysOnTop: true,
});
splash.loadURL(`file://${__dirname}/electron/splash/splash.html`);
win = new BrowserWindow({
width: 1920,
height: 1000,
minWidth: 500,
minHeight: 530,
maxWidth: 1920,
maxHeight: 1440,
backgroundColor: '#202020',
icon: appIcon,
show: false,
textAreasAreResizable: false,
enableWebSQL: false,
webPreferences: {
preload: path.join(__dirname, './electron/preload.js'),
// TODO: what are recommended alternatives to node integration?
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
},
});
win.setMenu(null);
// Load page served by node
const reactApp =
env == 'prod'
? 'http://localhost:4001/editor'
: 'http://localhost:3000/editor';
win.loadURL(reactApp).then(() => {
win.webContents.setBackgroundThrottling(false);
});
}
app.whenReady().then(() => {
createWindow();
/* ======================================
* CONTEXT MENU CREATION ON REACT SIDE
// Create context menu
// const contextMenu = new Menu();
// contextMenu.append(
// new MenuItem({
// label: 'Build context menu here',
// })
// );
// open context menu when clicked
// win.webContents.on('context-menu', (e, params) => {
// contextMenu.popup(win, params.x, params.y);
// });
* ======================================
*/
// register global shortcuts
// (available regardless of wheter app is in focus)
// bring focus to window
globalShortcut.register('Alt+1', () => {
win.show();
});
globalShortcut.register('Alt+t', () => {
// Show dev tools
win.webContents.openDevTools({ mode: 'detach' });
});
// recreate window if no others open
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
win.once('ready-to-show', () => {
setTimeout(() => {
// window stuff
win.show();
splash.destroy();
showNotification(loaded.toString());
// tray stuff
// TODO: get IP Address
tray.setToolTip(loaded);
}, 2000);
});
// Hide on close
win.on('close', function (event) {
event.preventDefault();
if (!isQuitting) {
showNotification('App running in background');
win.hide();
return false;
}
return true;
});
// create tray
// TODO: Design better icon
tray = new Tray(trayIcon);
// TODO: Move to separate file
// Define context menu
const trayMenuTemplate = [
{
label: 'Show App',
click: () => win.show(),
},
{
label: 'Close',
click: () => {
win.destroy();
app.quit();
},
},
];
const trayContextMenu = Menu.buildFromTemplate(trayMenuTemplate);
tray.setContextMenu(trayContextMenu);
});
// unregister shortcuts before quitting
app.once('will-quit', () => {
globalShortcut.unregisterAll();
});
// Get messages from react
// Test message
ipcMain.on('test-message', (event, arg) => {
showNotification('testing 1-2', arg);
});
// Terminate
ipcMain.on('shutdown', (event, arg) => {
console.log('Got IPC shutdown');
// terminate node service
(async () => {
const { shutdown } = await import(nodePath);
// Shutdown service
await shutdown();
})();
isQuitting = true;
tray.destroy();
win.destroy();
app.quit();
});
// Window manipulation
ipcMain.on('set-window', (event, arg) => {
console.log('Got IPC set-window', arg);
if (arg === 'to-max') {
// window full
win.setContentSize(1920, 1000);
win.setPosition(0, 0);
} else if (arg === 'to-tray') {
// window to tray
win.hide();
}
});
// Open links external
ipcMain.on('send-to-link', (event, arg) => {
console.log('Got IPC send-to-link', arg);
// send to help URL
if (arg === 'help') {
shell.openExternal('https://cpvalente.gitbook.io/ontime/');
}
});
+76 -17
View File
@@ -1,21 +1,80 @@
{
"name": "passport-example",
"version": "0.0.1",
"description": "Example with Passport (http://www.passportjs.org/)",
"type": "module",
"dependencies": {
"body-parser": "~1.19.0",
"express": "~4.17.1",
"express-session": "~1.17.1",
"lowdb": "2.1.0",
"multer": "^1.4.2",
"nanoid": "^3.1.22",
"node-osc": "6.0.2",
"passport": "~0.4.1",
"passport-local": "~1.0.0",
"socket.io": "^4.0.0"
"name": "ontime",
"version": "0.1.0",
"author": "Carlos Valente",
"description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime",
"keywords": [ "lighdev", "ontime", "timer" ],
"license": "MIT",
"main": "main.js",
"devDependencies": {
"concurrently": "^6.1.0",
"electron": "^13.1.2",
"electron-builder": "^22.11.3",
"eslint": "^7.26.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-simple-import-sort": "^7.0.0"
},
"scripts": {
"start": "node src/app.js"
}
"nodestart": "NODE_ENV=development node app.js",
"start": "NODE_ENV=development electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder",
"dist-win": "electron-builder --publish=never --x64 --win",
"dist-mac": "electron-builder --publish=never --x64 --mac",
"dist-all": "electron-builder -mw"
},
"build": {
"productName": "ontime",
"appId": "no.lightdev.ontime",
"asar": true,
"dmg": {
"artifactName": "ontime-macOS.dmg",
"icon": "icon.icns"
},
"mac": {
"target": "dmg",
"category": "public.app-category.productivity",
"icon": "icon.icns"
},
"win": {
"target": "nsis"
},
"nsis": {
"artifactName": "ontime-win64.exe",
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"deleteAppDataOnUninstall": true,
"installerIcon": "icon.ico"
},
"files": [
"**/*",
"assets/"
],
"directories": {
"buildResources": "./assets/"
},
"extraResources": [
{
"from": "../client/build",
"to": "extraResources/client/build",
"filter": [
"**/*"
]
},
{
"from": "src",
"to": "extraResources/src",
"filter": [
"**/*"
]
}
]
},
"postinstall": "electron-builder install-app-deps"
}
+64 -19
View File
@@ -3,9 +3,15 @@ import { config } from './config/config.js';
// init database
import { Low, JSONFile } from 'lowdb';
import { join } from 'path';
const file = join('data/', config.database.filename);
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const env = process.env.NODE_ENV || 'prod';
const file = path.join(__dirname, 'data/', config.database.filename);
const adapter = new JSONFile(file);
export const db = new Low(adapter);
@@ -34,9 +40,6 @@ import { router as eventsRouter } from './routes/eventsRouter.js';
import { router as eventRouter } from './routes/eventRouter.js';
import { router as ontimeRouter } from './routes/ontimeRouter.js';
// Setup default port
const port = process.env.PORT || config.server.port;
// Global Objects
import { EventTimer } from './classes/EventTimer.js';
@@ -60,30 +63,72 @@ app.use('/events', eventsRouter);
app.use('/event', eventRouter);
app.use('/ontime', ontimeRouter);
// implement general router
app.get('/', (req, res) => {
res.send('ontime API');
// serve react
app.use(
express.static(
path.join(__dirname, env == 'prod' ? '../' : '../../', 'client/build')
)
);
app.get('*', (req, res) => {
res.sendFile(
path.resolve(
__dirname,
env == 'prod' ? '../' : '../../',
'client',
'build',
'index.html'
)
);
});
// Implement route for errors
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
res.status(500).send(err.stack);
});
// create HTTP server
const server = http.createServer(app);
// init timer
global.timer = new EventTimer(server, config);
global.timer.setupWithEventList(data.events);
export const startServer = (overrideConfig = null) => {
// Setup default port
const serverPort = overrideConfig?.port || config.server.port;
// Start server
server.listen(port, () =>
console.log(`HTTP Server is listening on port ${port}`)
);
// Start server
const returnMessage = `HTTP Server is listening on port ${serverPort}`;
server.listen(serverPort, '0.0.0.0', () => console.log(returnMessage));
// init timer
global.timer = new EventTimer(server, config);
global.timer.setupWithEventList(data.events);
return returnMessage;
};
// Start OSC server
import { initiateOSC } from './controllers/OscController.js';
import { initiateOSC, shutdownOSCServer } from './controllers/OscController.js';
initiateOSC(config.osc);
export const startOSCServer = (overrideConfig = null) => {
// Setup default port
const oscInPort = overrideConfig?.port || config.osc.port;
initiateOSC(config.osc);
};
export const startOSCClient = (overrideConfig = null) => {
// Setup default port
const oscOutPort = overrideConfig?.port || config.osc.portOut;
console.log('initialise OSC Client at port: ', oscOutPort);
};
export const shutdown = () => {
console.log('Node service shutdown');
// shutdown express server
server.close();
// shutdown OSC Server
shutdownOSCServer();
// shutdown OSC Client
// shutdown timer
global.timer.shutdown();
};
+8
View File
@@ -83,6 +83,14 @@ export class EventTimer extends Timer {
this._listenToConnections();
}
/**
* @description Shutdown process
*/
shutdown() {
console.log('Closing socket server');
this.io.close();
}
// send current timer
broadcastTimer() {
this.io.emit('timer', this.getObject());
+1
View File
@@ -11,5 +11,6 @@ export const config = {
},
osc: {
port: 8888,
portOut: 8889,
},
};
+7 -1
View File
@@ -1,7 +1,13 @@
import { Server } from 'node-osc';
let oscServer = null;
export const shutdownOSCServer = () => {
if (oscServer != null) oscServer.close();
};
export const initiateOSC = (config) => {
const oscServer = new Server(config.port, '0.0.0.0', () => {
oscServer = new Server(config.port, '0.0.0.0', () => {
console.log(`OSC Server is listening on port ${config.port}`);
});
+40 -13
View File
@@ -1,6 +1,9 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// get database
import { db, data } from '../app.js';
import fs from 'fs';
import {
event as eventDef,
delay as delayDef,
@@ -9,6 +12,9 @@ import {
import { dbModel } from '../data/dataModel.js';
import { networkInterfaces } from 'os';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
function getEventTitle() {
return data.event.title;
}
@@ -24,6 +30,7 @@ async function deleteFile(file) {
// parses version 1 of the data system
async function parsev1(jsonData) {
let numEntries = 0;
if ('events' in jsonData) {
let events = [];
let ids = [];
@@ -46,15 +53,19 @@ async function parsev1(jsonData) {
isPublic: e.isPublic,
id: e.id,
});
numEntries++;
} else if (e.type === 'delay') {
events.push({ ...delayDef, duration: e.duration });
numEntries++;
} else if (e.type === 'block') {
events.push({ ...blockDef });
numEntries++;
}
}
// write to db
db.data.events = events;
db.write();
console.log(`Uploaded file with ${numEntries} entries`);
}
if ('event' in jsonData) {
@@ -83,7 +94,9 @@ async function parsev1(jsonData) {
// Returns -
export const dbDownload = async (req, res) => {
const fileTitle = getEventTitle() || 'ontime events';
res.download('db.json', `${fileTitle}.json`, (err) => {
const dbFile = path.resolve(__dirname, '../', 'data/db.json');
res.download(dbFile, `${fileTitle}.json`, (err) => {
if (err) {
res.status(500).send({
message: 'Could not download the file. ' + err,
@@ -92,15 +105,7 @@ export const dbDownload = async (req, res) => {
});
};
// Create controller for POST request to '/ontime/db'
// Returns -
export const dbUpload = async (req, res) => {
if (!req.file) {
res.status(400).send({ message: 'File not found' });
return;
}
const file = req.file.path;
const upload = async (file, req, res) => {
if (!fs.existsSync(file)) {
res.status(500).send({ message: 'Upload failed' });
return;
@@ -108,8 +113,8 @@ export const dbUpload = async (req, res) => {
try {
// get file
let rawdata = fs.readFileSync(file);
let uploadedJson = JSON.parse(rawdata);
const rawdata = fs.readFileSync(file);
const uploadedJson = JSON.parse(rawdata);
// delete file
deleteFile(file);
@@ -158,4 +163,26 @@ export const getInfo = async (req, res) => {
res.status(200).send({
networkInterfaces: ni,
});
// Create controller for POST request to '/ontime/db'
// Returns -
export const dbUpload = async (req, res) => {
if (!req.file) {
res.status(400).send({ message: 'File not found' });
return;
}
const file = req.file.path;
upload(file, req, res);
};
// Create controller for POST request to '/ontime/dbpath'
// Returns -
export const dbPathToUpload = async (req, res) => {
if (!req.body.path) {
res.status(400).send({ message: 'Path to file not found' });
return;
}
upload(req.body.path, req, res);
};
+28
View File
@@ -0,0 +1,28 @@
{
"type": "module",
"dependencies": {
"body-parser": "~1.19.0",
"express": "~4.17.1",
"express-session": "~1.17.1",
"lowdb": "2.1.0",
"multer": "^1.4.2",
"nanoid": "^3.1.22",
"node-osc": "6.0.2",
"passport": "~0.4.1",
"passport-local": "~1.0.0",
"socket.io": "^4.0.0"
},
"devDependencies": {
"eslint": "^7.26.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-simple-import-sort": "^7.0.0"
},
"scripts": {
"nodestart": "nodemon app.js",
"start": "node app.js"
}
}
+4
View File
@@ -6,6 +6,7 @@ import {
dbDownload,
dbUpload,
getInfo,
dbPathToUpload,
} from '../controllers/ontimeController.js';
// create route between controller and '/ontime/db' endpoint
@@ -16,3 +17,6 @@ router.post('/db', uploadJson, dbUpload);
// create route between controller and '/ontime/info' endpoint
router.get('/info', uploadJson, getInfo);
// create route between controller and '/ontime/dbpath' endpoint
router.post('/dbpath', dbPathToUpload);
+2189
View File
File diff suppressed because it is too large Load Diff
+2865 -518
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1