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.

325 lines (322 loc) 11.2 kB
import { FilterType } from '../components/_filters/filter-input/enum.js'; import { resolveDateRangeDefaults, appendDateRangeValue } from '../components/_inputs/date-range/utils.js'; import { resolveGranularDateRangeDefaults, appendGranularDateRangeValue } from '../components/_inputs/granular-date-range/utils.js'; import { appendMultiSelectValues } from '../components/_inputs/multi-select/utils.js'; import { visibleColumns, mandatoryColumns } from '../components/_reports/report-heading/report-columns/report-columns-form/utils.js'; import { ReportType } from '../types/UserReports.js'; import logger from './logger.js'; import { getQueryParamAsString } from './queryMappers.js'; /** * Gets the definition and fields by reportType * * @param {ReportType} reportType * @param {Services} services * @param {string} token * @param {string} reportId * @param {string} id * @param {string} [definitionsPath] */ const getDefinitionByType = async (reportType, services, token, reportId, id, definitionsPath, queryData) => { let definition; let fields; if (reportType === ReportType.REPORT) { definition = await services.reportingService.getDefinition(token, reportId, id, definitionsPath, queryData); fields = getFields(definition); } else { definition = await services.dashboardService.getDefinition(token, reportId, id, definitionsPath, queryData); fields = getDashboardFields(definition); } if (!definition) { throw Error(`Unable to retrieve definition for ${reportType} with id:${id} & reportId:${reportId}`); } return { definition, fields, }; }; /** * Given a field id, gets its filter object * * @param {components['schemas']['FieldDefinition'][]} fields * @param {string} fieldId * @return {*} {(components['schemas']['FilterDefinition'] | undefined)} */ const getFilter = (fields, fieldId) => { return fields.find(f => f.name === fieldId)?.filter; }; /** * Gets the current varaint definition * * @param {components['schemas']['ReportDefinitionSummary'][]} definitions * @param {string} reportId * @param {string} variantId * @return {*} {(components['schemas']['VariantDefinition'] | undefined)} */ const getCurrentVariantDefinition = (definitions, reportId, variantId) => { if (!definitions) { logger.info('No definitions'); return undefined; } let variantDef; const reportDef = definitions.find((report) => report.id === reportId); if (reportDef) { // TODO: this needs fixing, we should never be using `as unknown as`, but the types are very mixed up here variantDef = reportDef.variants.find(variant => variantId === variant.id); return variantDef; } return undefined; }; /** * Gets the display name of a field * * @param {(components['schemas']['FieldDefinition'][] | components['schemas']['SummaryField'][])} fields * @param {string} fieldId * @return {*} */ const getFieldDisplayName = (fields, fieldId) => { const ids = fieldId.split('.'); const field = fields.find(f => { return f.name === ids[0]; }); if (field) { return ids[1] ? `${field.display} ${ids[1]}` : field.display; } return fieldId; }; /** * Gets a single field by its id/name * * @param {components['schemas']['FieldDefinition'][]} fields * @param {string} fieldId * @return {*} */ const getField = (fields, fieldId) => { return fields.find(field => { return field.name === fieldId; }); }; /** * Get all fields from a definition * * @param {components['schemas']['SingleVariantReportDefinition']} definition * @return {*} {components['schemas']['FieldDefinition'][]} */ const getFields = (definition) => { return definition.variant.specification?.fields || []; }; /** * Get all fields from a definition * * @param {components['schemas']['SingleVariantReportDefinition']} definition * @return {*} {components['schemas']['FieldDefinition'][]} */ const getDashboardFields = (definition) => { return definition.filterFields || []; }; /** * Gets only the fields that have filters, from fields * * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} {FieldWithFilter[]} */ const getFieldsWithFilters = (fields) => { return fields.filter((f) => !!f.filter); }; /** * Gets the template type * * @param {components['schemas']['SingleVariantReportDefinition']} definition * @return {*} {Template} */ const getTemplate = (definition) => { return definition.variant.specification?.template || 'list'; }; /** * Gets the filters from a variant * * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} {components['schemas']['FilterDefinition'][]} */ const getFilters = (fields) => { const filters = fields .filter((field) => field.filter) .map((field) => field.filter); return filters.length ? filters : []; }; /** * Given an array of string names, will return the relative field types * * @param {string[]} names * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} {components['schemas']['FieldDefinition'][]} */ const getFieldsByName = (names, fields) => { return names.map(s => fields.find(field => field.name === s)).filter(field => field !== undefined); }; /** * Validates the definition * * @param {components['schemas']['SingleVariantReportDefinition']} definition * @return {*} */ const validateDefinition = (definition) => { const { variant } = definition; return validateVariant(variant, definition.id); }; /** * Validates that the variant has a `specification` * * @param {components['schemas']['VariantDefinition']} variant * @return {*} */ const validateVariant = (variant, defId) => { const { specification } = variant; if (!specification) { logger.error(`No specification found for definition ID: ${defId} variant ID: ${variant.id}`); throw new Error(`No specification found for definition ID: ${defId} variant ID: ${variant.id}`); } return { variant, specification }; }; /** * Determines whether there are any interactive filters * defined in the definition * * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} */ const hasInteractiveFilters = (fields) => { const filters = getFilters(fields); return filters.some(filter => filter.interactive); }; const getReportSummary = (reportId, reportingService, token, definitionPath) => reportingService.getDefinitionSummary(token, reportId, definitionPath); /** * Creates a the default filters querystring * * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} {DefaultFilterQueryStrings} */ const getDefaultFiltersQueryString = (fields) => { const defaultParams = new URLSearchParams(); const interactiveParams = new URLSearchParams(); const fieldsWithFilters = getFieldsWithFilters(fields); fieldsWithFilters.forEach(field => { const { interactive = false } = field.filter; appendFilterDefaults(interactive ? interactiveParams : defaultParams, field); }); return { defaultFiltersSearch: buildQueryString(defaultParams), interactiveDefaultFiltersSearch: buildQueryString(interactiveParams), }; }; /** * Sets the default sort query string * * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} */ const getDefaultSortQueryString = (fields) => { const defaultSortField = fields.find(field => field.defaultsort); if (!defaultSortField) { return ''; } const defaultSortParams = new URLSearchParams(); const isAsc = (defaultSortField.sortDirection ?? 'asc') === 'asc'; defaultSortParams.set('sortColumn', defaultSortField.name); defaultSortParams.set('sortedAsc', String(isAsc)); return buildQueryString(defaultSortParams); }; /** * Builds the querystring * * @param {URLSearchParams} params * @return {*} {string} */ const buildQueryString = (params) => { const qs = params.toString(); return qs || ''; }; /** * Appends the filter value to a query string * * @param {URLSearchParams} params * @param {FieldWithFilter} field */ const appendFilterDefaults = (params, field) => { const { name, filter } = field; const { type, defaultValue, defaultQuickFilterValue } = filter; if (!defaultValue && !defaultQuickFilterValue) return; switch (type.toLowerCase()) { case FilterType.radio.toLowerCase(): case FilterType.select.toLowerCase(): case FilterType.text.toLowerCase(): case FilterType.date.toLowerCase(): case FilterType.autocomplete.toLowerCase(): { if (!defaultValue) break; params.append(`filters.${name}`, defaultValue); break; } case FilterType.autocompleteMulti.toLowerCase(): case FilterType.multiselect.toLowerCase(): { if (!defaultValue) break; appendMultiSelectValues(params, name, defaultValue); break; } case FilterType.dateRange.toLowerCase(): { const resolved = resolveDateRangeDefaults(filter); if (!resolved) break; appendDateRangeValue(params, name, resolved); break; } case FilterType.granularDateRange.toLowerCase(): { const resolved = resolveGranularDateRangeDefaults(filter); if (!resolved) break; appendGranularDateRangeValue(params, name, resolved); break; } } }; /** * Get the default columns from the DPD * and creates a querystring * * @param {components['schemas']['FieldDefinition'][]} fields * @return {*} */ const getDefaultColumnsQueryString = (fields) => { const visibleCols = visibleColumns(fields); const mandatoryCols = mandatoryColumns(fields); const defaultColumns = Array.from(new Set([...mandatoryCols, ...visibleCols])); const params = new URLSearchParams(); defaultColumns.forEach(column => { params.append('columns', column); }); return buildQueryString(params); }; /** * Get the definition path from the query * * @param {Record<string, unknown>} query */ const getDefinitionsPath = (query) => getQueryParamAsString(query, 'dataProductDefinitionsPath'); var DefinitionUtils = { getCurrentVariantDefinition, getFieldDisplayName, getField, getFields, getTemplate, getFilter, getFilters, getReportSummary, hasInteractiveFilters, getDefaultFiltersQueryString, getDefaultColumnsQueryString, getDefinitionByType, }; export { DefinitionUtils as default, getCurrentVariantDefinition, getDashboardFields, getDefaultColumnsQueryString, getDefaultFiltersQueryString, getDefaultSortQueryString, getDefinitionByType, getDefinitionsPath, getField, getFieldDisplayName, getFields, getFieldsByName, getFieldsWithFilters, getFilter, getFilters, getReportSummary, getTemplate, hasInteractiveFilters, validateDefinition, validateVariant }; //# sourceMappingURL=definitionUtils.js.map