mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-17 13:23:35 +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:
@@ -0,0 +1,24 @@
|
||||
import PropTypes from "prop-types";
|
||||
import style from "../../../features/info/Info.module.scss";
|
||||
import {Icon} from "@chakra-ui/react";
|
||||
import {FiChevronUp} from "react-icons/fi";
|
||||
|
||||
export default function CollapseBar(props) {
|
||||
const {title = 'Collapse bar', isCollapsed = false, onClick}= props;
|
||||
|
||||
return(
|
||||
<div className={style.header}>
|
||||
{title}
|
||||
<Icon
|
||||
className={isCollapsed ? style.moreCollapsed : style.moreExpanded}
|
||||
as={FiChevronUp}
|
||||
onClick={onClick}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
CollapseBar.propTypes = {
|
||||
title: PropTypes.string,
|
||||
isCollapsed: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
.header,
|
||||
.header__roll {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
color: #ccc;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.header__roll {
|
||||
color: #2b6cb0;
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from 'react';
|
||||
import { LoggingContext } from '../../../app/context/LoggingContext';
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
static contextType = LoggingContext;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { error: null, errorInfo: null };
|
||||
@@ -17,15 +20,11 @@ class ErrorBoundary extends React.Component {
|
||||
errorInfo: info,
|
||||
});
|
||||
// TODO: Log the error to an error reporting service
|
||||
this.logErrorToServices(error.toString(), info.componentStack);
|
||||
this.context.emitError(error.toString());
|
||||
}
|
||||
|
||||
// A fake logging service.
|
||||
logErrorToServices = console.log;
|
||||
|
||||
render() {
|
||||
if (this.state.errorMessage) {
|
||||
// You can render any custom fallback UI
|
||||
return <p>:/</p>;
|
||||
}
|
||||
return this.props.children;
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import EditableTimer from 'common/input/EditableTimer';
|
||||
import { showWarningToast } from 'common/helpers/toastManager';
|
||||
import { useContext } from 'react';
|
||||
import { LoggingContext } from '../../../app/context/LoggingContext';
|
||||
|
||||
export default function EventTimes(props) {
|
||||
const { actionHandler, delay, timeStart, timeEnd } = props;
|
||||
const { emitWarning } = useContext(LoggingContext);
|
||||
|
||||
const handleValidate = (entry, v) => {
|
||||
// we dont inforce validation here
|
||||
// we dont enforce validation here
|
||||
|
||||
if (v == null || timeStart == null || timeEnd == null) return true;
|
||||
if (timeStart === 0) return true;
|
||||
|
||||
let validate = { value: true, catch: '' };
|
||||
if (entry === 'timeStart' && v > timeEnd)
|
||||
if (entry === 'timeStart' && v > timeEnd) {
|
||||
validate.catch = 'Start time later than end time';
|
||||
else if (entry === 'timeEnd' && v < timeStart)
|
||||
} else if (entry === 'timeEnd' && v < timeStart) {
|
||||
validate.catch = 'End time earlier than start time';
|
||||
}
|
||||
|
||||
if (validate.catch !== '')
|
||||
showWarningToast('Time Input Warning', validate.catch);
|
||||
emitWarning(`Time Input Warning: ${validate.catch}`);
|
||||
return validate.value;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import EditableTimer from 'common/input/EditableTimer';
|
||||
import { showWarningToast } from 'common/helpers/toastManager';
|
||||
import { stringFromMillis } from 'common/utils/dateConfig';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import { useContext } from 'react';
|
||||
import { LoggingContext } from '../../../app/context/LoggingContext';
|
||||
|
||||
const label = {
|
||||
fontSize: '0.75em',
|
||||
@@ -83,6 +84,8 @@ const Times = (props) => {
|
||||
|
||||
export default function EventTimesVertical(props) {
|
||||
const { delay, timeStart, timeEnd, duration } = props;
|
||||
const { emitWarning } = useContext(LoggingContext);
|
||||
|
||||
const handleValidate = (entry, v) => {
|
||||
// we dont enforce validation here
|
||||
|
||||
@@ -90,32 +93,36 @@ export default function EventTimesVertical(props) {
|
||||
if (timeStart === 0) return true;
|
||||
|
||||
let validate = { value: true, catch: '' };
|
||||
if (entry === 'timeStart' && v > timeEnd)
|
||||
if (entry === 'timeStart' && v > timeEnd) {
|
||||
validate.catch = 'Start time later than end time';
|
||||
else if (entry === 'timeEnd' && v < timeStart)
|
||||
} else if (entry === 'timeEnd' && v < timeStart) {
|
||||
validate.catch = 'End time earlier than start time';
|
||||
}
|
||||
|
||||
if (validate.catch !== '')
|
||||
showWarningToast('Time Input Warning', validate.catch);
|
||||
if (validate.catch !== '') {
|
||||
emitWarning(`Time Input Warning: ${validate.catch}`);
|
||||
}
|
||||
return validate.value;
|
||||
};
|
||||
|
||||
return (delay != null) & (delay > 0) ? (
|
||||
<TimesDelayed
|
||||
handleValidate={handleValidate}
|
||||
actionHandler={props.actionHandler}
|
||||
delay={delay}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
duration={duration}
|
||||
/>
|
||||
) : (
|
||||
<Times
|
||||
handleValidate={handleValidate}
|
||||
actionHandler={props.actionHandler}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
duration={duration}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
(delay != null) && (delay > 0) ? (
|
||||
<TimesDelayed
|
||||
handleValidate={handleValidate}
|
||||
actionHandler={props.actionHandler}
|
||||
delay={delay}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
duration={duration}
|
||||
/>
|
||||
) : (
|
||||
<Times
|
||||
handleValidate={handleValidate}
|
||||
actionHandler={props.actionHandler}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
duration={duration}
|
||||
/>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { stringFromMillis } from 'common/utils/dateConfig';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import style from './Paginator.module.css';
|
||||
export default function TodayItem(props) {
|
||||
const { selected, timeStart, timeEnd, title, backstageEvent } = props;
|
||||
@@ -19,7 +19,7 @@ export default function TodayItem(props) {
|
||||
}`}
|
||||
>{`${start} · ${end}`}</div>
|
||||
<div className={style.entryTitle}>{title}</div>
|
||||
{backstageEvent && <div className={style.backstageInd}></div>}
|
||||
{backstageEvent && <div className={style.backstageInd}/>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { createStandaloneToast } from '@chakra-ui/react';
|
||||
|
||||
const toast = createStandaloneToast();
|
||||
// const customToast = createStandaloneToast({ theme: yourCustomTheme })
|
||||
|
||||
// error toast
|
||||
export const showErrorToast = (title, description) => {
|
||||
toast({
|
||||
title: title,
|
||||
description: description,
|
||||
position: 'top-left',
|
||||
variant: 'subtle',
|
||||
status: 'error',
|
||||
isClosable: true,
|
||||
});
|
||||
};
|
||||
|
||||
// warning toast
|
||||
export const showWarningToast = (title, description) => {
|
||||
toast({
|
||||
title: title,
|
||||
description: description,
|
||||
position: 'top-left',
|
||||
variant: 'subtle',
|
||||
status: 'warning',
|
||||
isClosable: true,
|
||||
});
|
||||
};
|
||||
@@ -1,15 +1,16 @@
|
||||
import { Editable, EditableInput, EditablePreview } from '@chakra-ui/editable';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import {
|
||||
isTimeString,
|
||||
stringFromMillis,
|
||||
timeStringToMillis,
|
||||
} from '../utils/dateConfig';
|
||||
import { showErrorToast } from '../helpers/toastManager';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import style from './EditableTimer.module.css';
|
||||
import { LoggingContext } from '../../app/context/LoggingContext';
|
||||
|
||||
export default function EditableTimer(props) {
|
||||
const { name, actionHandler, time, delay, validate } = props;
|
||||
const { emitError } = useContext(LoggingContext);
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
// prepare time fields
|
||||
@@ -18,9 +19,9 @@ export default function EditableTimer(props) {
|
||||
try {
|
||||
setValue(stringFromMillis(time + delay));
|
||||
} catch (error) {
|
||||
showErrorToast('Error parsing date', error.text);
|
||||
emitError(`Unable to parse date: ${error.text}`);
|
||||
}
|
||||
}, [time, delay]);
|
||||
}, [time, delay, emitError]);
|
||||
|
||||
const validateValue = (value) => {
|
||||
const success = handleSubmit(value);
|
||||
|
||||
@@ -4,37 +4,7 @@ export const timeFormatSeconds = 'HH:mm:ss';
|
||||
const mts = 1000; // millis to seconds
|
||||
const mtm = 1000 * 60; // millis to minutes
|
||||
const mth = 1000 * 60 * 60; // millis to hours
|
||||
const mtd = 1000 * 60 * 60 * 24; // millis to days
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
// This is shared and tested in backend in time.js
|
||||
export const stringFromMillis = (
|
||||
ms,
|
||||
showSeconds = true,
|
||||
delim = ':',
|
||||
ifNull = '...'
|
||||
) => {
|
||||
if (ms === null || isNaN(ms)) return ifNull;
|
||||
const isNegative = ms < 0 ? '-' : '';
|
||||
const showWith0 = (value) => (value < 10 ? `0${value}` : value);
|
||||
const hours = showWith0(Math.floor(((ms / mth) % 60) % 24));
|
||||
const minutes = showWith0(Math.floor((ms / mtm) % 60));
|
||||
const seconds = showWith0(Math.floor((ms / mts) % 60));
|
||||
|
||||
return showSeconds
|
||||
? `${isNegative}${
|
||||
parseInt(hours) ? `${hours}${delim}` : `00${delim}`
|
||||
}${minutes}${delim}${seconds}`
|
||||
: `${isNegative}${parseInt(hours) ? `${hours}` : '00'}${delim}${minutes}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* another go at simpler string formatting (counters)
|
||||
@@ -79,7 +49,7 @@ export const millisToMinutes = (millis) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Converts timestring to milliseconds
|
||||
* @description Converts timestring to milliseconds
|
||||
* @param {string} string - time string "23:00:12"
|
||||
* @returns {number} Amount in milliseconds
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
|
||||
/**
|
||||
* @description From a list of events, returns only events of type event with calculated delays
|
||||
* @param {Object[]} events - given events
|
||||
* @returns {Object[]} Filtered events with calculated delays
|
||||
*/
|
||||
import {stringFromMillis} from "./dateConfig";
|
||||
|
||||
export const getEventsWithDelay = (events) => {
|
||||
|
||||
if (events == null) return [];
|
||||
|
||||
Reference in New Issue
Block a user