mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 12:28:21 +00:00
chore: more reporting
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { Controller, Get, NotFoundException, Param, Query, Res } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { CurrentUser } from '@edr/api-common';
|
||||
import type { Response } from 'express';
|
||||
import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type';
|
||||
@@ -12,13 +14,44 @@ import { ReportExportService } from './report-export.service';
|
||||
import { resolveExportCap, resolveExportColumns, resolveExportFormat } from './report-export-request.util';
|
||||
import { RawReportQuery, ReportRunnerService } from './report-runner.service';
|
||||
import { REPORTS, getReport } from './report.registry';
|
||||
import { ReportCatalogEntry, ReportDefinition } from './report.types';
|
||||
import { ReportCatalogEntry, ReportDefinition, ReportFilterOption } from './report.types';
|
||||
|
||||
const toCatalogEntry = (def: ReportDefinition): ReportCatalogEntry => {
|
||||
const { query: _query, summary, ...meta } = def;
|
||||
return { ...meta, hasSummary: Boolean(summary) };
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters whose choices are reference data resolve their options here rather
|
||||
* than declaring them inline, so the catalog the frontend receives looks the
|
||||
* same either way. Cached for the process lifetime — these are small, rarely
|
||||
* changing lists (23 stations, 18 cargo types), and the catalog is hit on
|
||||
* every page load.
|
||||
*/
|
||||
const optionsCache = new Map<string, ReportFilterOption[]>();
|
||||
|
||||
async function resolveFilterOptions(
|
||||
def: ReportCatalogEntry,
|
||||
ds: DataSource,
|
||||
): Promise<ReportCatalogEntry> {
|
||||
if (!def.filters.some((f) => f.optionsQuery)) return def;
|
||||
|
||||
const filters = await Promise.all(
|
||||
def.filters.map(async (filter) => {
|
||||
if (!filter.optionsQuery) return filter;
|
||||
let options = optionsCache.get(filter.key);
|
||||
if (!options) {
|
||||
options = await filter.optionsQuery(ds);
|
||||
optionsCache.set(filter.key, options);
|
||||
}
|
||||
// Drop the resolver itself — it is a function and would not serialise.
|
||||
const { optionsQuery: _resolver, ...rest } = filter;
|
||||
return { ...rest, options };
|
||||
}),
|
||||
);
|
||||
return { ...def, filters };
|
||||
}
|
||||
|
||||
@ApiTags('Reports')
|
||||
@ApiBearerAuth()
|
||||
@Controller('reports')
|
||||
@@ -28,14 +61,16 @@ export class ReportsController {
|
||||
private readonly runner: ReportRunnerService,
|
||||
private readonly exportService: ReportExportService,
|
||||
private readonly userTradeAccessService: UserTradeAccessService,
|
||||
@InjectDataSource() private readonly dataSource: DataSource,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'List reports the caller has permission to run' })
|
||||
async catalog(@CurrentUser() user: TCurrentUser): Promise<ReportCatalogEntry[]> {
|
||||
return REPORTS.filter((def) => hasFreightPermission(user, reportPermissionKey(def.key))).map(
|
||||
toCatalogEntry,
|
||||
);
|
||||
const allowed = REPORTS.filter((def) =>
|
||||
hasFreightPermission(user, reportPermissionKey(def.key)),
|
||||
).map(toCatalogEntry);
|
||||
return Promise.all(allowed.map((def) => resolveFilterOptions(def, this.dataSource)));
|
||||
}
|
||||
|
||||
@Get(':key')
|
||||
|
||||
Reference in New Issue
Block a user