mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-19 14:14:17 +00:00
refactor(report): finish via playback, one file per run
Uses the Finish the app already has, and stops rewriting the whole history every time a show ends. - The Go button already reads "Finish" on the last event and calls stop (playbackControl.utils). Closing the run hangs off that instead of a second Finish button of its own, so POST /report/runs/finish and the button in the overview are both gone. The run indicator stays as the way the feature is found, now a passive status that opens the reports panel. - Reports move from one file per project to a directory per project with one file per run. Finishing a show wrote the entire history back to disk, which grew with every show ever recorded; it now writes only the run that just ended. Deleting a run unlinks one file and deleting a project removes one directory. - A report that cannot be read is skipped instead of taking the rest of the history with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nr3FbLbM8gB8Jm771YgTV
This commit is contained in:
@@ -60,14 +60,6 @@ export async function fetchOpenRun(options?: RequestOptions): Promise<OpenRun |
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request to finish the run in progress, which is what writes it to history
|
||||
*/
|
||||
export async function finishRun(): Promise<void> {
|
||||
await axios.post(`${reportUrl}/runs/finish`);
|
||||
await ontimeQueryClient.invalidateQueries({ queryKey: REPORT });
|
||||
}
|
||||
|
||||
export async function renameRun(id: string, label: string): Promise<ShowRun> {
|
||||
const res = await axios.patch(`${reportUrl}/runs/${id}`, { label });
|
||||
await ontimeQueryClient.invalidateQueries({ queryKey: REPORT });
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
.indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
white-space: nowrap;
|
||||
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
font-size: calc(1rem - 3px);
|
||||
color: $label-gray;
|
||||
|
||||
&:hover {
|
||||
color: $ui-white;
|
||||
}
|
||||
}
|
||||
|
||||
.dot {
|
||||
|
||||
@@ -1,58 +1,39 @@
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
|
||||
import { finishRun } from '../../../common/api/report';
|
||||
import Button from '../../../common/components/buttons/Button';
|
||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||
import { useOpenRun } from '../../../common/hooks-query/useRuns';
|
||||
|
||||
import style from './RunIndicator.module.scss';
|
||||
|
||||
/**
|
||||
* Shows that a show report is being recorded, and lets the operator close it.
|
||||
* Shows that a report is being recorded for the show in progress.
|
||||
*
|
||||
* This is the feature's home in the editor: it appears only while a run is
|
||||
* open, so it stays out of the way until it is relevant, and finishing here
|
||||
* is what writes the run to history.
|
||||
* This is how the feature is discovered: it appears with the first event and
|
||||
* points at the reports panel. Ending the run is the existing Finish action
|
||||
* on the last event, so there is no separate control here.
|
||||
*/
|
||||
export default function RunIndicator() {
|
||||
const openRun = useOpenRun();
|
||||
const [isFinishing, setIsFinishing] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
if (!openRun) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleFinish = async () => {
|
||||
setIsFinishing(true);
|
||||
try {
|
||||
await finishRun();
|
||||
// take the user to the report they just made, which is also how most
|
||||
// people will discover that the history exists
|
||||
void navigate('/editor?settings=sharing__report');
|
||||
} catch (_error) {
|
||||
/** the run stays open, the user can try again */
|
||||
} finally {
|
||||
setIsFinishing(false);
|
||||
}
|
||||
};
|
||||
// startedAt is a wall clock instant, not a time of day, so formatTime does not apply
|
||||
const since = new Date(openRun.startedAt).toLocaleTimeString(undefined, { timeStyle: 'short' });
|
||||
|
||||
return (
|
||||
<div className={style.indicator}>
|
||||
<Tooltip text='A report is being recorded for this show' render={<span />}>
|
||||
<span className={style.label}>
|
||||
<span className={style.dot} />
|
||||
{/* startedAt is a wall clock instant, not a time of day, so it is not formatTime's job */}
|
||||
Recording since{' '}
|
||||
<span className={style.since}>
|
||||
{new Date(openRun.startedAt).toLocaleTimeString(undefined, { timeStyle: 'short' })}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Button size='small' variant='subtle' onClick={handleFinish} disabled={isFinishing}>
|
||||
Finish run
|
||||
</Button>
|
||||
</div>
|
||||
<Tooltip text='A report is being recorded. It is saved when you finish the show.' render={<span />}>
|
||||
<button
|
||||
type='button'
|
||||
className={style.indicator}
|
||||
onClick={() => navigate('/editor?settings=sharing__report')}
|
||||
aria-label='Show reports'
|
||||
>
|
||||
<span className={style.dot} />
|
||||
Recording since <span className={style.since}>{since}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user