* 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:
Alex Christoffer Rasmussen
2025-02-23 17:02:09 +01:00
committed by GitHub
parent 21877e4bff
commit b6507c27a6
35 changed files with 542 additions and 72 deletions
+2
View File
@@ -11,6 +11,7 @@ import { router as sheetsRouter } from './sheets/sheets.router.js';
import { router as excelRouter } from './excel/excel.router.js';
import { router as sessionRouter } from './session/session.router.js';
import { router as viewSettingsRouter } from './view-settings/viewSettings.router.js';
import { router as reportRouter } from './report/report.router.js';
export const appRouter = express.Router();
@@ -25,6 +26,7 @@ appRouter.use('/excel', excelRouter);
appRouter.use('/url-presets', urlPresetsRouter);
appRouter.use('/session', sessionRouter);
appRouter.use('/view-settings', viewSettingsRouter);
appRouter.use('/report', reportRouter);
//we don't want to redirect to react index when using api routes
appRouter.all('/*', (_req, res) => {
@@ -0,0 +1,18 @@
import type { Request, Response } from 'express';
import type { OntimeReport } from 'ontime-types';
import * as report from './report.service.js';
export function getAll(_req: Request, res: Response<OntimeReport>) {
res.json(report.generate());
}
export function deleteAll(_req: Request, res: Response<OntimeReport>) {
report.clear();
res.status(200).send();
}
export function deleteWithId(req: Request, res: Response<OntimeReport>) {
const { eventId } = req.params;
report.clear(eventId);
res.status(200).send();
}
@@ -0,0 +1,10 @@
import express from 'express';
import { getAll, deleteWithId, deleteAll } from './report.controller.js';
import { paramsMustHaveEventId } from '../rundown/rundown.validation.js';
export const router = express.Router();
router.get('/', getAll);
router.delete('/all', deleteAll);
router.delete('/:eventId', paramsMustHaveEventId, deleteWithId);
@@ -0,0 +1,65 @@
import { OntimeReport, OntimeEventReport, TimerLifeCycle } from 'ontime-types';
import { RuntimeState } from '../../stores/runtimeState.js';
import { sendRefetch } from '../../adapters/websocketAux.js';
import { DeepReadonly } from 'ts-essentials';
const report = new Map<string, OntimeEventReport>();
let formattedReport: OntimeReport | null = null;
/**
* generates a full report
* @returns full report
*/
export function generate(): OntimeReport {
if (formattedReport === null) {
formattedReport = Object.fromEntries(report);
}
return formattedReport;
}
/**
* clear report
* @param id optional id of a event report to clear
*/
export function clear(id?: string) {
formattedReport = null;
if (id) {
report.delete(id);
} else {
report.clear();
}
}
/**
* trigger report entry
* @param cycle
* @param state
* @returns
*/
export function triggerReportEntry(
cycle: TimerLifeCycle.onStart | TimerLifeCycle.onStop,
state: DeepReadonly<RuntimeState>,
) {
if (!state.eventNow?.id) {
return;
}
const eventId = state.eventNow.id;
if (cycle === TimerLifeCycle.onStart) {
report.set(eventId, { startedAt: state.timer.startedAt, endedAt: null });
formattedReport = null;
return;
}
if (cycle === TimerLifeCycle.onStop) {
const startedAt = report.get(eventId)?.startedAt ?? null;
report.set(eventId, { startedAt, endedAt: state.clock });
formattedReport = null;
sendRefetch({
target: 'REPORT',
});
return;
}
}