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.

333 lines (328 loc) 14.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var utils$1 = require('../../../components/my-reports/my-reports-list-item/my-reports-list-item-actions/utils.js'); var queryMappers = require('../../../utils/queryMappers.js'); var urlHelper = require('../../../utils/urlHelper.js'); var localsHelper = require('../../../utils/localsHelper.js'); var utils$3 = require('../../../components/_reports/report-heading/report-columns/report-columns-form/utils.js'); var sessionHelper = require('../../../utils/sessionHelper.js'); var definitionUtils = require('../../../utils/definitionUtils.js'); var UserReports = require('../../../types/UserReports.js'); var utils$2 = require('../../../components/_async/request-details/utils.js'); var builder = require('../my-reports/recently-viewed/builder.js'); var utils = require('../my-reports/utils.js'); /** * Apply interactive query to a REPORT * * @param {Request} req * @param {Response} res * @param {Services} services * @param {('columns' | 'filters')} applyType * @return {*} */ const applyReportInteractiveQuery = async (req, res, services, applyType, loadType) => { const { reportId, id } = req.params; const { token, definitionsPath } = localsHelper.default.getValues(res); // Get the definition const definition = res.locals['definition'] ?? (await services.reportingService.getDefinition(token, reportId, id, definitionsPath)); const fields = definitionUtils.getFields(definition) || []; return applyInteractiveQuery(req, res, applyType, loadType, fields); }; /** * Apply interactive query to a DASHBOARD * * @param {Request} req * @param {Response} res * @param {Services} services * @param {('columns' | 'filters')} applyType * @return {*} */ const applyDashboardInteractiveQuery = async (req, res, applyType, loadType) => { return applyInteractiveQuery(req, res, applyType, loadType); }; /** * Apply the interactive query * * @param {Request} req * @param {Response} res * @param {('columns' | 'filters')} applyType * @param {components['schemas']['FieldDefinition'][]} fields */ const applyInteractiveQuery = async (req, res, applyType, loadType, fields) => { const { tableId, id, reportId } = req.params; // Get the stored interactive query data const sessionkey = loadType === UserReports.LoadType.ASYNC ? { id, tableId, reportId } : { id, reportId }; const queryDataFromSession = sessionHelper.getActiveJourneyValue(req, sessionkey, 'currentReportSearch'); let queryData = {}; let filtersData = {}; let columnsData = {}; if (queryDataFromSession) { queryData = queryMappers.qsToQueryObject(queryDataFromSession, ''); filtersData = queryMappers.qsToQueryObject(queryDataFromSession, 'filters.'); columnsData = queryMappers.qsToQueryObject(queryDataFromSession, 'columns'); } // Set the query values from the current query const preventDefault = queryData?.['preventDefault']; const pageSize = queryData?.['pageSize']; const selectedPage = applyType === 'columns' ? queryData?.['selectedPage'] : '1'; const sortColumn = queryData?.['sortColumn']; const sortedAsc = queryData?.['sortedAsc']; // Create merged form data let formData = { ...(preventDefault && { preventDefault }), ...(selectedPage && { selectedPage }), ...(pageSize && { pageSize }), ...(sortColumn && { sortColumn }), ...(sortedAsc && { sortedAsc }), ...(filtersData && filtersData), ...(columnsData && columnsData), }; formData = applyType === 'columns' && fields ? applyColumns(req, queryData, formData, fields) : applyFilters(req, queryData, formData); const filtersString = queryMappers.queryObjectToQs(formData); // Redirect back to report res.redirect(`${req.baseUrl}?${filtersString}`); }; /** * Apply columns * * @param {Request} req * @param {(Record<string, string | string[]>)} queryData * @param {(Record<string, string | string[]>)} formData * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} */ const applyColumns = (req, queryData, formData, fields) => { const { columns: reqColumns } = req.body; // Normalize the req columns - should always be an array let bodyColumns = []; if (reqColumns) { bodyColumns = Array.isArray(reqColumns) ? reqColumns : [reqColumns]; } // ensure mandatory cols are present and set the updated columns const mandatoryCols = utils$3.default.mandatoryColumns(fields); const columns = Array.from(new Set([...mandatoryCols, ...bodyColumns])); // Keep the filter values the same as current let filters = {}; if (queryData) { filters = Object.keys(queryData) .filter(key => key.includes('filters.')) .reduce((acc, key) => ({ ...acc, [key]: queryData[key] }), {}); } return { ...formData, columns, ...filters }; }; /** * Apply filters * * @param {(Record<string, string | string[]>)} queryData * @param {(Record<string, string | string[]>)} formData * @return {*} */ const applyFilters = (req, queryData, formData) => { // Ensure current columns stay the same and are normalized const columns = queryMappers.normalizeQueryStringArray(queryData?.['columns']) || []; const filters = Object.fromEntries(Object.keys(req.body) .filter(key => key.startsWith('filters.')) .map(key => [key, req.body[key]])); return { ...formData, ...filters, columns }; }; /** * Reset filters action * * @param {Request} req * @param {Response} res */ const resetFilters = (req, res, sessionKey) => { // Create the reset querystring const finalQuery = resetFiltersQueryString(req, sessionKey); // Redirect with new query string - query string will handle all rendered elements if (finalQuery) { res.redirect(`${req.baseUrl}?${finalQuery}`); } }; /** * Creates the query string to reset the filters * * @param {Request} req * @param {{ id: string; reportId: string; tableId?: string }} sessionKey * @return {*} {string} */ const resetFiltersQueryString = (req, sessionKey) => { const defaultSessionKey = { id: sessionKey.id, reportId: sessionKey.reportId }; const defaultFiltersSearch = sessionHelper.getActiveJourneyValue(req, defaultSessionKey, 'interactiveDefaultFiltersSearch'); const savedInteractiveDefaultsSearch = sessionHelper.getActiveJourneyValue(req, defaultSessionKey, 'savedInteractiveDefaultsSearch'); // Set the effective qs: if saved defaults, use those. Otherwise use DPD defaults const effectiveQueryString = savedInteractiveDefaultsSearch && savedInteractiveDefaultsSearch.length ? savedInteractiveDefaultsSearch : defaultFiltersSearch; // Get all the current stuff const currentColumnsSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'currentReportColumnsSearch'); const currentSortSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'currentSortSearch'); const currentPageSizeSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'currentPageSizeSearch'); // Create the final querystring return urlHelper.joinQueryStrings(effectiveQueryString, currentColumnsSearch, currentSortSearch, currentPageSizeSearch); }; /** * Creates the query string to reset the columns * * @param {Request} req * @param {{ id: string; reportId: string; tableId?: string }} sessionKey * @return {*} {string} */ const resetColumnsQueryString = (req, sessionKey) => { // get the default DPD filters const defaultSessionKey = { id: sessionKey.id, reportId: sessionKey.reportId }; const defaultColumnsSearch = sessionHelper.getActiveJourneyValue(req, defaultSessionKey, 'defaultColumnsSearch'); // Get all the current stuff const currentReportFiltersSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'currentReportFiltersSearch'); const currentSortSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'currentSortSearch'); const currentPageSizeSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'currentPageSizeSearch'); // Create the final querystring return urlHelper.joinQueryStrings(defaultColumnsSearch, currentReportFiltersSearch, currentSortSearch, currentPageSizeSearch); }; /** * Creates the default query string * * @param {Request} req * @return {*} {(string | undefined)} */ const createDefaultQueryString = (req) => { const { id, reportId, tableId } = req.params; // Get the interactive report defaults const sessionKey = { id, reportId }; // Definition defaults const defaultFiltersSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'interactiveDefaultFiltersSearch'); const defaultColumnsSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'defaultColumnsSearch'); const defaultSort = sessionHelper.getActiveJourneyValue(req, sessionKey, 'defaultSortQueryString'); // User defined values const savedInteractiveDefaultsSearch = sessionHelper.getActiveJourneyValue(req, sessionKey, 'savedInteractiveDefaultsSearch'); const requestedSort = sessionHelper.getActiveJourneyValue(req, { id, reportId, tableId }, 'requestedSortSearch'); /** * A report will always have default columns. * Redirect when the request has no query params, * applying default columns and optional filters. */ const hasIncomingQueryParams = Object.keys(req.query).length > 0; if (hasIncomingQueryParams || !defaultColumnsSearch) { return undefined; } // Filters: saved defaults override interactive default const filtersToApply = savedInteractiveDefaultsSearch && savedInteractiveDefaultsSearch.length ? savedInteractiveDefaultsSearch : defaultFiltersSearch; // Sort precedence: requested > default > none const sortToApply = requestedSort ?? defaultSort; // Build the query string progressively let query = defaultColumnsSearch; if (filtersToApply) { query = urlHelper.joinQueryStrings(query, filtersToApply); } if (sortToApply) { query = urlHelper.joinQueryStrings(query, sortToApply); } return query; }; /** * Redirects the report to use the defaults * * @param {Response} res * @param {Request} req * @return {*} */ const redirectWithDefaults = (res, req) => { const finalQuery = createDefaultQueryString(req); if (finalQuery) { const baseUrl = req.originalUrl.split('?')[0].replace(/\/$/, ''); res.redirect(`${baseUrl}?${finalQuery}`); return true; } return false; }; /** * Updates the report state to expired and redirects * * @param {Request} req * @param {Response} res * @param {Services} services */ const updateStateToExpiredAndRedirect = async (req, res, services) => { const { tableId } = req.params; const { dprUser } = localsHelper.default.getValues(res); // set the report to expired await services.recentlyViewedService.setToExpiredByTableId(tableId, dprUser.id); await services.requestedReportService.setToExpiredByTableId(tableId, dprUser.id); // get the updated report state const updatedReportState = await utils.getMyReport({ tableId }, 'recentlyViewedReports', services, dprUser.id); const pollingUrl = updatedReportState ? utils$1.buildPollingAction(res, req, updatedReportState).href : '/'; // redirect to polling page, or safe fallback res.redirect(pollingUrl); }; /** * Updates the state for a viewed ASYNC report * * @param {Request} req * @param {Response} res * @param {Services} services * @param {RequestedReport} reportStateData * @param {string} userId * @param {components['schemas']['FieldDefinition'][]} fields */ const updateLastViewedAsync = async (req, res, services, reportStateData, userId, fields) => { const { type, reportId, reportName, description, id, name, executionId, tableId, query, url } = reportStateData; const reportData = { type, reportId, reportName, description, id, name }; const executionData = { executionId, tableId }; const filtersQuery = queryMappers.extractFiltersFromQuery(req.query); const interactiveQueryData = { query: req.query, querySummary: utils$2.buildQuerySummary(filtersQuery, fields), }; const recentlyViewedReportData = new builder.ViewedReportBuilder(req, res) .withReportData(reportData) .withExecutionData(executionData) .withInteractiveQuery(interactiveQueryData) .withRequestData(query, url) .build(); if (executionId) await services.requestedReportService.updateLastViewed(executionId, userId); await services.recentlyViewedService.setRecentlyViewed(recentlyViewedReportData, userId); }; /** * Updates the last viewed state for a sync report * * @param {Request} req * @param {Services} services * @param {*} stateData * @param {string} userId * @param {components['schemas']['FieldDefinition'][]} fields */ const updateLastViewedSync = async (req, res, services, reportData, userId, fields) => { const filtersQuery = queryMappers.extractFiltersFromQuery(req.query); const interactiveQueryData = { query: req.query, querySummary: utils$2.buildQuerySummary(filtersQuery, fields), }; const recentlyViewedReportData = new builder.ViewedReportBuilder(req, res) .withReportData(reportData) .withInteractiveQuery(interactiveQueryData) .build(); await services.recentlyViewedService?.setRecentlyViewed(recentlyViewedReportData, userId); }; var ViewReportUtils = { applyDashboardInteractiveQuery, applyReportInteractiveQuery, resetFilters, resetFiltersQueryString, resetColumnsQueryString, redirectWithDefaults, }; exports.applyDashboardInteractiveQuery = applyDashboardInteractiveQuery; exports.applyReportInteractiveQuery = applyReportInteractiveQuery; exports.default = ViewReportUtils; exports.redirectWithDefaults = redirectWithDefaults; exports.updateLastViewedAsync = updateLastViewedAsync; exports.updateLastViewedSync = updateLastViewedSync; exports.updateStateToExpiredAndRedirect = updateStateToExpiredAndRedirect; //# sourceMappingURL=utils.js.map