mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-08 00:43:54 +00:00
Merge branch 'master' into chore/open
This commit is contained in:
@@ -15,8 +15,8 @@ on:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
# build a file for windows
|
||||
buildwin:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
@@ -55,3 +55,44 @@ jobs:
|
||||
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 }}
|
||||
|
||||
@@ -14,6 +14,7 @@ dist/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Table of contents
|
||||
|
||||
* [Initial page](README.md)
|
||||
|
||||
@@ -10,4 +10,7 @@ html,
|
||||
overflow: hidden;
|
||||
overflow: clip;
|
||||
height: 100vh;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const NODE_PORT = 4001;
|
||||
export const EVENT_TABLE = 'event';
|
||||
export const EVENTS_TABLE = 'events';
|
||||
export const APP_TABLE = 'appinfo';
|
||||
|
||||
const calculateServer = () => {
|
||||
return window.location.origin.replace(window.location.port, `${NODE_PORT}/`);
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import axios from 'axios';
|
||||
import { ontimeURL } from './apiConstants';
|
||||
|
||||
export const ontimePlaceholderInfo = {
|
||||
networkInterfaces: [],
|
||||
};
|
||||
|
||||
export const getInfo = async () => {
|
||||
const res = await axios.get(ontimeURL + '/info');
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const downloadEvents = async () => {
|
||||
await axios({
|
||||
url: ontimeURL + '/db',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
|
||||
import style from './EditableText.module.css';
|
||||
|
||||
export default function EditableText(props) {
|
||||
const { label, defaultValue, placeholder, submitHandler } = props;
|
||||
const { label, defaultValue, placeholder, submitHandler, ...rest } = props;
|
||||
const [text, setText] = useState(defaultValue || '');
|
||||
|
||||
useEffect(() => {
|
||||
@@ -30,6 +30,7 @@ export default function EditableText(props) {
|
||||
value={text}
|
||||
placeholder={placeholder}
|
||||
className={style.inline}
|
||||
{...rest}
|
||||
>
|
||||
<EditablePreview
|
||||
color={text === '' ? '#666' : 'inherit'}
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
|
||||
.block {
|
||||
display: 'block';
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { lazy, useEffect } from 'react';
|
||||
import { Heading } from '@chakra-ui/layout';
|
||||
import { Box } from '@chakra-ui/layout';
|
||||
import NumberedText from 'common/components/text/NumberedText';
|
||||
import styles from './Editor.module.css';
|
||||
import { useDisclosure } from '@chakra-ui/hooks';
|
||||
import SettingsModal from '../modals/SettingsModal';
|
||||
import styles from './Editor.module.css';
|
||||
import SettingsModal from 'features/modals/SettingsModal';
|
||||
import MenuBar from 'features/menu/MenuBar';
|
||||
|
||||
const EventListWrapper = lazy(() =>
|
||||
@@ -12,6 +10,7 @@ const EventListWrapper = lazy(() =>
|
||||
);
|
||||
const PlaybackControl = lazy(() => import('features/control/PlaybackControl'));
|
||||
const MessageControl = lazy(() => import('features/control/MessageControl'));
|
||||
const Info = lazy(() => import('features/info/Info'));
|
||||
|
||||
export default function Editor() {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
@@ -31,44 +30,31 @@ export default function Editor() {
|
||||
</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}></div>
|
||||
<Box className={styles.info}>
|
||||
<h1>Info</h1>
|
||||
<div className={styles.content}>
|
||||
<Info />
|
||||
</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';
|
||||
@@ -77,6 +77,7 @@ const ExpandedBlock = (props) => {
|
||||
label='Note'
|
||||
defaultValue={data.note}
|
||||
placeholder='Add Note'
|
||||
style={{ color: '#d69e2e' }}
|
||||
submitHandler={(v) =>
|
||||
actionHandler('update', { field: 'note', value: v })
|
||||
}
|
||||
@@ -93,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
|
||||
@@ -146,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
|
||||
@@ -160,10 +161,6 @@ const CollapsedBlock = (props) => {
|
||||
|
||||
export default function EventBlock(props) {
|
||||
const { data, selected, delay, index, eventIndex, actionHandler } = props;
|
||||
|
||||
// const [collapsed, setCollapsed] = useState(checkLocalStorage(data.id));
|
||||
|
||||
// const collapsed = useSelector(itemsAtom, (state) => state === data.id);
|
||||
const [collapsed] = useAtom(
|
||||
useMemo(() => SelectCollapse(data.id), [data.id])
|
||||
);
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
grid-template-columns: 2em 2em auto auto 1fr auto 3.7em;
|
||||
grid-template-areas: 'drag indi time time text more btns';
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.expanded {
|
||||
@@ -152,6 +151,8 @@
|
||||
font-size: 0.8em;
|
||||
float: right;
|
||||
padding-right: 1em;
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
/* ================ MORE ================ */
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useSocket } from 'app/context/socketContext';
|
||||
import style from './Info.module.css';
|
||||
import InfoTitle from './InfoTitle';
|
||||
import InfoLogger from './InfoLogger';
|
||||
import InfoNif from './InfoNif';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function Info() {
|
||||
const socket = useSocket();
|
||||
const [titles, setTitles] = useState({
|
||||
titleNow: '',
|
||||
subtitleNow: '',
|
||||
presenterNow: '',
|
||||
noteNow: '',
|
||||
titleNext: '',
|
||||
subtitleNext: '',
|
||||
presenterNext: '',
|
||||
noteNext: '',
|
||||
});
|
||||
const [selected, setSelected] = useState('-/-');
|
||||
const logData = [];
|
||||
|
||||
// handle incoming messages
|
||||
useEffect(() => {
|
||||
if (socket == null) return;
|
||||
|
||||
// Ask for titles
|
||||
socket.emit('get-titles');
|
||||
|
||||
// Handle titles
|
||||
socket.on('titles', (data) => {
|
||||
setTitles(data);
|
||||
});
|
||||
|
||||
// Ask for selection data
|
||||
socket.emit('get-selected');
|
||||
|
||||
// Handle selection data
|
||||
socket.on('selected', (data) => {
|
||||
const formatedCurrent = `Event ${
|
||||
data.index != null ? data.index + 1 : '-'
|
||||
}/${data.total != null ? data.total : '-'}`;
|
||||
|
||||
setSelected(formatedCurrent);
|
||||
});
|
||||
|
||||
// Clear listener
|
||||
return () => {
|
||||
socket.off('titles');
|
||||
socket.off('selected');
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
// TODO: Put this in use effect
|
||||
// prepare data
|
||||
const titlesNow = {
|
||||
title: titles.titleNow,
|
||||
subtitle: titles.subtitleNow,
|
||||
presenter: titles.presenterNow,
|
||||
note: titles.noteNow,
|
||||
};
|
||||
|
||||
const titlesNext = {
|
||||
title: titles.titleNext,
|
||||
subtitle: titles.subtitleNext,
|
||||
presenter: titles.presenterNext,
|
||||
note: titles.noteNext,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={style.main}>{selected}</div>
|
||||
{/* <InfoLogger logData={logData} /> */}
|
||||
<InfoNif />
|
||||
<InfoTitle title={'Now'} data={titlesNow} />
|
||||
<InfoTitle title={'Next'} data={titlesNext} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
.container {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.main {
|
||||
font-size: 0.9em;
|
||||
text-align: right;
|
||||
color: #ff7597;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
color: #aaa;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.label {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.notes {
|
||||
color: #d69e2e;
|
||||
}
|
||||
|
||||
.if {
|
||||
font-size: 0.8em;
|
||||
color: #4bffabcc;
|
||||
background-color: rgba(0, 0, 0, 0.13);
|
||||
border-radius: 2px;
|
||||
padding: 0 0.5em;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
ul > li {
|
||||
font-size: 0.9em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.log {
|
||||
overflow-y: scroll;
|
||||
height: 30vh;
|
||||
}
|
||||
|
||||
.info {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.client {
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.moreExpanded,
|
||||
.moreCollapsed {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.moreExpanded {
|
||||
transform: scaleY(-1);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.moreCollapsed {
|
||||
transform: scaleY(1);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Icon } from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import { FiChevronUp } from 'react-icons/fi';
|
||||
import style from './Info.module.css';
|
||||
|
||||
export default function InfoLogger(props) {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
const { logData } = props;
|
||||
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<div className={style.header}>
|
||||
Log
|
||||
<Icon
|
||||
className={collapsed ? style.moreCollapsed : style.moreExpanded}
|
||||
as={FiChevronUp}
|
||||
onClick={() => setCollapsed((c) => !c)}
|
||||
/>
|
||||
</div>
|
||||
{!collapsed && (
|
||||
<ul className={style.log}>
|
||||
<li className={style.info}>10:35:23 [PLAYBACK] Next</li>
|
||||
<li className={style.client}>
|
||||
10:32:10 [CLIENT] New socket client (total: 3)
|
||||
</li>
|
||||
<li className={style.info}>10:28:23 [PLAYBACK] Next</li>
|
||||
<li className={style.info}>10:25:23 [PLAYBACK] Play</li>
|
||||
<li className={style.info}>10:23:13 [SERVER] Server Reconnected</li>
|
||||
<li className={style.error}>10:23:10 [SERVER] Server Disconnected</li>
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Icon } from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import { FiChevronUp } from 'react-icons/fi';
|
||||
import { APP_TABLE } from 'app/api/apiConstants';
|
||||
import { getInfo, ontimePlaceholderInfo } from 'app/api/ontimeApi';
|
||||
import { useFetch } from 'app/hooks/useFetch';
|
||||
import style from './Info.module.css';
|
||||
|
||||
export default function InfoNif() {
|
||||
const { data, status } = useFetch(APP_TABLE, getInfo, {
|
||||
placeholderData: ontimePlaceholderInfo,
|
||||
});
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
const baseURL = `http://__IP__:${isDev ? 3000 : 4001}`;
|
||||
|
||||
const handleLink = (url) => {
|
||||
if (window.process.type === 'renderer') {
|
||||
window.ipcRenderer.send('send-to-link', url);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<div className={style.header}>
|
||||
Network Info
|
||||
<Icon
|
||||
className={collapsed ? style.moreCollapsed : style.moreExpanded}
|
||||
as={FiChevronUp}
|
||||
onClick={() => setCollapsed((c) => !c)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!collapsed && (
|
||||
<div>
|
||||
{status === 'success' && (
|
||||
<>
|
||||
{data?.networkInterfaces.map((e) => {
|
||||
return (
|
||||
<a
|
||||
href='/'
|
||||
onClick={() =>
|
||||
handleLink(baseURL.replace('__IP__', e.address))
|
||||
}
|
||||
className={style.if}
|
||||
>{`${e.name} - ${e.address}`}</a>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Icon } from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import { FiChevronUp } from 'react-icons/fi';
|
||||
import style from './Info.module.css';
|
||||
|
||||
export default function InfoTitle(props) {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
const { title, data } = props;
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<div className={style.header}>
|
||||
{title}
|
||||
<Icon
|
||||
className={collapsed ? style.moreCollapsed : style.moreExpanded}
|
||||
as={FiChevronUp}
|
||||
onClick={() => setCollapsed((c) => !c)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!collapsed && (
|
||||
<>
|
||||
<div>
|
||||
<span className={style.label}>Title: </span>
|
||||
{data.title}
|
||||
</div>
|
||||
<div>
|
||||
<span className={style.label}>Presenter: </span>
|
||||
{data.presenter}
|
||||
</div>
|
||||
<div>
|
||||
<span className={style.label}>Subtitle: </span>
|
||||
{data.subtitle}
|
||||
</div>
|
||||
<div className={style.notes}>
|
||||
<span className={style.label}>Note: </span>
|
||||
{data.note}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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'}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import {
|
||||
downloadEvents,
|
||||
uploadEvents,
|
||||
uploadEventsWithPath,
|
||||
} from 'app/api/ontimeApi';
|
||||
import { downloadEvents, uploadEvents } from 'app/api/ontimeApi';
|
||||
import { EVENTS_TABLE } from 'app/api/apiConstants';
|
||||
import DownloadIconBtn from './buttons/DownloadIconBtn';
|
||||
import SettingsIconBtn from './buttons/SettingsIconBtn';
|
||||
@@ -16,8 +12,6 @@ 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 } = props;
|
||||
const hiddenFileInput = useRef(null);
|
||||
@@ -51,21 +45,23 @@ export default function MenuBar(props) {
|
||||
};
|
||||
|
||||
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;
|
||||
if (window.process.type === 'renderer') {
|
||||
switch (action) {
|
||||
case 'min':
|
||||
window.ipcRenderer.send('set-window', 'to-tray');
|
||||
break;
|
||||
case 'max':
|
||||
window.ipcRenderer.send('set-window', 'to-max');
|
||||
break;
|
||||
case 'shutdown':
|
||||
window.ipcRenderer.send('shutdown', 'now');
|
||||
break;
|
||||
case 'help':
|
||||
window.ipcRenderer.send('send-to-link', 'help');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -87,7 +83,6 @@ export default function MenuBar(props) {
|
||||
style={{ fontSize: '1.5em' }}
|
||||
size='lg'
|
||||
clickhandler={() => handleIPC('help')}
|
||||
disabled
|
||||
/>
|
||||
<SettingsIconBtn style={{ fontSize: '1.5em' }} size='lg' disabled />
|
||||
<div className={style.gap} />
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { stringFromMillis } from '../../src/utils/time';
|
||||
|
||||
const t1 = { val: null, result: '...' };
|
||||
test('test stringFromMillis() on null values', () => {
|
||||
expect(stringFromMillis(t1.val)).toBe(t1.result);
|
||||
});
|
||||
|
||||
const t2 = { val: 3600000, result: '01:00:00' };
|
||||
test('test stringFromMillis() on valid millis', () => {
|
||||
expect(stringFromMillis(t2.val)).toBe(t2.result);
|
||||
});
|
||||
|
||||
const t3 = { val: -3600000, result: '-01:00:00' };
|
||||
test('test stringFromMillis() on negative millis', () => {
|
||||
expect(stringFromMillis(t3.val)).toBe(t3.result);
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
@@ -1 +1 @@
|
||||
window.require = require;
|
||||
window.ipcRenderer = require('electron').ipcRenderer;
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
<title>ontime</title>
|
||||
<style>
|
||||
body {
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
animation: fadein 0s;
|
||||
background-color: #0005;
|
||||
}
|
||||
h1 {
|
||||
@@ -29,10 +33,10 @@
|
||||
}
|
||||
.lds-ellipsis div {
|
||||
position: absolute;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #fffa;
|
||||
background: #ff7597aa;
|
||||
animation-timing-function: cubic-bezier(0, 1, 1, 0);
|
||||
}
|
||||
.lds-ellipsis div:nth-child(1) {
|
||||
@@ -51,6 +55,14 @@
|
||||
left: 56px;
|
||||
animation: lds-ellipsis3 0.6s infinite;
|
||||
}
|
||||
@keyframes fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes lds-ellipsis1 {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
@@ -79,7 +91,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<img src="../../assets/images/logosbwa/LOGO-192.png" />
|
||||
<img src="../../assets/logo.png" />
|
||||
<h1>ontime · event timers</h1>
|
||||
<div class="lds-ellipsis">
|
||||
<div></div>
|
||||
|
||||
+6
-2
@@ -33,6 +33,7 @@ const nodePath =
|
||||
// Start OSC Client (Feedback)
|
||||
startOSCClient();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
loaded = error;
|
||||
}
|
||||
})();
|
||||
@@ -41,10 +42,12 @@ const nodePath =
|
||||
// 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();
|
||||
}
|
||||
|
||||
@@ -120,7 +123,6 @@ function createWindow() {
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
|
||||
/* ======================================
|
||||
* CONTEXT MENU CREATION ON REACT SIDE
|
||||
// Create context menu
|
||||
@@ -253,6 +255,8 @@ ipcMain.on('send-to-link', (event, arg) => {
|
||||
|
||||
// send to help URL
|
||||
if (arg === 'help') {
|
||||
shell.openExternal('http://blank');
|
||||
shell.openExternal('https://cpvalente.gitbook.io/ontime/');
|
||||
} else {
|
||||
shell.openExternal(arg);
|
||||
}
|
||||
});
|
||||
|
||||
+12
-8
@@ -17,28 +17,31 @@
|
||||
"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"
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"jest": "^27.0.4"
|
||||
},
|
||||
"scripts": {
|
||||
"nodestart": "NODE_ENV=development node app.js",
|
||||
"nodestart": "NODE_ENV=development node src/app.js",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.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",
|
||||
|
||||
"startall": "concurrently \"BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\""
|
||||
"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": "no.lightdev.ontime"
|
||||
"target": "dmg",
|
||||
"category": "public.app-category.productivity",
|
||||
"icon": "icon.icns"
|
||||
},
|
||||
"win": {
|
||||
"target": "nsis"
|
||||
@@ -48,6 +51,7 @@
|
||||
"createDesktopShortcut": true,
|
||||
"createStartMenuShortcut": true,
|
||||
"deleteAppDataOnUninstall": true,
|
||||
"runAfterFinish": false,
|
||||
"installerIcon": "icon.ico"
|
||||
},
|
||||
"files": [
|
||||
|
||||
+24
-4
@@ -1,4 +1,9 @@
|
||||
// get config
|
||||
// get environment vars
|
||||
import 'dotenv/config';
|
||||
import { sessionId, user } from './utils/analytics.js';
|
||||
user.screenview('Node service', 'ontime').send();
|
||||
user.event('NODE', 'started', 'starting node service').send();
|
||||
|
||||
import { config } from './config/config.js';
|
||||
|
||||
// init database
|
||||
@@ -16,10 +21,12 @@ const adapter = new JSONFile(file);
|
||||
export const db = new Low(adapter);
|
||||
|
||||
// dependencies
|
||||
import { Client } from 'node-osc';
|
||||
import express from 'express';
|
||||
import http from 'http';
|
||||
import cors from 'cors';
|
||||
import { dbModel } from './data/dataModel.js';
|
||||
import ua from 'universal-analytics';
|
||||
|
||||
// Read data from JSON file, this will set db.data content
|
||||
await db.read();
|
||||
@@ -53,11 +60,12 @@ app.use(cors());
|
||||
app.options('*', cors());
|
||||
|
||||
// Implement middleware
|
||||
app.use('/uploads', express.static('uploads'));
|
||||
|
||||
app.use(ua.middleware(process.env.ANALYTICS_ID, sessionId));
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json({ limit: '1mb' }));
|
||||
|
||||
app.use('/uploads', express.static('uploads'));
|
||||
|
||||
// Implement route endpoints
|
||||
app.use('/events', eventsRouter);
|
||||
app.use('/event', eventRouter);
|
||||
@@ -87,6 +95,10 @@ app.use((err, req, res, next) => {
|
||||
res.status(500).send(err.stack);
|
||||
});
|
||||
|
||||
// Start OSC Client
|
||||
// TODO: Move this to function
|
||||
const oscClient = new Client('127.0.0.1', 9999);
|
||||
|
||||
// create HTTP server
|
||||
const server = http.createServer(app);
|
||||
|
||||
@@ -99,7 +111,7 @@ export const startServer = (overrideConfig = null) => {
|
||||
server.listen(serverPort, '0.0.0.0', () => console.log(returnMessage));
|
||||
|
||||
// init timer
|
||||
global.timer = new EventTimer(server, config);
|
||||
global.timer = new EventTimer(server, oscClient, config);
|
||||
global.timer.setupWithEventList(data.events);
|
||||
|
||||
return returnMessage;
|
||||
@@ -123,6 +135,8 @@ export const startOSCClient = (overrideConfig = null) => {
|
||||
export const shutdown = () => {
|
||||
console.log('Node service shutdown');
|
||||
|
||||
user.event('NODE', 'shutdown', 'requesting node shutfown').send();
|
||||
|
||||
// shutdown express server
|
||||
server.close();
|
||||
// shutdown OSC Server
|
||||
@@ -132,3 +146,9 @@ export const shutdown = () => {
|
||||
// shutdown timer
|
||||
global.timer.shutdown();
|
||||
};
|
||||
|
||||
// if (env == 'development') {
|
||||
// startServer();
|
||||
// startOSCServer();
|
||||
// startOSCClient();
|
||||
// }
|
||||
|
||||
@@ -15,6 +15,10 @@ export class EventTimer extends Timer {
|
||||
|
||||
// Socket IO Object
|
||||
io = null;
|
||||
|
||||
// OSC Client
|
||||
oscClient = null;
|
||||
|
||||
_numClients = 0;
|
||||
_interval = null;
|
||||
|
||||
@@ -44,9 +48,11 @@ export class EventTimer extends Timer {
|
||||
titleNow: null,
|
||||
subtitleNow: null,
|
||||
presenterNow: null,
|
||||
noteNow: null,
|
||||
titleNext: null,
|
||||
subtitleNext: null,
|
||||
presenterNext: null,
|
||||
noteNext: null,
|
||||
};
|
||||
|
||||
selectedEventIndex = null;
|
||||
@@ -57,7 +63,7 @@ export class EventTimer extends Timer {
|
||||
numEvents = null;
|
||||
_eventlist = null;
|
||||
|
||||
constructor(httpServer, config) {
|
||||
constructor(httpServer, oscClient, config) {
|
||||
// call super constructor
|
||||
super();
|
||||
|
||||
@@ -79,6 +85,101 @@ export class EventTimer extends Timer {
|
||||
|
||||
// listen to new connections
|
||||
this._listenToConnections();
|
||||
|
||||
// set oscClient
|
||||
this.updateOSCClient(oscClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Updates the osc client used in the object
|
||||
* @param {object} oscClient
|
||||
*/
|
||||
updateOSCClient(oscClient) {
|
||||
this.oscClient = oscClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Sends osc value from predefined messages
|
||||
* @param {string} event - message to be sent
|
||||
*/
|
||||
sendOSC(event) {
|
||||
if (this.oscClient == null) return;
|
||||
|
||||
const add = '/ontime';
|
||||
const play = 'play';
|
||||
const pause = 'pause';
|
||||
const stop = 'stop';
|
||||
const prev = 'prev';
|
||||
const next = 'next';
|
||||
const reload = 'reload';
|
||||
const finished = 'finished';
|
||||
const time = this.timeTag;
|
||||
// TODO: Should this be boolean?
|
||||
const overtime = this.current > 0 ? 0 : 1;
|
||||
const title = this.titles.titleNow;
|
||||
|
||||
switch (event) {
|
||||
case 'time':
|
||||
// Send Timetag Message
|
||||
this.oscClient.send(add + '/time', time, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'finished':
|
||||
// Runs when timer reaches 0
|
||||
this.oscClient.send(add, finished, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'overtime':
|
||||
// Whether timer is negative
|
||||
this.oscClient.send(add + '/overtime', overtime, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'title':
|
||||
// Send Title of current event
|
||||
this.oscClient.send(add + '/title', title, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'play':
|
||||
// Play Message
|
||||
this.oscClient.send(add, play, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'pause':
|
||||
// Pause Message
|
||||
this.oscClient.send(add, pause, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'stop':
|
||||
// Stop Message
|
||||
this.oscClient.send(add, stop, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'prev':
|
||||
this.oscClient.send(add, prev, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'next':
|
||||
this.oscClient.send(add, next, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
case 'reload':
|
||||
this.oscClient.send(add, reload, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +192,14 @@ export class EventTimer extends Timer {
|
||||
|
||||
// send current timer
|
||||
broadcastTimer() {
|
||||
// through websockets
|
||||
this.io.emit('timer', this.getObject());
|
||||
|
||||
// through OSC, only if running
|
||||
if (this.state === 'start' || this.state === 'roll') {
|
||||
this.sendOSC('time');
|
||||
this.sendOSC('overtime');
|
||||
}
|
||||
}
|
||||
|
||||
// broadcast state
|
||||
@@ -101,6 +209,7 @@ export class EventTimer extends Timer {
|
||||
this.io.emit('selected', {
|
||||
id: this.selectedEventId,
|
||||
index: this.selectedEventIndex,
|
||||
total: this.numEvents,
|
||||
});
|
||||
this.io.emit('selected-id', this.selectedEventId);
|
||||
this.io.emit('next-id', this.nextEventId);
|
||||
@@ -116,44 +225,32 @@ export class EventTimer extends Timer {
|
||||
}
|
||||
|
||||
update() {
|
||||
// if there is nothing selected, no nothing
|
||||
// if there is nothing selected, do nothing
|
||||
if (this.selectedEventId == null && this.state !== 'roll') return;
|
||||
|
||||
// only implement roll here
|
||||
if (this.state !== 'roll') {
|
||||
super.update();
|
||||
return;
|
||||
}
|
||||
|
||||
// get current time
|
||||
const now = this._getCurrentTime();
|
||||
this.clock = now;
|
||||
|
||||
if (this.selectedEventId && this.current > 0) {
|
||||
// update timer as usual
|
||||
this.current = this._finishAt - now;
|
||||
} else {
|
||||
// look for event if none is loaded
|
||||
if (this.current <= 0 || this.secondaryTimer <= 0) this.rollLoad();
|
||||
// get current time
|
||||
const now = this._getCurrentTime();
|
||||
this.clock = now;
|
||||
|
||||
// count to next event
|
||||
// TODO: replace with proper counter
|
||||
if (this.secondaryTimer != null) this.secondaryTimer -= 1000;
|
||||
if (this.selectedEventId && this.current > 0) {
|
||||
// update timer as usual
|
||||
this.current = this._finishAt - now;
|
||||
} else {
|
||||
// look for event if none is loaded
|
||||
if (this.current <= 0 || this.secondaryTimer <= 0) this.rollLoad();
|
||||
|
||||
// count to next event
|
||||
// TODO: replace with proper counter
|
||||
if (this.secondaryTimer != null) this.secondaryTimer -= 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
// if there is nothing selected, no nothing
|
||||
if (this.selectedEventId == null) return;
|
||||
super.start();
|
||||
this.broadcastState();
|
||||
}
|
||||
|
||||
pause() {
|
||||
// if there is nothing selected, no nothing
|
||||
if (this.selectedEventId == null) return;
|
||||
super.pause();
|
||||
this.broadcastState();
|
||||
// sendOSC on reaching 0
|
||||
if (this.current === 0 && this.state === 'start') this.sendOSC('finished');
|
||||
}
|
||||
|
||||
_setterManager(action, payload) {
|
||||
@@ -297,6 +394,7 @@ export class EventTimer extends Timer {
|
||||
socket.emit('selected', {
|
||||
id: this.selectedEventId,
|
||||
index: this.selectedEventIndex,
|
||||
total: this.numEvents,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -596,6 +694,7 @@ export class EventTimer extends Timer {
|
||||
this.titles.titleNow = e.title;
|
||||
this.titles.subtitleNow = e.subtitle;
|
||||
this.titles.presenterNow = e.presenter;
|
||||
this.titles.noteNow = e.note;
|
||||
this.selectedEventId = e.id;
|
||||
|
||||
break;
|
||||
@@ -609,6 +708,7 @@ export class EventTimer extends Timer {
|
||||
this.titles.titleNow = e.title;
|
||||
this.titles.subtitleNow = e.subtitle;
|
||||
this.titles.presenterNow = e.presenter;
|
||||
this.titles.noteNow = e.note;
|
||||
this.selectedEventId = e.id;
|
||||
break;
|
||||
|
||||
@@ -624,6 +724,7 @@ export class EventTimer extends Timer {
|
||||
this.titles.titleNext = e.title;
|
||||
this.titles.subtitleNext = e.subtitle;
|
||||
this.titles.presenterNext = e.presenter;
|
||||
this.titles.noteNext = e.note;
|
||||
this.nextEventId = e.id;
|
||||
break;
|
||||
case 'next-public':
|
||||
@@ -636,6 +737,7 @@ export class EventTimer extends Timer {
|
||||
this.titles.titleNext = e.title;
|
||||
this.titles.subtitleNext = e.subtitle;
|
||||
this.titles.presenterNext = e.presenter;
|
||||
this.titles.noteNext = e.note;
|
||||
this.nextEventId = e.id;
|
||||
break;
|
||||
|
||||
@@ -652,6 +754,7 @@ export class EventTimer extends Timer {
|
||||
this.titles.titleNext = null;
|
||||
this.titles.subtitleNext = null;
|
||||
this.titles.presenterNext = null;
|
||||
this.titles.noteNext = null;
|
||||
this.nextEventId = null;
|
||||
|
||||
this.titlesPublic.titleNext = null;
|
||||
@@ -690,9 +793,11 @@ export class EventTimer extends Timer {
|
||||
titleNow: null,
|
||||
subtitleNow: null,
|
||||
presenterNow: null,
|
||||
noteNow: null,
|
||||
titleNext: null,
|
||||
subtitleNext: null,
|
||||
presenterNext: null,
|
||||
noteNext: null,
|
||||
};
|
||||
|
||||
this.publicTitles = {
|
||||
@@ -739,9 +844,11 @@ export class EventTimer extends Timer {
|
||||
Title Now = ${this.titles.titleNow}
|
||||
Subtitle Now = ${this.titles.subtitleNow}
|
||||
Presenter Now = ${this.titles.presenterNow}
|
||||
Note Now = ${this.titles.noteNow}
|
||||
Title Next = ${this.titles.titleNext}
|
||||
Subtitle Next = ${this.titles.subtitleNext}
|
||||
Presenter Next = ${this.titles.presenterNext}
|
||||
Note Next = ${this.titles.noteNext}
|
||||
|
||||
Public Titles
|
||||
------------------------------
|
||||
@@ -779,19 +886,31 @@ export class EventTimer extends Timer {
|
||||
}
|
||||
|
||||
start() {
|
||||
// if there is nothing selected, no nothing
|
||||
if (this.selectedEventId == null) return;
|
||||
|
||||
// call super
|
||||
super.start();
|
||||
|
||||
// broadcast current state
|
||||
this.broadcastState();
|
||||
|
||||
// send OSC
|
||||
this.sendOSC('play');
|
||||
}
|
||||
|
||||
pause() {
|
||||
// if there is nothing selected, no nothing
|
||||
if (this.selectedEventId == null) return;
|
||||
|
||||
// call super
|
||||
super.pause();
|
||||
|
||||
// broadcast current state
|
||||
this.broadcastState();
|
||||
|
||||
// send OSC
|
||||
this.sendOSC('pause');
|
||||
}
|
||||
|
||||
stop() {
|
||||
@@ -800,6 +919,9 @@ export class EventTimer extends Timer {
|
||||
|
||||
// broadcast current state
|
||||
this.broadcastState();
|
||||
|
||||
// send OSC
|
||||
this.sendOSC('stop');
|
||||
}
|
||||
|
||||
increment(amount) {
|
||||
@@ -893,6 +1015,9 @@ export class EventTimer extends Timer {
|
||||
return;
|
||||
}
|
||||
|
||||
// send OSC
|
||||
this.sendOSC('prev');
|
||||
|
||||
// change playstate
|
||||
this.pause();
|
||||
|
||||
@@ -913,6 +1038,9 @@ export class EventTimer extends Timer {
|
||||
return;
|
||||
}
|
||||
|
||||
// send OSC
|
||||
this.sendOSC('next');
|
||||
|
||||
// change playstate
|
||||
this.pause();
|
||||
|
||||
@@ -940,6 +1068,9 @@ export class EventTimer extends Timer {
|
||||
// reset playstate
|
||||
this.pause();
|
||||
|
||||
// send OSC
|
||||
this.sendOSC('reload');
|
||||
|
||||
// reload data
|
||||
this.loadEvent(this.selectedEventIndex);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import { stringFromMillis } from '../utils/time.js';
|
||||
|
||||
export class Timer {
|
||||
clock = null;
|
||||
duration = null;
|
||||
current = null;
|
||||
timeTag = null;
|
||||
secondaryTimer = null;
|
||||
_finishAt = null;
|
||||
_finishedAt = null;
|
||||
@@ -133,8 +136,12 @@ export class Timer {
|
||||
|
||||
// getObject
|
||||
getObject() {
|
||||
// update timer
|
||||
this.update();
|
||||
|
||||
// update timetag
|
||||
this.timeTag = stringFromMillis(this.current);
|
||||
|
||||
return {
|
||||
clock: this.clock,
|
||||
running: Timer.toSeconds(this.current),
|
||||
@@ -216,4 +223,4 @@ export class Timer {
|
||||
this._finishedAt = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export const config = {
|
||||
},
|
||||
osc: {
|
||||
port: 8888,
|
||||
portOut: 8889,
|
||||
ipOut: '127.0.0.1',
|
||||
portOut: 9999,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ export const initiateOSC = (config) => {
|
||||
if (address !== 'ontime') return;
|
||||
|
||||
// get second part (command)
|
||||
switch (path.toLocaleLowerCase()) {
|
||||
switch (path.toLowerCase()) {
|
||||
case 'start':
|
||||
case 'play':
|
||||
console.log('calling play');
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
block as blockDef,
|
||||
} from '../data/eventsDefinition.js';
|
||||
import { dbModel } from '../data/dataModel.js';
|
||||
import { networkInterfaces } from 'os';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -119,8 +120,14 @@ const upload = async (file, req, res) => {
|
||||
deleteFile(file);
|
||||
|
||||
// check version
|
||||
if (uploadedJson.settings.version === 1) parsev1(uploadedJson);
|
||||
else {
|
||||
if (uploadedJson.settings.version === 1) {
|
||||
try {
|
||||
parsev1(uploadedJson);
|
||||
global.timer.setupWithEventList(db.data.events);
|
||||
} catch (error) {
|
||||
res.status(400).send({ message: `Error parsing file: ${error}` });
|
||||
}
|
||||
} else {
|
||||
res.status(400).send({ message: 'Error parsing file, version unknown' });
|
||||
return;
|
||||
}
|
||||
@@ -132,6 +139,38 @@ const upload = async (file, req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Gets information on IPV4 non internal interfaces
|
||||
* @returns {array} - Array of objects {name: ip}
|
||||
*/
|
||||
const getNetworkInterfaces = () => {
|
||||
const nets = networkInterfaces();
|
||||
const results = [];
|
||||
|
||||
for (const name of Object.keys(nets)) {
|
||||
for (const net of nets[name]) {
|
||||
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
||||
if (net.family === 'IPv4' && !net.internal) {
|
||||
results.push({
|
||||
name: name,
|
||||
address: net.address,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
// Create controller for POST request to '/ontime/info'
|
||||
// Returns -
|
||||
// TODO: Add version
|
||||
export const getInfo = async (req, res) => {
|
||||
const ni = getNetworkInterfaces();
|
||||
res.status(200).send({
|
||||
networkInterfaces: ni,
|
||||
});
|
||||
};
|
||||
|
||||
// Create controller for POST request to '/ontime/db'
|
||||
// Returns -
|
||||
export const dbUpload = async (req, res) => {
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
"node-osc": "6.0.2",
|
||||
"passport": "~0.4.1",
|
||||
"passport-local": "~1.0.0",
|
||||
"socket.io": "^4.0.0"
|
||||
"socket.io": "^4.0.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"universal-analytics": "^0.4.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^7.26.0",
|
||||
|
||||
@@ -5,6 +5,7 @@ export const router = express.Router();
|
||||
import {
|
||||
dbDownload,
|
||||
dbUpload,
|
||||
getInfo,
|
||||
dbPathToUpload,
|
||||
} from '../controllers/ontimeController.js';
|
||||
|
||||
@@ -14,5 +15,8 @@ router.get('/db', dbDownload);
|
||||
// create route between controller and '/ontime/db' endpoint
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// get environment vars
|
||||
import 'dotenv/config.js';
|
||||
|
||||
import ua from 'universal-analytics';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export const sessionId = nanoid();
|
||||
export const user = ua(process.env.ANALYTICS_ID);
|
||||
|
||||
// Track session
|
||||
user.set('uid', sessionId);
|
||||
|
||||
// Allows filtering by the 'Application?' field in GA
|
||||
user.set('ds', 'app');
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @description Converts milliseconds to string representing time
|
||||
* @param {number} ms - time in milliseconds
|
||||
* @param {boolean} showSeconds - wether to show the seconds
|
||||
* @param {string} delim - character between HH MM SS
|
||||
* @param {string} ifNull - what to return if value is null
|
||||
* @returns {string} String representing time 00:12:02
|
||||
*/
|
||||
|
||||
export const stringFromMillis = (
|
||||
ms,
|
||||
showSeconds = true,
|
||||
delim = ':',
|
||||
ifNull = '...'
|
||||
) => {
|
||||
if (ms === null || isNaN(ms)) return ifNull;
|
||||
const isNegative = ms < 0 ? '-' : '';
|
||||
const millis = Math.abs(ms);
|
||||
|
||||
const showWith0 = (value) => (value < 10 ? `0${value}` : value);
|
||||
const hours = showWith0(Math.floor(((millis / (1000 * 60 * 60)) % 60) % 24));
|
||||
const minutes = showWith0(Math.floor((millis / (1000 * 60)) % 60));
|
||||
const seconds = showWith0(Math.floor((millis / 1000) % 60));
|
||||
|
||||
return showSeconds
|
||||
? `${isNegative}${
|
||||
parseInt(hours) ? `${hours}${delim}` : `00${delim}`
|
||||
}${minutes}${delim}${seconds}`
|
||||
: `${isNegative}${parseInt(hours) ? `${hours}` : '00'}${delim}${minutes}`;
|
||||
};
|
||||
+274
-6
@@ -96,7 +96,7 @@ acorn@^7.4.0:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
ajv@^6.10.0, ajv@^6.12.4:
|
||||
ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||
@@ -195,6 +195,18 @@ array.prototype.flatmap@^1.2.4:
|
||||
es-abstract "^1.18.0-next.1"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
ast-types-flow@^0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
|
||||
@@ -205,6 +217,21 @@ astral-regex@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
|
||||
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
|
||||
aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
axe-core@^4.0.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.2.2.tgz#0c987d82c8b82b4b9b7a945f1b5ef0d8fed586ed"
|
||||
@@ -230,6 +257,13 @@ base64id@2.0.0, base64id@~2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
|
||||
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
binpack@~0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/binpack/-/binpack-0.1.0.tgz#bd3d0974c3f2a0446e17df4f60b55a72a205a97e"
|
||||
@@ -290,6 +324,11 @@ callsites@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
||||
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
@@ -331,6 +370,13 @@ color-name@~1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
component-emitter@~1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
@@ -388,7 +434,7 @@ core-js-pure@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.14.0.tgz#72bcfacba74a65ffce04bf94ae91d966e80ee553"
|
||||
integrity sha512-YVh+LN2FgNU0odThzm61BsdkwrbrchumFq3oztnE9vTKC4KS2fvnPmcx8t6jnqAyOTCTF4ZSiuK8Qhh7SNcL4g==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
@@ -415,6 +461,13 @@ damerau-levenshtein@^1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d"
|
||||
integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==
|
||||
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
debug@2.6.9, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
@@ -448,6 +501,11 @@ define-properties@^1.1.3:
|
||||
dependencies:
|
||||
object-keys "^1.0.12"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
@@ -485,6 +543,19 @@ doctrine@^3.0.0:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dotenv@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
|
||||
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
@@ -853,6 +924,21 @@ express@~4.17.1:
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
|
||||
|
||||
extsprintf@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
@@ -908,6 +994,20 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
|
||||
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||
@@ -942,6 +1042,13 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
glob-parent@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
@@ -973,6 +1080,19 @@ graceful-fs@^4.1.2:
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
|
||||
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.1.3:
|
||||
version "5.1.5"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
|
||||
integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
|
||||
dependencies:
|
||||
ajv "^6.12.3"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
has-bigints@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
|
||||
@@ -1027,6 +1147,15 @@ http-errors@~1.7.2:
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
@@ -1165,6 +1294,11 @@ is-symbol@^1.0.2, is-symbol@^1.0.3:
|
||||
dependencies:
|
||||
has-symbols "^1.0.2"
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||
@@ -1180,6 +1314,11 @@ isexe@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
@@ -1193,6 +1332,11 @@ js-yaml@^3.13.1:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
json-parse-better-errors@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
||||
@@ -1208,11 +1352,21 @@ json-schema-traverse@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
|
||||
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
||||
|
||||
json-stable-stringify-without-jsonify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
|
||||
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
json5@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
|
||||
@@ -1220,6 +1374,16 @@ json5@^1.0.1:
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
|
||||
dependencies:
|
||||
assert-plus "1.0.0"
|
||||
extsprintf "1.3.0"
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82"
|
||||
@@ -1322,7 +1486,7 @@ mime-db@1.48.0:
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d"
|
||||
integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
|
||||
|
||||
mime-types@~2.1.24:
|
||||
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
|
||||
version "2.1.31"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b"
|
||||
integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
|
||||
@@ -1419,6 +1583,11 @@ normalize-package-data@^2.3.2:
|
||||
semver "2 || 3 || 4 || 5"
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
object-assign@^4, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@@ -1606,6 +1775,11 @@ pause@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d"
|
||||
integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
@@ -1657,7 +1831,12 @@ proxy-addr@~2.0.5:
|
||||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
punycode@^2.1.0:
|
||||
psl@^1.1.28:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
||||
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
@@ -1667,6 +1846,11 @@ qs@6.7.0:
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
random-bytes@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
|
||||
@@ -1750,6 +1934,32 @@ regexpp@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
|
||||
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
|
||||
|
||||
request@^2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-from-string@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
|
||||
@@ -1788,12 +1998,12 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@5.2.1:
|
||||
safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
@@ -1934,6 +2144,21 @@ sprintf-js@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
getpass "^0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.0.2"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
@@ -2053,6 +2278,14 @@ toidentifier@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
dependencies:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tsconfig-paths@^3.9.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
|
||||
@@ -2063,6 +2296,18 @@ tsconfig-paths@^3.9.0:
|
||||
minimist "^1.2.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||
@@ -2105,6 +2350,15 @@ unbox-primitive@^1.0.1:
|
||||
has-symbols "^1.0.2"
|
||||
which-boxed-primitive "^1.0.2"
|
||||
|
||||
universal-analytics@^0.4.23:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.23.tgz#d915e676850c25c4156762471bdd7cf2eaaca8ac"
|
||||
integrity sha512-lgMIH7XBI6OgYn1woDEmxhGdj8yDefMKg7GkWdeATAlQZFrMrNyxSkpDzY57iY0/6fdlzTbBV03OawvvzG+q7A==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
request "^2.88.2"
|
||||
uuid "^3.0.0"
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
@@ -2127,6 +2381,11 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||
|
||||
uuid@^3.0.0, uuid@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
@@ -2145,6 +2404,15 @@ vary@^1, vary@~1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
which-boxed-primitive@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
|
||||
|
||||
+2009
-95
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user