UNPKG

@ministryofjustice/hmpps-digital-prison-reporting-frontend

Version:

The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.

233 lines (202 loc) 6.76 kB
import parseUrl from 'parseurl' import { Url } from 'url' import { Request } from 'express' import type { AsyncReportUtilsParams } from '../../../types/AsyncReportUtils' import { DashboardUIVisualisation, DashboardVisualisationType, ListVisualisation, type DashboardDefinition, type DashboardSection, type DashboardUISection, type DashboardVisualisation, } from './types' import type { DashboardDataResponse } from '../../../types/Metrics' import type { RequestedReport } from '../../../types/UserReports' import { ReportType } from '../../../types/UserReports' import type { components } from '../../../types/api' import ChartUtils from '../../_charts/utils' import DefinitionUtils from '../../../utils/definitionUtils' import UserReportsUtils from '../../user-reports/utils' import DashboardListUtils from '../dashboard-list/utils' import FilterUtils from '../../_filters/utils' import ScorecardsUtils from '../scorecard/utils' import ReportActionsUtils from '../../_reports/report-actions/utils' import ReportQuery from '../../../types/ReportQuery' import LocalsHelper from '../../../utils/localsHelper' import { Services } from '../../../types/Services' import { FilterValue } from '../../_filters/types' const setDashboardActions = ( dashboardDefinition: DashboardDefinition, reportDefinition: components['schemas']['ReportDefinitionSummary'], requestData: RequestedReport, ) => { const reportName = reportDefinition.name const { name } = dashboardDefinition const actionsUrl = requestData.url.request.fullUrl const { executionId } = requestData return ReportActionsUtils.getActions({ share: { reportName, name, url: actionsUrl, }, refresh: { url: actionsUrl, executionId, }, copy: { url: actionsUrl, }, }) } const getDefinitionData = async ({ req, res, services, next }: AsyncReportUtilsParams) => { const { token } = LocalsHelper.getValues(res) const { reportId, id } = req.params const { dataProductDefinitionsPath } = req.query // Dashboard Definition, const dashboardDefinition: DashboardDefinition = await services.dashboardService.getDefinition( token, id, reportId, dataProductDefinitionsPath, ) // Report summary data const reportDefinition = await DefinitionUtils.getReportSummary( reportId, services.reportingService, token, <string>dataProductDefinitionsPath, ) // Get the filters const filters = await FilterUtils.getFilters({ fields: dashboardDefinition.filterFields || [], req, interactive: true, }) // Create the query const query = new ReportQuery({ fields: dashboardDefinition.filterFields || [], queryParams: req.query, definitionsPath: <string>dataProductDefinitionsPath, }).toRecordWithFilterPrefix(true) return { query, filters, dashboardDefinition, reportDefinition, } } const getSections = ( dashboardDefinition: DashboardDefinition, dashboardData: DashboardDataResponse[], ): DashboardUISection[] => { return dashboardDefinition.sections.map((section: DashboardSection) => { const { id, display: title, description } = section let hasScorecard = false const visualisations = section.visualisations.map((visDefinition: DashboardVisualisation) => { const { type, display, description: visDescription, id: visId } = visDefinition let data: DashboardUIVisualisation['data'] switch (type) { case DashboardVisualisationType.LIST: data = DashboardListUtils.createList(visDefinition as ListVisualisation, dashboardData) break case DashboardVisualisationType.SCORECARD: hasScorecard = true data = ScorecardsUtils.createScorecard(visDefinition, dashboardData) break case DashboardVisualisationType.SCORECARD_GROUP: data = ScorecardsUtils.createScorecards(visDefinition, dashboardData) break case DashboardVisualisationType.BAR: case DashboardVisualisationType.LINE: case DashboardVisualisationType.BAR_TIMESERIES: case DashboardVisualisationType.LINE_TIMESERIES: case DashboardVisualisationType.DONUT: { data = ChartUtils.createChart(visDefinition, dashboardData) break } default: break } return { id: visId, title: display, description: visDescription, type, data, } }) if (hasScorecard) ScorecardsUtils.mergeScorecardsIntoGroup(visualisations) return { id, title, description, visualisations } }) } const updateStore = async ( services: Services, tableId: string, userId: string, sections: DashboardUISection[], url: Url, req: Request, filters: FilterValue[], ) => { const dashboardRequestData: RequestedReport = await services.requestedReportService.getReportByTableId( tableId, userId, ) // Add to recently viewed if (sections && sections.length && dashboardRequestData) { UserReportsUtils.updateLastViewed({ services, reportStateData: dashboardRequestData, userId, search: url.search, href: url.href, req, filters, }) } return dashboardRequestData } export default { renderAsyncDashboard: async ({ req, res, services, next }: AsyncReportUtilsParams) => { const { token, csrfToken, userId } = LocalsHelper.getValues(res) const { reportId, id, tableId } = req.params const url = parseUrl(req) // Get the definition Data const { query, filters, reportDefinition, dashboardDefinition } = await getDefinitionData({ req, res, services, }) // Get the results data const dashboardData: DashboardDataResponse[][] = await services.dashboardService.getAsyncDashboard( token, id, reportId, tableId, query, ) const flattenedData: DashboardDataResponse[] = dashboardData.flat() // Get the dashboard parts const sections: DashboardUISection[] = getSections(dashboardDefinition, flattenedData) // Update the store const dashboardRequestData = await updateStore(services, tableId, userId, sections, url, req, filters.filters) return { dashboardData: { token, id, reportId, name: dashboardDefinition.name, description: dashboardDefinition.description, reportName: reportDefinition.name, bookmarked: await services.bookmarkService.isBookmarked(id, reportId, userId), csrfToken, sections, filters, type: ReportType.DASHBOARD, actions: setDashboardActions(dashboardDefinition, reportDefinition, dashboardRequestData), }, } }, }