mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 14:39:06 +00:00
Report (#1469)
* create report service * write report from runtimeState * use in UI * clear report * update types * clear all from settings menu * rearence rightclik menu * refactor styling * also report roll events * ontime/under time is same colour * refactor reporter * add target to ontime-refetch * remove menu * fectch only on message from server * memo useGetEventReport * refactor * use staleTime * dont add to menu yet * implement review * clear all from menu * fix merge * start end show * combine test for the go button text and action * add report to menu * extract csv utility * report management * unneeded async * small refacort of triggerReportEntry --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me>
This commit is contained in:
committed by
GitHub
parent
21877e4bff
commit
b6507c27a6
@@ -22,7 +22,8 @@ export type EventItemActions =
|
||||
| 'delete'
|
||||
| 'clone'
|
||||
| 'update'
|
||||
| 'swap';
|
||||
| 'swap'
|
||||
| 'clear-report';
|
||||
|
||||
interface RundownEntryProps {
|
||||
type: SupportedEvent;
|
||||
|
||||
@@ -175,7 +175,7 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
},
|
||||
isDisabled: selectedEventId == null || selectedEventId === eventId,
|
||||
},
|
||||
{ withDivider: true, label: 'Clone', icon: IoDuplicateOutline, onClick: () => actionHandler('clone') },
|
||||
{ withDivider: false, label: 'Clone', icon: IoDuplicateOutline, onClick: () => actionHandler('clone') },
|
||||
{ withDivider: true, label: 'Delete', icon: IoTrash, onClick: () => actionHandler('delete') },
|
||||
],
|
||||
);
|
||||
|
||||
@@ -125,6 +125,7 @@ function EventBlockInner(props: EventBlockInnerProps) {
|
||||
isLoaded={loaded}
|
||||
totalGap={totalGap}
|
||||
isLinkedAndNext={isNext && linkStart !== null}
|
||||
duration={duration}
|
||||
/>
|
||||
)}
|
||||
<div className={style.statusElements} id='block-status' data-ispublic={isPublic}>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
border-radius: 2px;
|
||||
|
||||
&.over {
|
||||
color: $playback-negative;
|
||||
color: $ontime-delay-text;
|
||||
}
|
||||
|
||||
&.under {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { IoCheckmarkCircle } from '@react-icons/all-files/io5/IoCheckmarkCircle';
|
||||
import { isPlaybackActive, MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from 'ontime-utils';
|
||||
|
||||
import { usePlayback, useTimelineStatus } from '../../../../common/hooks/useSocket';
|
||||
import useReport from '../../../../common/hooks-query/useReport';
|
||||
import { cx } from '../../../../common/utils/styleUtils';
|
||||
import { formatDuration } from '../../../../common/utils/time';
|
||||
import { formatDuration, formatTime } from '../../../../common/utils/time';
|
||||
import { tooltipDelayFast } from '../../../../ontimeConfig';
|
||||
|
||||
import style from './EventBlockChip.module.scss';
|
||||
@@ -16,10 +19,11 @@ interface EventBlockChipProps {
|
||||
className: string;
|
||||
totalGap: number;
|
||||
isLinkedAndNext: boolean;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export default function EventBlockChip(props: EventBlockChipProps) {
|
||||
const { trueTimeStart, isPast, isLoaded, className, totalGap, isLinkedAndNext } = props;
|
||||
const { trueTimeStart, isPast, isLoaded, className, totalGap, isLinkedAndNext, id, duration } = props;
|
||||
const { playback } = usePlayback();
|
||||
|
||||
if (isLoaded) {
|
||||
@@ -29,7 +33,7 @@ export default function EventBlockChip(props: EventBlockChipProps) {
|
||||
const playbackActive = isPlaybackActive(playback);
|
||||
|
||||
if (!playbackActive || isPast) {
|
||||
return null; //TODO: Event report will go here
|
||||
return <EventReport className={className} id={id} duration={duration} />;
|
||||
}
|
||||
|
||||
if (playbackActive) {
|
||||
@@ -65,3 +69,55 @@ function EventUntil(props: EventUntilProps) {
|
||||
|
||||
return <div className={cx([style.chip, isDue && style.due])}>{timeUntilString}</div>;
|
||||
}
|
||||
|
||||
interface EventReportProps {
|
||||
className: string;
|
||||
id: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
function EventReport(props: EventReportProps) {
|
||||
const { className, id, duration } = props;
|
||||
const { data } = useReport();
|
||||
const currentReport = data[id];
|
||||
|
||||
const [value, overUnderStyle, tooltip] = useMemo(() => {
|
||||
if (!currentReport) {
|
||||
return [null, 'none', ''];
|
||||
}
|
||||
|
||||
const { startedAt, endedAt } = currentReport;
|
||||
if (!startedAt || !endedAt) {
|
||||
return [null, 'none', ''];
|
||||
}
|
||||
|
||||
const actualDuration = endedAt - startedAt;
|
||||
const difference = actualDuration - duration;
|
||||
const absDifference = Math.abs(difference);
|
||||
|
||||
if (absDifference < MILLIS_PER_SECOND) {
|
||||
return ['ontime', 'ontime', 'Event finished ontime'];
|
||||
}
|
||||
|
||||
const isOver = difference > 0;
|
||||
|
||||
const fullTimeValue = formatTime(absDifference);
|
||||
|
||||
const tooltip = `Event ran ${isOver ? 'over' : 'under'} time by ${fullTimeValue}`;
|
||||
|
||||
const value = `${isOver ? '+' : '-'}${formatDuration(absDifference, absDifference > 2 * MILLIS_PER_MINUTE)}`;
|
||||
return [value, isOver ? 'over' : 'under', tooltip];
|
||||
}, [currentReport, duration]);
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip label={tooltip} openDelay={tooltipDelayFast}>
|
||||
<div className={cx([style.chip, style[overUnderStyle], className])}>
|
||||
{value === 'ontime' ? <IoCheckmarkCircle size='1.1rem' /> : value}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user