@ministryofjustice/hmpps-digital-prison-reporting-frontend
Version:
The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.
177 lines (174 loc) • 6.15 kB
JavaScript
import localsHelper from '../../../utils/localsHelper.js';
import logger from '../../../utils/logger.js';
import { getActiveJourneyValue } from '../../../utils/sessionHelper.js';
import { qsToQueryObject } from '../../../utils/queryMappers.js';
import { validateDefinition, getFields, getField } from '../../../utils/definitionUtils.js';
/**
* Streams the download for an Async repoort
*
* @param {({
* services: Services
* token: string
* tableId: string
* reportId: string
* id: string
* queryParams: Record<string, string | string[]>
* res: Response
* })} args
* @return {*}
*/
const streamDownloadAsyncData = async (args) => {
const { token, services, tableId, reportId, id, queryParams, res } = args;
return services.reportingService.downloadAsyncReport(token, reportId, id, tableId, queryParams, res);
};
/**
* Streams the download for a sync report
*
* @param {({
* definition: components['schemas']['SingleVariantReportDefinition']
* services: Services
* token: string
* queryParams: Record<string, string | string[]>
* res: Response
* })} args
* @return {*}
*/
const streamDownloadSyncData = async (args) => {
const { token, services, queryParams, definition, res } = args;
const { variant } = validateDefinition(definition);
const { resourceName } = variant;
return services.reportingService.downloadSyncReport(token, resourceName, queryParams, res);
};
/**
* Downloads the report
*
* @param {{
* req: Request
* services: Services
* res: Response
* redirect: string
* }} {
* req,
* services,
* res,
* redirect,
* }
*/
const downloadReport = async ({ req, services, res }) => {
const { reportId, id, tableId } = req.params;
const { token, definitionsPath: dataProductDefinitionsPath } = localsHelper.getValues(res);
const definition = await services.reportingService.getDefinition(token, reportId, id, dataProductDefinitionsPath);
const queryParams = setQueryForDownload(req, definition, dataProductDefinitionsPath);
logger.info(`Initiating streaming...`);
if (!tableId) {
await streamDownloadSyncData({
definition,
services,
token,
queryParams,
res,
});
}
else {
await streamDownloadAsyncData({
services,
token,
reportId,
id,
tableId,
queryParams,
res,
});
}
};
/**
* Initialises the download config in the UI
*
* @param {Response} res
* @param {Request} req
* @param {ExtractedDefinitionData} definitionData
* @param {LoadType} loadType
* @param {ExtractedRequestData} [requestData]
* @return {*} {(DownloadActionParams | undefined)}
*/
const setUpDownload = (res, req) => {
const { downloadingEnabled } = localsHelper.getValues(res);
let downloadConfig;
if (downloadingEnabled) {
const { tableId, id, reportId } = req.params;
const { csrfToken } = localsHelper.getValues(res);
const { downloadActionEndpoint } = localsHelper.getRouteLocals(res);
const downloadEnabledForReport = getActiveJourneyValue(req, { id, reportId }, 'downloadEnabled');
const formaction = tableId
? `${downloadActionEndpoint}${reportId}/${id}/tableId/${tableId}`
: `${downloadActionEndpoint}${reportId}/${id}`;
return {
enabled: downloadingEnabled,
formAction: formaction,
canDownload: Boolean(downloadEnabledForReport),
csrfToken,
};
}
return downloadConfig;
};
/**
* Sets the query for the download API request
*
* @param {string} currentReportSearch
* @param {components['schemas']['SingleVariantReportDefinition']} definition
* @return {*}
*/
const setQueryForDownload = (req, definition, dataProductDefinitionsPath) => {
const { reportId, id, tableId } = req.params;
const sessionKey = tableId ? { reportId, id, tableId } : { reportId, id };
const currentReportSearch = getActiveJourneyValue(req, sessionKey, 'currentReportSearch') || '';
// Filters query
const filtersQuery = qsToQueryObject(currentReportSearch, 'filters.');
// Sort query
let sortQuery = qsToQueryObject(currentReportSearch, 'sort');
if (!sortQuery || Object.keys(sortQuery).length === 0) {
// Fall back to default
const defaultSortQueryString = getActiveJourneyValue(req, sessionKey, 'defaultSortQueryString') || '';
sortQuery = qsToQueryObject(defaultSortQueryString, 'sort');
}
// Columns
const columnsQuery = qsToQueryObject(currentReportSearch, 'columns');
const validColumnsQuery = setColumnsForDownload(columnsQuery, definition);
return {
...filtersQuery,
...validColumnsQuery,
...sortQuery,
...(dataProductDefinitionsPath && { dataProductDefinitionsPath }),
};
};
/**
* Gets the columns/fields for the download request
*
* - Fields with fieldSource of 'specfield' should be discarded
*
* @param {Columns} columns
* @param {ExtractedDefinitionData} definitionData
* @return {*}
*/
const setColumnsForDownload = (query, definition) => {
const fields = getFields(definition);
const { specification } = definition.variant;
// Ensure sections heading are always included in download, if present
const sections = specification?.sections || [];
// Normalize columns - single column will be a `string`, we need an array
const queryColumns = [].concat(query['columns'] ?? []);
// master columns list
const requestedColumns = [...new Set([...queryColumns, ...sections])];
// Ensure only valid columns are part of download query
const validColumns = requestedColumns.filter(fieldName => {
const field = getField(fields, fieldName);
return field && (field.fieldSource === 'specfield' || field.fieldSource === undefined);
});
return { columns: validColumns };
};
var DownloadUtils = {
downloadReport,
setUpDownload,
};
export { DownloadUtils as default, downloadReport, setUpDownload };
//# sourceMappingURL=utils.js.map