mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-17 05:13:32 +00:00
Feat/62 logger (#79)
* feat/62-logger request log data in app * feat/62-logger refact osc integration * feat/62-logger feedback on osc * feat/62-logger refact broadcast on triggers * feat/62-logger log triggers * feat/62-logger add link to studio * feat/62-logger replace toasts with logger context * feat/62-logger style improvements * feat/62-logger refactor code duplications * feat/62-logger cleanup and version bump
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import style from './PlaybackControl.module.scss';
|
||||
import Countdown from 'common/components/countdown/Countdown';
|
||||
import {stringFromMillis} from 'common/utils/dateConfig';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import {Tooltip} from '@chakra-ui/react';
|
||||
import {Button} from '@chakra-ui/button';
|
||||
import {memo} from 'react';
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { lazy, useEffect } from 'react';
|
||||
import { Box } from '@chakra-ui/layout';
|
||||
import { useDisclosure } from '@chakra-ui/hooks';
|
||||
import styles from './Editor.module.css';
|
||||
import styles from './Editor.module.scss';
|
||||
import MenuBar from 'features/menu/MenuBar';
|
||||
import ModalManager from 'features/modals/ModalManager';
|
||||
import ErrorBoundary from 'common/components/errorBoundary/ErrorBoundary';
|
||||
import { LoggingProvider } from '../../app/context/LoggingContext';
|
||||
|
||||
const EventListWrapper = lazy(() =>
|
||||
import('features/editors/list/EventListWrapper')
|
||||
@@ -22,7 +23,7 @@ export default function Editor() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<LoggingProvider>
|
||||
<ModalManager isOpen={isOpen} onClose={onClose} />
|
||||
|
||||
<div className={styles.mainContainer}>
|
||||
@@ -68,6 +69,6 @@ export default function Editor() {
|
||||
</div>
|
||||
</Box>
|
||||
</div>
|
||||
</>
|
||||
</LoggingProvider>
|
||||
);
|
||||
}
|
||||
|
||||
+13
-2
@@ -8,7 +8,7 @@
|
||||
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-columns: 40px 48em auto auto;
|
||||
grid-template-columns: 40px 48em 31em auto;
|
||||
grid-template-areas:
|
||||
'sett even play info'
|
||||
'sett even mess info';
|
||||
@@ -110,12 +110,23 @@ h1 {
|
||||
|
||||
.editor {
|
||||
grid-area: even;
|
||||
|
||||
.content {
|
||||
height: calc(100% - 3em);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
grid-area: info;
|
||||
min-width: 17em;
|
||||
max-width: 32em;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% - 3em);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.messages {
|
||||
@@ -1,4 +1,4 @@
|
||||
import style from './List.module.css';
|
||||
import style from './List.module.scss';
|
||||
import { createRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useSocket } from 'app/context/socketContext';
|
||||
import Empty from 'common/state/Empty';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import DelayBlock from './DelayBlock';
|
||||
import BlockBlock from './BlockBlock';
|
||||
import EventBlock from './EventBlock';
|
||||
import { showErrorToast } from 'common/helpers/toastManager';
|
||||
import { memo } from 'react';
|
||||
import { memo, useContext } from 'react';
|
||||
import { LoggingContext } from '../../../app/context/LoggingContext';
|
||||
|
||||
const areEqual = (prevProps, nextProps) => {
|
||||
return (
|
||||
@@ -26,6 +26,7 @@ const EventListItem = (props) => {
|
||||
delay,
|
||||
...rest
|
||||
} = props;
|
||||
const { emitError } = useContext(LoggingContext);
|
||||
|
||||
// Create / delete new events
|
||||
const actionHandler = (action, payload) => {
|
||||
@@ -59,7 +60,7 @@ const EventListItem = (props) => {
|
||||
// request update in parent
|
||||
eventsHandler('patch', newData);
|
||||
} else {
|
||||
showErrorToast('Field Error: ' + field);
|
||||
emitError(`Unknown field: ${field}`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import {
|
||||
fetchAllEvents,
|
||||
requestPatch,
|
||||
@@ -12,16 +12,17 @@ import {
|
||||
} from 'app/api/eventsApi.js';
|
||||
import EventList from './EventList';
|
||||
import EventListMenu from 'features/menu/EventListMenu.jsx';
|
||||
import { showErrorToast } from 'common/helpers/toastManager';
|
||||
import { useFetch } from 'app/hooks/useFetch.js';
|
||||
import Empty from 'common/state/Empty';
|
||||
import { EVENTS_TABLE } from 'app/api/apiConstants';
|
||||
import { BatchOperation } from 'app/context/collapseAtom';
|
||||
import { useAtom } from 'jotai';
|
||||
import { LoggingContext } from '../../../app/context/LoggingContext';
|
||||
|
||||
export default function EventListWrapper() {
|
||||
const [, setCollapsed] = useAtom(BatchOperation);
|
||||
const queryClient = useQueryClient();
|
||||
const { emitError } = useContext(LoggingContext);
|
||||
const { data, status, isError, refetch } = useFetch(
|
||||
EVENTS_TABLE,
|
||||
fetchAllEvents
|
||||
@@ -230,9 +231,9 @@ export default function EventListWrapper() {
|
||||
// Show toasts on errors
|
||||
useEffect(() => {
|
||||
if (isError) {
|
||||
showErrorToast('Error fetching data');
|
||||
emitError('Error fetching data');
|
||||
}
|
||||
}, [isError]);
|
||||
}, [emitError, isError]);
|
||||
|
||||
// Events API
|
||||
const eventsHandler = useCallback(
|
||||
@@ -242,35 +243,35 @@ export default function EventListWrapper() {
|
||||
try {
|
||||
await addEvent.mutateAsync(payload);
|
||||
} catch (error) {
|
||||
showErrorToast('Error creating event', error.message);
|
||||
emitError(`Error fetching data: ${error.message}`);
|
||||
}
|
||||
break;
|
||||
case 'update':
|
||||
try {
|
||||
await updateEvent.mutateAsync(payload);
|
||||
} catch (error) {
|
||||
showErrorToast('Error updating event', error.message);
|
||||
emitError(`Error updating event: ${error.message}`);
|
||||
}
|
||||
break;
|
||||
case 'patch':
|
||||
try {
|
||||
await patchEvent.mutateAsync(payload);
|
||||
} catch (error) {
|
||||
showErrorToast('Error updating event', error.message);
|
||||
emitError(`Error updating event: ${error.message}`);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
try {
|
||||
await deleteEvent.mutateAsync(payload);
|
||||
} catch (error) {
|
||||
showErrorToast('Error deleting event', error.message);
|
||||
emitError(`Error deleting event: ${error.message}`);
|
||||
}
|
||||
break;
|
||||
case 'reorder':
|
||||
try {
|
||||
await reorderEvent.mutateAsync(payload);
|
||||
} catch (error) {
|
||||
showErrorToast('Error reordering event', error.message);
|
||||
emitError(`Error re-ordering event: ${error.message}`);
|
||||
}
|
||||
break;
|
||||
case 'applyDelay':
|
||||
@@ -293,13 +294,13 @@ export default function EventListWrapper() {
|
||||
// delete block after, if any
|
||||
if (blockAfter) await deleteEvent.mutateAsync(blockAfter);
|
||||
} catch (error) {
|
||||
showErrorToast('Error applying delay', error.message);
|
||||
emitError(`Error applying delay: ${error.message}`);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await applyDelay.mutateAsync(payload.id);
|
||||
} catch (error) {
|
||||
showErrorToast('Error applying delay', error.message);
|
||||
emitError(`Error applying delay: ${error.message}`);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -317,11 +318,11 @@ export default function EventListWrapper() {
|
||||
try {
|
||||
await deleteAllEvents.mutateAsync();
|
||||
} catch (error) {
|
||||
showErrorToast('Error deleting events', error.message);
|
||||
emitError(`Error deleting events: ${error.message}`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
showErrorToast('Unrecognised request', action);
|
||||
emitError(`Unhandled request: ${action}`);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
overflow-y: scroll;
|
||||
height: 73vh;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.list {
|
||||
@@ -15,11 +15,10 @@ export default function Info() {
|
||||
titleNext: '',
|
||||
subtitleNext: '',
|
||||
presenterNext: '',
|
||||
noteNext: '',
|
||||
noteNext: ''
|
||||
});
|
||||
const [selected, setSelected] = useState('No events');
|
||||
const [playback, setPlayback] = useState(null);
|
||||
const logData = [];
|
||||
|
||||
// handle incoming messages
|
||||
useEffect(() => {
|
||||
@@ -61,20 +60,19 @@ export default function Info() {
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
// TODO: Put this in use effect
|
||||
// prepare data
|
||||
const titlesNow = {
|
||||
title: titles.titleNow,
|
||||
subtitle: titles.subtitleNow,
|
||||
presenter: titles.presenterNow,
|
||||
note: titles.noteNow,
|
||||
note: titles.noteNow
|
||||
};
|
||||
|
||||
const titlesNext = {
|
||||
title: titles.titleNext,
|
||||
subtitle: titles.subtitleNext,
|
||||
presenter: titles.presenterNext,
|
||||
note: titles.noteNext,
|
||||
note: titles.noteNext
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -83,10 +81,10 @@ export default function Info() {
|
||||
<span>{`Running on port 4001`}</span>
|
||||
<span>{selected}</span>
|
||||
</div>
|
||||
{/* <InfoLogger logData={logData} /> */}
|
||||
<InfoNif />
|
||||
<InfoTitle title={'Now'} data={titlesNow} roll={playback === 'roll'} />
|
||||
<InfoTitle title={'Next'} data={titlesNext} roll={playback === 'roll'} />
|
||||
<InfoLogger />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
.container {
|
||||
@use '../../main' as *;
|
||||
|
||||
@mixin container {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -8,9 +10,13 @@
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@include container;
|
||||
}
|
||||
|
||||
.main {
|
||||
font-size: 0.9em;
|
||||
color: #ff7597;
|
||||
color: $ontime-pink;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -20,17 +26,17 @@
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
color: #ccc;
|
||||
color: $header-gray;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: #ccc;
|
||||
color: $header-gray;
|
||||
}
|
||||
|
||||
.headerRoll {
|
||||
color: #2b6cb0;
|
||||
color: $ontime-roll;
|
||||
}
|
||||
|
||||
.collapsedTitle {
|
||||
@@ -57,7 +63,7 @@
|
||||
|
||||
.label {
|
||||
font-size: 0.9em;
|
||||
color: #aaa;
|
||||
color: $label-gray;
|
||||
}
|
||||
|
||||
.label::after {
|
||||
@@ -70,43 +76,22 @@
|
||||
}
|
||||
|
||||
.notes {
|
||||
color: #d69e2e;
|
||||
color: $notes-color;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.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;
|
||||
color: $ontime-accent;
|
||||
@include container-bg;
|
||||
}
|
||||
|
||||
.log {
|
||||
overflow-y: scroll;
|
||||
height: 30vh;
|
||||
|
||||
ul > li {
|
||||
font-size: 0.9em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.info {
|
||||
ul > li {
|
||||
font-size: 0.9em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.client {
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.moreExpanded,
|
||||
.moreCollapsed {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,34 +1,117 @@
|
||||
import { Icon } from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import { FiChevronUp } from 'react-icons/fi';
|
||||
import style from './Info.module.scss';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import style from './InfoLogger.module.scss';
|
||||
import CollapseBar from "../../common/components/collapseBar/CollapseBar";
|
||||
import { LoggingContext } from '../../app/context/LoggingContext';
|
||||
|
||||
export default function InfoLogger(props) {
|
||||
export default function InfoLogger() {
|
||||
const { logData, clearLog } = useContext(LoggingContext);
|
||||
const [data, setData] = useState([]);
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
// Todo: save in local storage
|
||||
const [showClient, setShowClient] = useState(true);
|
||||
const [showServer, setShowServer] = useState(true);
|
||||
const [showRx, setShowRx] = useState(true);
|
||||
const [showTx, setShowTx] = useState(true);
|
||||
const [showPlayback, setShowPlayback] = useState(true);
|
||||
const [showUser, setShowUser] = useState(true);
|
||||
|
||||
const { logData } = props;
|
||||
useEffect(() => {
|
||||
const matchers = [];
|
||||
if (showUser) {
|
||||
matchers.push('USER');
|
||||
}
|
||||
if (showClient) {
|
||||
matchers.push('CLIENT');
|
||||
}
|
||||
if (showServer) {
|
||||
matchers.push('SERVER');
|
||||
}
|
||||
if (showRx) {
|
||||
matchers.push('RX');
|
||||
}
|
||||
if (showTx) {
|
||||
matchers.push('TX');
|
||||
}
|
||||
if (showPlayback) {
|
||||
matchers.push('PLAYBACK');
|
||||
}
|
||||
|
||||
const d = logData.filter((d) => (
|
||||
matchers.some((m) => d.origin === m)
|
||||
))
|
||||
|
||||
setData(d);
|
||||
},[logData, showUser, showClient, showServer, showPlayback, showRx, showTx])
|
||||
|
||||
const disableOthers = (toEnable) => {
|
||||
toEnable === 'USER' ? setShowUser(true) : setShowUser(false);
|
||||
toEnable === 'CLIENT' ? setShowClient(true) : setShowClient(false);
|
||||
toEnable === 'SERVER' ? setShowServer(true) : setShowServer(false);
|
||||
toEnable === 'RX' ? setShowRx(true) : setShowRx(false);
|
||||
toEnable === 'TX' ? setShowTx(true) : setShowTx(false);
|
||||
toEnable === 'PLAYBACK' ? setShowPlayback(true) : setShowPlayback(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<div className={style.header}>
|
||||
Log
|
||||
<Icon
|
||||
className={collapsed ? style.moreCollapsed : style.moreExpanded}
|
||||
as={FiChevronUp}
|
||||
onClick={() => setCollapsed((c) => !c)}
|
||||
/>
|
||||
</div>
|
||||
<div className={collapsed ? style.container : style.container__expanded}>
|
||||
<CollapseBar title={'Log'} isCollapsed={collapsed} onClick={() => setCollapsed((c) => !c)}/>
|
||||
{!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 className={style.toggleBar}>
|
||||
<div
|
||||
onClick={() => setShowUser((s) => !s)}
|
||||
onAuxClick={() => disableOthers('USER')}
|
||||
className={(showUser) ? style.active : null}>
|
||||
USER
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setShowClient((s) => !s)}
|
||||
onAuxClick={() => disableOthers('CLIENT')}
|
||||
className={(showClient) ? style.active : null}>
|
||||
CLIENT
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setShowServer((s) => !s)}
|
||||
onAuxClick={() => disableOthers('SERVER')}
|
||||
className={(showServer) ? style.active : null}>
|
||||
SERVER
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setShowPlayback((s) => !s)}
|
||||
onAuxClick={() => disableOthers('PLAYBACK')}
|
||||
className={(showPlayback) ? style.active : null}>
|
||||
Playback
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setShowRx((s) => !s)}
|
||||
onAuxClick={() => disableOthers('RX')}
|
||||
className={(showRx) ? style.active : null}>
|
||||
RX
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setShowTx((s) => !s)}
|
||||
onAuxClick={() => disableOthers('TX')}
|
||||
className={(showTx) ? style.active : null}>
|
||||
TX
|
||||
</div>
|
||||
<div
|
||||
onClick={clearLog}
|
||||
className={style.clear}>
|
||||
Clear
|
||||
</div>
|
||||
</div>
|
||||
<ul className={style.log}>
|
||||
{data.map((d) => (
|
||||
<li key={d.id} className={d.level === 'INFO' ? style.info : d.level === 'WARN' ? style.warn : d.level === 'ERROR' ? style.error : ''}>
|
||||
<div
|
||||
className={style.time}
|
||||
>{d.time}</div>
|
||||
<div className={style.origin}>{d.origin}</div>
|
||||
<div className={style.msg}>{d.text}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
@use 'Info.module' as *;
|
||||
@use '../../main' as *;
|
||||
|
||||
.container,
|
||||
.container__expanded{
|
||||
@include container;
|
||||
max-height: 80%;
|
||||
}
|
||||
|
||||
.container__expanded {
|
||||
min-height: 50%;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
.log {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
font-size: 0.8em;
|
||||
user-select:text;
|
||||
@include container-bg;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
margin-bottom: 2px;
|
||||
|
||||
.time {
|
||||
width: 13%;
|
||||
}
|
||||
.origin {
|
||||
width: 18%;
|
||||
}
|
||||
.msg {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
li.info {
|
||||
color: #aaa;
|
||||
}
|
||||
li.warn {
|
||||
color: #dd6b20;
|
||||
}
|
||||
li.error {
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.entry:hover {
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.info {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.client {
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.toggleBar {
|
||||
display: flex;
|
||||
font-size: 0.7em;
|
||||
justify-content: flex-start;
|
||||
gap: 1em;
|
||||
padding: 0.5em 0;
|
||||
font-weight: 600;
|
||||
|
||||
div {
|
||||
padding: 2px 8px;
|
||||
background: #0002;
|
||||
border: 1px solid #fff1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.active {
|
||||
background: $ontime-accent;
|
||||
color: darken($ontime-accent, 70%);
|
||||
}
|
||||
|
||||
.clear {
|
||||
border: 1px solid rgba($ontime-pink, 0.5);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
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.scss';
|
||||
import CollapseBar from '../../common/components/collapseBar/CollapseBar';
|
||||
|
||||
export default function InfoNif() {
|
||||
const { data, status } = useFetch(APP_TABLE, getInfo, {
|
||||
@@ -22,16 +21,8 @@ export default function InfoNif() {
|
||||
};
|
||||
|
||||
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>
|
||||
|
||||
<div className={style.container}>
|
||||
<CollapseBar title={'Network Info'} isCollapsed={collapsed} onClick={() => setCollapsed((c) => !c)}/>
|
||||
{!collapsed && (
|
||||
<div>
|
||||
{status === 'success' && (
|
||||
|
||||
@@ -9,10 +9,12 @@ 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';
|
||||
import { useContext, useRef } from 'react';
|
||||
import { LoggingContext } from '../../app/context/LoggingContext';
|
||||
|
||||
export default function MenuBar(props) {
|
||||
const { onOpen } = props;
|
||||
const { emitError } = useContext(LoggingContext);
|
||||
const hiddenFileInput = useRef(null);
|
||||
const queryClient = useQueryClient();
|
||||
const uploaddb = useMutation(uploadEvents, {
|
||||
@@ -34,28 +36,24 @@ export default function MenuBar(props) {
|
||||
const handleUpload = (event) => {
|
||||
const fileUploaded = event.target.files[0];
|
||||
if (fileUploaded == null) return;
|
||||
console.log(fileUploaded);
|
||||
|
||||
// Limit file size to 1MB
|
||||
if (fileUploaded.size > 1000000) {
|
||||
console.log('Error: File size limit (1MB) exceeded');
|
||||
emitError('Error: File size limit (1MB) exceeded')
|
||||
return;
|
||||
}
|
||||
|
||||
// Check file extension
|
||||
if (fileUploaded.name.endsWith('.xlsx')) {
|
||||
console.log('excel file');
|
||||
} else if (fileUploaded.name.endsWith('.json')) {
|
||||
console.log('json file');
|
||||
} else {
|
||||
console.log('Error: File type unknown');
|
||||
if (! fileUploaded.name.endsWith('.xlsx')
|
||||
|| !fileUploaded.name.endsWith('.json')) {
|
||||
emitError('Error: File type unknown')
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
uploaddb.mutate(fileUploaded);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
emitError(`Failed uploading file: ${error}`)
|
||||
}
|
||||
|
||||
// reset input value
|
||||
|
||||
@@ -23,6 +23,7 @@ export default function AliasesModal() {
|
||||
const smLink = 'http://localhost:4001/sm';
|
||||
const publicLink = 'http://localhost:4001/public';
|
||||
const pipLink = 'http://localhost:4001/pip';
|
||||
const studioLink = 'http://localhost:4001/studio';
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -81,6 +82,17 @@ export default function AliasesModal() {
|
||||
{pipLink}
|
||||
</a>
|
||||
</p>
|
||||
<p className={style.flexNote}>
|
||||
Studio Clock<br />
|
||||
<a
|
||||
href={studioLink}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
className={style.label}
|
||||
>
|
||||
{studioLink}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<span>Manage custom aliases</span>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { ModalBody } from '@chakra-ui/modal';
|
||||
import { FormLabel, FormControl, Input, Button } from '@chakra-ui/react';
|
||||
import { getOSC, oscPlaceholderSettings, postOSC } from 'app/api/ontimeApi';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useFetch } from 'app/hooks/useFetch';
|
||||
import { OSC_SETTINGS } from 'app/api/apiConstants';
|
||||
import { showErrorToast } from 'common/helpers/toastManager';
|
||||
import style from './Modals.module.scss';
|
||||
import { LoggingContext } from '../../app/context/LoggingContext';
|
||||
|
||||
export default function AppSettingsModal() {
|
||||
const { data, status } = useFetch(OSC_SETTINGS, getOSC);
|
||||
const { emitError } = useContext(LoggingContext);
|
||||
const [formData, setFormData] = useState(oscPlaceholderSettings);
|
||||
const [changed, setChanged] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
@@ -41,7 +42,7 @@ export default function AppSettingsModal() {
|
||||
|
||||
// set fields with error
|
||||
if (e.status) {
|
||||
showErrorToast('Invalid Input', e.message);
|
||||
emitError(`Invalid Input: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,15 @@ import {
|
||||
ontimeVars,
|
||||
postInfo,
|
||||
} from 'app/api/ontimeApi';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useFetch } from 'app/hooks/useFetch';
|
||||
import { APP_TABLE } from 'app/api/apiConstants';
|
||||
import { showErrorToast } from 'common/helpers/toastManager';
|
||||
import style from './Modals.module.scss';
|
||||
import { LoggingContext } from '../../app/context/LoggingContext';
|
||||
|
||||
export default function IntegrationSettingsModal() {
|
||||
const { data, status } = useFetch(APP_TABLE, getInfo);
|
||||
const { emitError } = useContext(LoggingContext);
|
||||
const [formData, setFormData] = useState(httpPlaceholder);
|
||||
const [changed, setChanged] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
@@ -51,7 +52,7 @@ export default function IntegrationSettingsModal() {
|
||||
|
||||
// set fields with error
|
||||
if (e.status) {
|
||||
showErrorToast('Invalid Input', e.message);
|
||||
emitError(`Invalid Input: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
||||
import { fetchAllEvents } from 'app/api/eventsApi';
|
||||
import { fetchEvent } from 'app/api/eventApi';
|
||||
import { useSocket } from 'app/context/socketContext';
|
||||
import { stringFromMillis } from 'common/utils/dateConfig';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import { useFetch } from 'app/hooks/useFetch';
|
||||
import { EVENTS_TABLE, EVENT_TABLE } from 'app/api/apiConstants';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user