@ministryofjustice/hmpps-digital-prison-reporting-frontend 4.15.0 → 4.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dpr/components/_charts/chart/heatmap/Heatmap.js +2 -0
  2. package/dpr/components/_charts/chart/heatmap/Heatmap.js.map +7 -0
  3. package/dpr/components/_charts/chart/heatmap/Heatmap.ts +278 -0
  4. package/dpr/components/_charts/utils.js +1 -1
  5. package/dpr/components/_charts/utils.js.map +3 -3
  6. package/dpr/components/_charts/utils.ts +2 -2
  7. package/dpr/components/_dashboards/dashboard/types.js +1 -1
  8. package/dpr/components/_dashboards/dashboard/types.js.map +2 -2
  9. package/dpr/components/_dashboards/dashboard/types.ts +8 -0
  10. package/dpr/components/_dashboards/dashboard-list/utils.js +1 -1
  11. package/dpr/components/_dashboards/dashboard-list/utils.js.map +3 -3
  12. package/dpr/components/_dashboards/dashboard-list/utils.ts +3 -2
  13. package/dpr/components/user-reports/utils.js +1 -1
  14. package/dpr/components/user-reports/utils.js.map +3 -3
  15. package/dpr/components/user-reports/utils.ts +13 -3
  16. package/dpr/routes/journeys/view-report/async/report/tests.cy.js +1 -1
  17. package/dpr/routes/journeys/view-report/async/report/tests.cy.js.map +2 -2
  18. package/dpr/routes/journeys/view-report/async/report/tests.cy.ts +44 -8
  19. package/dpr/routes/journeys/view-report/utils.js +1 -1
  20. package/dpr/routes/journeys/view-report/utils.js.map +3 -3
  21. package/dpr/routes/journeys/view-report/utils.ts +6 -1
  22. package/dpr/utils/DataTableBuilder/DataTableBuilder.js +1 -1
  23. package/dpr/utils/DataTableBuilder/DataTableBuilder.js.map +2 -2
  24. package/dpr/utils/DataTableBuilder/DataTableBuilder.ts +37 -19
  25. package/dpr/utils/UserStoreItemBuilder.js.map +1 -1
  26. package/dpr/utils/UserStoreItemBuilder.ts +1 -1
  27. package/package.json +1 -1
  28. package/dpr/components/_charts/chart/heatmap/utils.js +0 -2
  29. package/dpr/components/_charts/chart/heatmap/utils.js.map +0 -7
  30. package/dpr/components/_charts/chart/heatmap/utils.ts +0 -182
@@ -1,2 +1,2 @@
1
- var g=Object.create;var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var w=(o,t)=>{for(var e in t)m(o,e,{get:t[e],enumerable:!0})},d=(o,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of b(t))!C.call(o,a)&&a!==e&&m(o,a,{get:()=>t[a],enumerable:!(r=D(t,a))||r.enumerable});return o};var h=(o,t,e)=>(e=o!=null?g(S(o)):{},d(t||!o||!o.__esModule?m(e,"default",{value:o,enumerable:!0}):e,o)),v=o=>d(m({},"__esModule",{value:!0}),o);var A={};w(A,{DataTableBuilder:()=>c,default:()=>F});module.exports=v(A);var p=h(require("../urlHelper")),y=h(require("../DateMapper/DateMapper"));class c{constructor(t,e=!1){this.columns=[];this.reportSummaries={};this.reportQuery=null;this.currentQueryParams=null;this.dateMapper=new y.default;this.fields=t,this.sortData=e}mapDate(t){return t?this.dateMapper.toDateString(t,"local-datetime-short-year"):""}mapBoolean(t){return t?t.substring(0,1).toUpperCase()+t.substring(1).toLowerCase():""}mapRow(t,e="",r=[]){return this.fields.filter(a=>this.columns.includes(a.name)).map(a=>{const s=r.find(n=>n.name===a.name)??a;return this.mapCell(s,t,e)})}mapCell(t,e,r=""){const a=this.mapCellValue(t,e[t.name]);let i="string",s=r;t.wordWrap&&(s+=` data-table-cell-wrap-${t.wordWrap.toLowerCase()}`),t.header&&(s+=" govuk-table__header"),(t.type==="double"||t.type==="long")&&(i="numeric");const n=t.type==="HTML";return{fieldName:t.name,...n?{html:a}:{text:a},format:i,classes:s.trim()}}mapCellValue(t,e){if(t.calculated)return e;switch(t.type){case"boolean":return this.mapBoolean(e);case"date":case"time":return this.mapDate(e);default:return e}}mapHeader(t=!1,e=null){return this.fields.filter(r=>this.columns.includes(r.name)).map(r=>{if(this.reportQuery&&!t&&r.sortable){let a="none",i=(0,p.default)(this.currentQueryParams||{},{sortColumn:r.name,sortedAsc:"true"});return r.name===this.reportQuery.sortColumn&&(a=this.reportQuery.sortedAsc?"ascending":"descending",this.reportQuery.sortedAsc&&(i=(0,p.default)(this.currentQueryParams||{},{sortColumn:r.name,sortedAsc:"false"}))),{html:`<a data-column="${r.name}" class="data-table-header-button data-table-header-button-sort-${a}" href="${i}">${r.display}</a>`,...e&&{classes:e}}}return{text:r.display,...e&&{classes:e}}})}mapData(t){const e=this.mapSummary("table-header"),r=this.mergeCells(t.map(i=>this.mapRow(i))),a=this.mapSummary("table-footer");return e.concat(r).concat(a)}mergeCells(t){const e=this.fields.filter(a=>a.mergeRows).map(a=>a.name);if(e.length===0)return t;const r={};return e.forEach(a=>{r[a]=t.reduce((i,s)=>{const n=this.getCellByFieldName(s,a);let l="";return n&&(l=n.text||n.html||""),{...i,[l]:(i[l]??0)+1}},{})}),t.map(a=>{let i=[...a];return e.forEach(s=>{const n=this.getCellByFieldName(a,s);let l,u;if(n&&r[s])switch(l=n.text||n.html||"",u=r[s][l],u){case-1:i=i.filter(f=>f.fieldName!==s);break;case 1:break;default:n.rowspan=u,r[s][l]=-1}}),i})}getCellByFieldName(t,e){return t.find(r=>r.fieldName===e)}mapSummary(t){return this.reportSummaries[t]?this.reportSummaries[t].flatMap(e=>e.data.map(r=>this.mapRow(r,`dpr-report-summary-cell dpr-report-summary-cell-${t}`,e.fields))):[]}sort(t){return this.appendSortKeyToData(t).sort(this.sortKeyComparison()).map(e=>({...e}))}sortKeyComparison(){return(t,e)=>{const r=t.sortKey,a=e.sortKey;return r===a?0:r<a?-1:1}}appendSortKeyToData(t,e=null){const r=e||this.fields;return t.map(a=>{const i=this.getSortKey(a,r);return{...a,sortKey:i}})}mapNamesToFields(t){return t.map(e=>this.fields.find(r=>r.name===e)).filter(e=>e!==void 0)}getSortKey(t,e){return e.map(r=>{const a=t[r.name];return a&&this.dateMapper.isDate(a)?this.dateMapper.toDateString(a,"iso"):this.mapCellValue(r,a)}).join("-").toLowerCase()}convertDataTableToHtml(t){const r=(t.head||[]).map(i=>`<th scope='col' class='govuk-table__header'>${i.html??i.text}</th>`),a=t.rows.map(i=>`<tr class='govuk-table__row'>${i.map(s=>`<td class='govuk-table__cell govuk-table__cell--${s.format} ${s.classes}'>${s.html??s.text}</td>`).join("")}</tr>`);return`<table class='govuk-table'><thead class='govuk-table__head'>${r.join("")}</thead><tbody class='govuk-table__body'>${a.join("")}</tbody></table>`}withHeaderOptions({reportQuery:t,columns:e,interactive:r}){return r&&t?this.withHeaderSortOptions(t):this.withNoHeaderOptions(e)}withHeaderSortOptions(t){return this.reportQuery=t,this.columns=t.columns,this.currentQueryParams=this.reportQuery.toRecordWithFilterPrefix(),this}withNoHeaderOptions(t){return this.columns=t,this}buildTable(t){const e=this.mapData(this.sortData?this.sort(t):t);return{head:this.mapHeader(),rows:e,rowCount:t.length,colCount:this.columns.length}}withSummaries(t){return this.reportSummaries=t,this}withSortedData(t=!0){return this.sortData=t,this}}var F=c;0&&(module.exports={DataTableBuilder});
1
+ var g=Object.create;var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var w=(i,e)=>{for(var t in e)m(i,t,{get:e[t],enumerable:!0})},d=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of b(e))!C.call(i,a)&&a!==t&&m(i,a,{get:()=>e[a],enumerable:!(r=D(e,a))||r.enumerable});return i};var h=(i,e,t)=>(t=i!=null?g(S(i)):{},d(e||!i||!i.__esModule?m(t,"default",{value:i,enumerable:!0}):t,i)),v=i=>d(m({},"__esModule",{value:!0}),i);var K={};w(K,{DataTableBuilder:()=>u,default:()=>F});module.exports=v(K);var p=h(require("../urlHelper")),y=h(require("../DateMapper/DateMapper"));class u{constructor(e,t=!1){this.columns=[];this.reportSummaries={};this.reportQuery=null;this.currentQueryParams=null;this.dateMapper=new y.default;this.fields=e,this.sortData=t}mapDate(e){return e?this.dateMapper.toDateString(e,"local-datetime-short-year"):""}mapBoolean(e){return e?e.substring(0,1).toUpperCase()+e.substring(1).toLowerCase():""}mapRow(e,t="",r=[]){return this.fields.filter(a=>this.columns.includes(a.name)).map(a=>{const o=r.find(n=>n.name===a.name)??a;return this.mapCell(o,e,t)})}mapCell(e,t,r=""){const a=this.mapCellValue(e,t[e.name]);let s="string",o=r;e.wordWrap&&(o+=` data-table-cell-wrap-${e.wordWrap.toLowerCase()}`),e.header&&(o+=" govuk-table__header"),(e.type==="double"||e.type==="long")&&(s="numeric");const n=e.type==="HTML";return{fieldName:e.name,...n?{html:a}:{text:a},format:s,classes:o.trim()}}mapCellValue(e,t){if(e.calculated)return t;switch(e.type){case"boolean":return this.mapBoolean(t);case"date":case"time":return this.mapDate(t);default:return t}}mapHeader(e=!1,t=null){return this.fields.filter(r=>this.columns.includes(r.name)).map(r=>{if(this.reportQuery&&!e&&r.sortable){let a="none",s=(0,p.default)(this.currentQueryParams||{},{sortColumn:r.name,sortedAsc:"true"},this.fields);return r.name===this.reportQuery.sortColumn&&(a=this.reportQuery.sortedAsc?"ascending":"descending",this.reportQuery.sortedAsc&&(s=(0,p.default)(this.currentQueryParams||{},{sortColumn:r.name,sortedAsc:"false"},this.fields))),{html:`<a data-column="${r.name}" class="data-table-header-button data-table-header-button-sort-${a}" href="${s}">${r.display}</a>`,...t&&{classes:t}}}return{text:r.display,...t&&{classes:t}}})}mapData(e){const t=this.mapSummary("table-header"),r=this.mergeCells(e.map(s=>this.mapRow(s))),a=this.mapSummary("table-footer");return t.concat(r).concat(a)}mergeCells(e){const t=this.fields.filter(a=>a.mergeRows).map(a=>a.name);if(t.length===0)return e;const r={};return t.forEach(a=>{r[a]=e.reduce((s,o)=>{const n=this.getCellByFieldName(o,a);let l="";return n&&(l=n.text||n.html||""),{...s,[l]:(s[l]??0)+1}},{})}),e.map(a=>{let s=[...a];return t.forEach(o=>{const n=this.getCellByFieldName(a,o);let l,c;if(n&&r[o])switch(l=n.text||n.html||"",c=r[o][l],c){case-1:s=s.filter(f=>f.fieldName!==o);break;case 1:break;default:n.rowspan=c,r[o][l]=-1}}),s})}getCellByFieldName(e,t){return e.find(r=>r.fieldName===t)}mapSummary(e){return this.reportSummaries[e]?this.reportSummaries[e].flatMap(t=>t.data.map(r=>this.mapRow(r,`dpr-report-summary-cell dpr-report-summary-cell-${e}`,t.fields))):[]}sort(e){return this.appendSortKeyToData(e).sort(this.sortKeyComparison()).map(t=>({...t}))}sortKeyComparison(){return(e,t)=>{const r=e.sortKey,a=t.sortKey;return r===a?0:r<a?-1:1}}appendSortKeyToData(e,t=null){const r=t||this.fields;return e.map(a=>{const s=this.getSortKey(a,r);return{...a,sortKey:s}})}mapNamesToFields(e){return e.map(t=>this.fields.find(r=>r.name===t)).filter(t=>t!==void 0)}getSortKey(e,t){return t.map(r=>{const a=e[r.name];return a&&this.dateMapper.isDate(a)?this.dateMapper.toDateString(a,"iso"):this.mapCellValue(r,a)}).join("-").toLowerCase()}convertDataTableToHtml(e){const r=(e.head||[]).map(s=>`<th scope='col' class='govuk-table__header'>${s.html??s.text}</th>`),a=e.rows.map(s=>`<tr class='govuk-table__row'>${s.map(o=>`<td class='govuk-table__cell govuk-table__cell--${o.format} ${o.classes}'>${o.html??o.text}</td>`).join("")}</tr>`);return`<table class='govuk-table'><thead class='govuk-table__head'>${r.join("")}</thead><tbody class='govuk-table__body'>${a.join("")}</tbody></table>`}withHeaderOptions({reportQuery:e,columns:t,interactive:r}){return r&&e?this.withHeaderSortOptions(e):this.withNoHeaderOptions(t)}withHeaderSortOptions(e){return this.reportQuery=e,this.columns=e.columns,this.currentQueryParams=this.reportQuery.toRecordWithFilterPrefix(),this}withNoHeaderOptions(e){return this.columns=e,this}buildTable(e){const t=this.mapData(this.sortData?this.sort(e):e);return{head:this.mapHeader(),rows:t,rowCount:e.length,colCount:this.columns.length}}withSummaries(e){return this.reportSummaries=e,this}withSortedData(e=!0){return this.sortData=e,this}}var F=u;0&&(module.exports={DataTableBuilder});
2
2
  //# sourceMappingURL=DataTableBuilder.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/dpr/utils/DataTableBuilder/DataTableBuilder.ts"],
4
- "sourcesContent": ["import Dict = NodeJS.Dict\nimport ReportQuery from '../../types/ReportQuery'\nimport { Cell, CellFormat, DataTable, FieldDefinition, SortKey } from './types'\nimport createUrlForParameters from '../urlHelper'\nimport type { SummaryTemplate } from '../../types/Templates'\nimport { AsyncSummary } from '../../types/UserReports'\nimport DateMapper from '../DateMapper/DateMapper'\n\nclass DataTableBuilder {\n protected fields: Array<FieldDefinition>\n\n private sortData: boolean\n\n protected columns: Array<string> = []\n\n protected reportSummaries: Dict<Array<AsyncSummary>> = {}\n\n // Sortable headers only\n private reportQuery: ReportQuery | null = null\n\n private currentQueryParams: NodeJS.Dict<string | Array<string>> | null = null\n\n private dateMapper = new DateMapper()\n\n constructor(fields: Array<FieldDefinition>, sortData = false) {\n this.fields = fields\n this.sortData = sortData\n }\n\n private mapDate(isoDate?: string) {\n if (!isoDate) return ''\n\n return this.dateMapper.toDateString(isoDate, 'local-datetime-short-year')\n }\n\n private mapBoolean(value?: string) {\n if (!value) return ''\n return value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase()\n }\n\n protected mapRow(\n rowData: NodeJS.Dict<string>,\n extraClasses = '',\n overrideFields: Array<FieldDefinition> = [],\n ): Cell[] {\n return this.fields\n .filter((f) => this.columns.includes(f.name))\n .map((f) => {\n const overrideField = overrideFields.find((o) => o.name === f.name)\n const field = overrideField ?? f\n return this.mapCell(field, rowData, extraClasses)\n })\n }\n\n private mapCell(field: FieldDefinition, rowData: NodeJS.Dict<string>, extraClasses = '') {\n const textValue = this.mapCellValue(field, rowData[field.name])\n let fieldFormat: CellFormat = 'string'\n\n let classes = extraClasses\n\n if (field.wordWrap) {\n classes += ` data-table-cell-wrap-${field.wordWrap.toLowerCase()}`\n }\n\n if (field.header) {\n classes += ' govuk-table__header'\n }\n\n if (field.type === 'double' || field.type === 'long') {\n fieldFormat = 'numeric'\n }\n\n const isHtml = field.type === 'HTML'\n const cell: Cell = {\n fieldName: field.name,\n ...(isHtml ? { html: textValue } : { text: textValue }),\n format: fieldFormat,\n classes: classes.trim(),\n }\n\n return cell\n }\n\n protected mapCellValue(field: FieldDefinition, cellData?: string) {\n if (field.calculated) {\n return cellData\n }\n\n switch (field.type) {\n case 'boolean':\n return this.mapBoolean(cellData)\n\n case 'date':\n case 'time':\n return this.mapDate(cellData)\n\n default:\n return cellData\n }\n }\n\n protected mapHeader(disableSort = false, extraClasses: string | null = null): Cell[] {\n return this.fields\n .filter((field) => this.columns.includes(field.name))\n .map((f) => {\n if (this.reportQuery && !disableSort) {\n if (f.sortable) {\n let sortDirection = 'none'\n let url = createUrlForParameters(this.currentQueryParams || {}, {\n sortColumn: f.name,\n sortedAsc: 'true',\n })\n\n if (f.name === this.reportQuery.sortColumn) {\n sortDirection = this.reportQuery.sortedAsc ? 'ascending' : 'descending'\n\n if (this.reportQuery.sortedAsc) {\n url = createUrlForParameters(this.currentQueryParams || {}, {\n sortColumn: f.name,\n sortedAsc: 'false',\n })\n }\n }\n\n return {\n html:\n `<a ` +\n `data-column=\"${f.name}\" ` +\n `class=\"data-table-header-button data-table-header-button-sort-${sortDirection}\" ` +\n `href=\"${url}\"` +\n `>${f.display}</a>`,\n ...(extraClasses && { classes: extraClasses }),\n }\n }\n }\n return {\n text: f.display,\n ...(extraClasses && { classes: extraClasses }),\n }\n })\n }\n\n protected mapData(data: Array<Dict<string>>): Cell[][] {\n const mappedHeaderSummary = this.mapSummary('table-header')\n const mappedTableData = this.mergeCells(data.map((rowData) => this.mapRow(rowData)))\n const mappedFooterSummary = this.mapSummary('table-footer')\n\n return mappedHeaderSummary.concat(mappedTableData).concat(mappedFooterSummary)\n }\n\n private mergeCells(rows: Cell[][]): Cell[][] {\n const mergeFieldNames = this.fields.filter((f) => f.mergeRows).map((f) => f.name)\n\n if (mergeFieldNames.length === 0) {\n return rows\n }\n\n const occurrences: Dict<Dict<number>> = {}\n mergeFieldNames.forEach((f) => {\n occurrences[f] = rows.reduce((accumulator: Dict<number>, currentRow) => {\n const currentCell = this.getCellByFieldName(currentRow, f)\n let cellValue = ''\n if (currentCell) {\n cellValue = currentCell.text || currentCell.html || ''\n }\n\n return {\n ...accumulator,\n [cellValue]: (accumulator[cellValue] ?? 0) + 1,\n }\n }, {})\n })\n\n return rows.map((row) => {\n let mergedRow = [...row]\n\n mergeFieldNames.forEach((mergeFieldName) => {\n const currentRowCell = this.getCellByFieldName(row, mergeFieldName)\n let cellValue\n let occurrencesOfValue\n if (currentRowCell && occurrences[mergeFieldName]) {\n cellValue = currentRowCell.text || currentRowCell.html || ''\n occurrencesOfValue = occurrences[mergeFieldName][cellValue]\n\n switch (occurrencesOfValue) {\n case -1:\n mergedRow = mergedRow.filter((c) => c.fieldName !== mergeFieldName)\n break\n\n case 1:\n break\n\n default:\n currentRowCell.rowspan = occurrencesOfValue\n occurrences[mergeFieldName][cellValue] = -1\n }\n }\n })\n\n return mergedRow\n })\n }\n\n private getCellByFieldName(row: Cell[], fieldName: string) {\n return row.find((c) => c.fieldName === fieldName)\n }\n\n private mapSummary(template: SummaryTemplate): Cell[][] {\n if (this.reportSummaries[template]) {\n return this.reportSummaries[template].flatMap((reportSummary) =>\n reportSummary.data.map((rowData) =>\n this.mapRow(rowData, `dpr-report-summary-cell dpr-report-summary-cell-${template}`, reportSummary.fields),\n ),\n )\n }\n return []\n }\n\n protected sort(data: Dict<string>[]): Dict<string>[] {\n return this.appendSortKeyToData(data)\n .sort(this.sortKeyComparison())\n .map((d: SortKey) => ({\n ...d,\n }))\n }\n\n protected sortKeyComparison() {\n return (a: SortKey, b: SortKey) => {\n const aValue = a.sortKey\n const bValue = b.sortKey\n\n if (aValue === bValue) {\n return 0\n }\n\n if (aValue < bValue) {\n return -1\n }\n\n return 1\n }\n }\n\n private appendSortKeyToData(data: Dict<string>[], fields: FieldDefinition[] | null = null): SortKey[] {\n const sortFields = fields || this.fields\n\n return data.map((rowData) => {\n const sortKey = this.getSortKey(rowData, sortFields)\n\n return {\n ...rowData,\n sortKey,\n }\n })\n }\n\n protected mapNamesToFields(names: string[]): FieldDefinition[] {\n return names.map((s) => this.fields.find((f) => f.name === s)).filter((n) => n !== undefined)\n }\n\n protected getSortKey(rowData: NodeJS.Dict<string>, sortFields: FieldDefinition[]) {\n return sortFields\n .map((f) => {\n const value = rowData[f.name]\n if (value && this.dateMapper.isDate(value)) {\n return this.dateMapper.toDateString(value, 'iso')\n }\n\n return this.mapCellValue(f, value)\n })\n .join('-')\n .toLowerCase()\n }\n\n protected convertDataTableToHtml(dataTable: DataTable): string {\n const head = dataTable.head || []\n const headers = head.map((h) => `<th scope='col' class='govuk-table__header'>${h.html ?? h.text}</th>`)\n const rows = dataTable.rows.map(\n (r) =>\n `<tr class='govuk-table__row'>${r\n .map(\n (c) => `<td class='govuk-table__cell govuk-table__cell--${c.format} ${c.classes}'>${c.html ?? c.text}</td>`,\n )\n .join('')}</tr>`,\n )\n\n return (\n \"<table class='govuk-table'>\" +\n `<thead class='govuk-table__head'>${headers.join('')}</thead>` +\n `<tbody class='govuk-table__body'>${rows.join('')}</tbody>` +\n '</table>'\n )\n }\n\n withHeaderOptions({\n reportQuery,\n columns,\n interactive,\n }: {\n reportQuery?: ReportQuery\n columns: string[]\n interactive: boolean\n }) {\n if (interactive && reportQuery) {\n return this.withHeaderSortOptions(reportQuery)\n }\n return this.withNoHeaderOptions(columns)\n }\n\n withHeaderSortOptions(reportQuery: ReportQuery) {\n this.reportQuery = reportQuery\n this.columns = reportQuery.columns\n this.currentQueryParams = this.reportQuery.toRecordWithFilterPrefix()\n\n return this\n }\n\n withNoHeaderOptions(columns: string[]) {\n this.columns = columns\n return this\n }\n\n buildTable(data: Array<Dict<string>>): DataTable {\n const mappedData = this.mapData(this.sortData ? this.sort(data) : data)\n\n return {\n head: this.mapHeader(),\n rows: mappedData,\n rowCount: data.length,\n colCount: this.columns.length,\n }\n }\n\n withSummaries(reportSummaries: Dict<Array<AsyncSummary>>) {\n this.reportSummaries = reportSummaries\n return this\n }\n\n withSortedData(sortData = true) {\n this.sortData = sortData\n return this\n }\n}\n\nexport { DataTableBuilder }\nexport default DataTableBuilder\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import Dict = NodeJS.Dict\nimport ReportQuery from '../../types/ReportQuery'\nimport { Cell, CellFormat, DataTable, SortKey } from './types'\nimport createUrlForParameters from '../urlHelper'\nimport type { SummaryTemplate } from '../../types/Templates'\nimport { AsyncSummary } from '../../types/UserReports'\nimport DateMapper from '../DateMapper/DateMapper'\nimport { components } from '../../types/api'\n\nclass DataTableBuilder {\n protected fields: components['schemas']['FieldDefinition'][]\n\n private sortData: boolean\n\n protected columns: Array<string> = []\n\n protected reportSummaries: Dict<Array<AsyncSummary>> = {}\n\n // Sortable headers only\n private reportQuery: ReportQuery | null = null\n\n private currentQueryParams: NodeJS.Dict<string | Array<string>> | null = null\n\n private dateMapper = new DateMapper()\n\n constructor(fields: components['schemas']['FieldDefinition'][], sortData = false) {\n this.fields = fields\n this.sortData = sortData\n }\n\n private mapDate(isoDate?: string) {\n if (!isoDate) return ''\n\n return this.dateMapper.toDateString(isoDate, 'local-datetime-short-year')\n }\n\n private mapBoolean(value?: string) {\n if (!value) return ''\n return value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase()\n }\n\n protected mapRow(\n rowData: NodeJS.Dict<string>,\n extraClasses = '',\n overrideFields: components['schemas']['FieldDefinition'][] = [],\n ): Cell[] {\n return this.fields\n .filter((f) => this.columns.includes(f.name))\n .map((f) => {\n const overrideField = overrideFields.find((o) => o.name === f.name)\n const field = overrideField ?? f\n return this.mapCell(field, rowData, extraClasses)\n })\n }\n\n private mapCell(field: components['schemas']['FieldDefinition'], rowData: NodeJS.Dict<string>, extraClasses = '') {\n const textValue = this.mapCellValue(field, rowData[field.name])\n let fieldFormat: CellFormat = 'string'\n\n let classes = extraClasses\n\n if (field.wordWrap) {\n classes += ` data-table-cell-wrap-${field.wordWrap.toLowerCase()}`\n }\n\n if (field.header) {\n classes += ' govuk-table__header'\n }\n\n if (field.type === 'double' || field.type === 'long') {\n fieldFormat = 'numeric'\n }\n\n const isHtml = field.type === 'HTML'\n const cell: Cell = {\n fieldName: field.name,\n ...(isHtml ? { html: textValue } : { text: textValue }),\n format: fieldFormat,\n classes: classes.trim(),\n }\n\n return cell\n }\n\n protected mapCellValue(field: components['schemas']['FieldDefinition'], cellData?: string) {\n if (field.calculated) {\n return cellData\n }\n\n switch (field.type) {\n case 'boolean':\n return this.mapBoolean(cellData)\n\n case 'date':\n case 'time':\n return this.mapDate(cellData)\n\n default:\n return cellData\n }\n }\n\n protected mapHeader(disableSort = false, extraClasses: string | null = null): Cell[] {\n return this.fields\n .filter((field) => this.columns.includes(field.name))\n .map((f) => {\n if (this.reportQuery && !disableSort) {\n if (f.sortable) {\n let sortDirection = 'none'\n let url = createUrlForParameters(\n this.currentQueryParams || {},\n {\n sortColumn: f.name,\n sortedAsc: 'true',\n },\n this.fields,\n )\n\n if (f.name === this.reportQuery.sortColumn) {\n sortDirection = this.reportQuery.sortedAsc ? 'ascending' : 'descending'\n\n if (this.reportQuery.sortedAsc) {\n url = createUrlForParameters(\n this.currentQueryParams || {},\n {\n sortColumn: f.name,\n sortedAsc: 'false',\n },\n this.fields,\n )\n }\n }\n\n return {\n html:\n `<a ` +\n `data-column=\"${f.name}\" ` +\n `class=\"data-table-header-button data-table-header-button-sort-${sortDirection}\" ` +\n `href=\"${url}\"` +\n `>${f.display}</a>`,\n ...(extraClasses && { classes: extraClasses }),\n }\n }\n }\n return {\n text: f.display,\n ...(extraClasses && { classes: extraClasses }),\n }\n })\n }\n\n protected mapData(data: Array<Dict<string>>): Cell[][] {\n const mappedHeaderSummary = this.mapSummary('table-header')\n const mappedTableData = this.mergeCells(data.map((rowData) => this.mapRow(rowData)))\n const mappedFooterSummary = this.mapSummary('table-footer')\n\n return mappedHeaderSummary.concat(mappedTableData).concat(mappedFooterSummary)\n }\n\n private mergeCells(rows: Cell[][]): Cell[][] {\n const mergeFieldNames = this.fields\n .filter((f) => (<components['schemas']['SummaryField']>f).mergeRows)\n .map((f) => f.name)\n\n if (mergeFieldNames.length === 0) {\n return rows\n }\n\n const occurrences: Dict<Dict<number>> = {}\n mergeFieldNames.forEach((f) => {\n occurrences[f] = rows.reduce((accumulator: Dict<number>, currentRow) => {\n const currentCell = this.getCellByFieldName(currentRow, f)\n let cellValue = ''\n if (currentCell) {\n cellValue = currentCell.text || currentCell.html || ''\n }\n\n return {\n ...accumulator,\n [cellValue]: (accumulator[cellValue] ?? 0) + 1,\n }\n }, {})\n })\n\n return rows.map((row) => {\n let mergedRow = [...row]\n\n mergeFieldNames.forEach((mergeFieldName) => {\n const currentRowCell = this.getCellByFieldName(row, mergeFieldName)\n let cellValue\n let occurrencesOfValue\n if (currentRowCell && occurrences[mergeFieldName]) {\n cellValue = currentRowCell.text || currentRowCell.html || ''\n occurrencesOfValue = occurrences[mergeFieldName][cellValue]\n\n switch (occurrencesOfValue) {\n case -1:\n mergedRow = mergedRow.filter((c) => c.fieldName !== mergeFieldName)\n break\n\n case 1:\n break\n\n default:\n currentRowCell.rowspan = occurrencesOfValue\n occurrences[mergeFieldName][cellValue] = -1\n }\n }\n })\n\n return mergedRow\n })\n }\n\n private getCellByFieldName(row: Cell[], fieldName: string) {\n return row.find((c) => c.fieldName === fieldName)\n }\n\n private mapSummary(template: SummaryTemplate): Cell[][] {\n if (this.reportSummaries[template]) {\n return this.reportSummaries[template].flatMap((reportSummary) =>\n reportSummary.data.map((rowData) =>\n this.mapRow(\n rowData,\n `dpr-report-summary-cell dpr-report-summary-cell-${template}`,\n <components['schemas']['FieldDefinition'][]>reportSummary.fields,\n ),\n ),\n )\n }\n return []\n }\n\n protected sort(data: Dict<string>[]): Dict<string>[] {\n return this.appendSortKeyToData(data)\n .sort(this.sortKeyComparison())\n .map((d: SortKey) => ({\n ...d,\n }))\n }\n\n protected sortKeyComparison() {\n return (a: SortKey, b: SortKey) => {\n const aValue = a.sortKey\n const bValue = b.sortKey\n\n if (aValue === bValue) {\n return 0\n }\n\n if (aValue < bValue) {\n return -1\n }\n\n return 1\n }\n }\n\n private appendSortKeyToData(\n data: Dict<string>[],\n fields: components['schemas']['FieldDefinition'][] | null = null,\n ): SortKey[] {\n const sortFields = fields || this.fields\n\n return data.map((rowData) => {\n const sortKey = this.getSortKey(rowData, sortFields)\n\n return {\n ...rowData,\n sortKey,\n }\n })\n }\n\n protected mapNamesToFields(names: string[]): components['schemas']['FieldDefinition'][] {\n return names.map((s) => this.fields.find((f) => f.name === s)).filter((n) => n !== undefined)\n }\n\n protected getSortKey(rowData: NodeJS.Dict<string>, sortFields: components['schemas']['FieldDefinition'][]) {\n return sortFields\n .map((f) => {\n const value = rowData[f.name]\n if (value && this.dateMapper.isDate(value)) {\n return this.dateMapper.toDateString(value, 'iso')\n }\n\n return this.mapCellValue(f, value)\n })\n .join('-')\n .toLowerCase()\n }\n\n protected convertDataTableToHtml(dataTable: DataTable): string {\n const head = dataTable.head || []\n const headers = head.map((h) => `<th scope='col' class='govuk-table__header'>${h.html ?? h.text}</th>`)\n const rows = dataTable.rows.map(\n (r) =>\n `<tr class='govuk-table__row'>${r\n .map(\n (c) => `<td class='govuk-table__cell govuk-table__cell--${c.format} ${c.classes}'>${c.html ?? c.text}</td>`,\n )\n .join('')}</tr>`,\n )\n\n return (\n \"<table class='govuk-table'>\" +\n `<thead class='govuk-table__head'>${headers.join('')}</thead>` +\n `<tbody class='govuk-table__body'>${rows.join('')}</tbody>` +\n '</table>'\n )\n }\n\n withHeaderOptions({\n reportQuery,\n columns,\n interactive,\n }: {\n reportQuery?: ReportQuery\n columns: string[]\n interactive: boolean\n }) {\n if (interactive && reportQuery) {\n return this.withHeaderSortOptions(reportQuery)\n }\n return this.withNoHeaderOptions(columns)\n }\n\n withHeaderSortOptions(reportQuery: ReportQuery) {\n this.reportQuery = reportQuery\n this.columns = reportQuery.columns\n this.currentQueryParams = this.reportQuery.toRecordWithFilterPrefix()\n\n return this\n }\n\n withNoHeaderOptions(columns: string[]) {\n this.columns = columns\n return this\n }\n\n buildTable(data: Array<Dict<string>>): DataTable {\n const mappedData = this.mapData(this.sortData ? this.sort(data) : data)\n\n return {\n head: this.mapHeader(),\n rows: mappedData,\n rowCount: data.length,\n colCount: this.columns.length,\n }\n }\n\n withSummaries(reportSummaries: Dict<Array<AsyncSummary>>) {\n this.reportSummaries = reportSummaries\n return this\n }\n\n withSortedData(sortData = true) {\n this.sortData = sortData\n return this\n }\n}\n\nexport { DataTableBuilder }\nexport default DataTableBuilder\n"],
5
+ "mappings": "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",
6
6
  "names": ["DataTableBuilder_exports", "__export", "DataTableBuilder", "DataTableBuilder_default", "__toCommonJS", "import_urlHelper", "import_DateMapper", "fields", "sortData", "DateMapper", "isoDate", "value", "rowData", "extraClasses", "overrideFields", "f", "field", "o", "textValue", "fieldFormat", "classes", "isHtml", "cellData", "disableSort", "sortDirection", "url", "createUrlForParameters", "data", "mappedHeaderSummary", "mappedTableData", "mappedFooterSummary", "rows", "mergeFieldNames", "occurrences", "accumulator", "currentRow", "currentCell", "cellValue", "row", "mergedRow", "mergeFieldName", "currentRowCell", "occurrencesOfValue", "c", "fieldName", "template", "reportSummary", "d", "a", "b", "aValue", "bValue", "sortFields", "sortKey", "names", "s", "n", "dataTable", "headers", "h", "r", "reportQuery", "columns", "interactive", "mappedData", "reportSummaries"]
7
7
  }
@@ -1,13 +1,14 @@
1
1
  import Dict = NodeJS.Dict
2
2
  import ReportQuery from '../../types/ReportQuery'
3
- import { Cell, CellFormat, DataTable, FieldDefinition, SortKey } from './types'
3
+ import { Cell, CellFormat, DataTable, SortKey } from './types'
4
4
  import createUrlForParameters from '../urlHelper'
5
5
  import type { SummaryTemplate } from '../../types/Templates'
6
6
  import { AsyncSummary } from '../../types/UserReports'
7
7
  import DateMapper from '../DateMapper/DateMapper'
8
+ import { components } from '../../types/api'
8
9
 
9
10
  class DataTableBuilder {
10
- protected fields: Array<FieldDefinition>
11
+ protected fields: components['schemas']['FieldDefinition'][]
11
12
 
12
13
  private sortData: boolean
13
14
 
@@ -22,7 +23,7 @@ class DataTableBuilder {
22
23
 
23
24
  private dateMapper = new DateMapper()
24
25
 
25
- constructor(fields: Array<FieldDefinition>, sortData = false) {
26
+ constructor(fields: components['schemas']['FieldDefinition'][], sortData = false) {
26
27
  this.fields = fields
27
28
  this.sortData = sortData
28
29
  }
@@ -41,7 +42,7 @@ class DataTableBuilder {
41
42
  protected mapRow(
42
43
  rowData: NodeJS.Dict<string>,
43
44
  extraClasses = '',
44
- overrideFields: Array<FieldDefinition> = [],
45
+ overrideFields: components['schemas']['FieldDefinition'][] = [],
45
46
  ): Cell[] {
46
47
  return this.fields
47
48
  .filter((f) => this.columns.includes(f.name))
@@ -52,7 +53,7 @@ class DataTableBuilder {
52
53
  })
53
54
  }
54
55
 
55
- private mapCell(field: FieldDefinition, rowData: NodeJS.Dict<string>, extraClasses = '') {
56
+ private mapCell(field: components['schemas']['FieldDefinition'], rowData: NodeJS.Dict<string>, extraClasses = '') {
56
57
  const textValue = this.mapCellValue(field, rowData[field.name])
57
58
  let fieldFormat: CellFormat = 'string'
58
59
 
@@ -81,7 +82,7 @@ class DataTableBuilder {
81
82
  return cell
82
83
  }
83
84
 
84
- protected mapCellValue(field: FieldDefinition, cellData?: string) {
85
+ protected mapCellValue(field: components['schemas']['FieldDefinition'], cellData?: string) {
85
86
  if (field.calculated) {
86
87
  return cellData
87
88
  }
@@ -106,19 +107,27 @@ class DataTableBuilder {
106
107
  if (this.reportQuery && !disableSort) {
107
108
  if (f.sortable) {
108
109
  let sortDirection = 'none'
109
- let url = createUrlForParameters(this.currentQueryParams || {}, {
110
- sortColumn: f.name,
111
- sortedAsc: 'true',
112
- })
110
+ let url = createUrlForParameters(
111
+ this.currentQueryParams || {},
112
+ {
113
+ sortColumn: f.name,
114
+ sortedAsc: 'true',
115
+ },
116
+ this.fields,
117
+ )
113
118
 
114
119
  if (f.name === this.reportQuery.sortColumn) {
115
120
  sortDirection = this.reportQuery.sortedAsc ? 'ascending' : 'descending'
116
121
 
117
122
  if (this.reportQuery.sortedAsc) {
118
- url = createUrlForParameters(this.currentQueryParams || {}, {
119
- sortColumn: f.name,
120
- sortedAsc: 'false',
121
- })
123
+ url = createUrlForParameters(
124
+ this.currentQueryParams || {},
125
+ {
126
+ sortColumn: f.name,
127
+ sortedAsc: 'false',
128
+ },
129
+ this.fields,
130
+ )
122
131
  }
123
132
  }
124
133
 
@@ -149,7 +158,9 @@ class DataTableBuilder {
149
158
  }
150
159
 
151
160
  private mergeCells(rows: Cell[][]): Cell[][] {
152
- const mergeFieldNames = this.fields.filter((f) => f.mergeRows).map((f) => f.name)
161
+ const mergeFieldNames = this.fields
162
+ .filter((f) => (<components['schemas']['SummaryField']>f).mergeRows)
163
+ .map((f) => f.name)
153
164
 
154
165
  if (mergeFieldNames.length === 0) {
155
166
  return rows
@@ -209,7 +220,11 @@ class DataTableBuilder {
209
220
  if (this.reportSummaries[template]) {
210
221
  return this.reportSummaries[template].flatMap((reportSummary) =>
211
222
  reportSummary.data.map((rowData) =>
212
- this.mapRow(rowData, `dpr-report-summary-cell dpr-report-summary-cell-${template}`, reportSummary.fields),
223
+ this.mapRow(
224
+ rowData,
225
+ `dpr-report-summary-cell dpr-report-summary-cell-${template}`,
226
+ <components['schemas']['FieldDefinition'][]>reportSummary.fields,
227
+ ),
213
228
  ),
214
229
  )
215
230
  }
@@ -241,7 +256,10 @@ class DataTableBuilder {
241
256
  }
242
257
  }
243
258
 
244
- private appendSortKeyToData(data: Dict<string>[], fields: FieldDefinition[] | null = null): SortKey[] {
259
+ private appendSortKeyToData(
260
+ data: Dict<string>[],
261
+ fields: components['schemas']['FieldDefinition'][] | null = null,
262
+ ): SortKey[] {
245
263
  const sortFields = fields || this.fields
246
264
 
247
265
  return data.map((rowData) => {
@@ -254,11 +272,11 @@ class DataTableBuilder {
254
272
  })
255
273
  }
256
274
 
257
- protected mapNamesToFields(names: string[]): FieldDefinition[] {
275
+ protected mapNamesToFields(names: string[]): components['schemas']['FieldDefinition'][] {
258
276
  return names.map((s) => this.fields.find((f) => f.name === s)).filter((n) => n !== undefined)
259
277
  }
260
278
 
261
- protected getSortKey(rowData: NodeJS.Dict<string>, sortFields: FieldDefinition[]) {
279
+ protected getSortKey(rowData: NodeJS.Dict<string>, sortFields: components['schemas']['FieldDefinition'][]) {
262
280
  return sortFields
263
281
  .map((f) => {
264
282
  const value = rowData[f.name]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/dpr/utils/UserStoreItemBuilder.ts"],
4
- "sourcesContent": ["import type { Request } from 'express'\nimport parseUrl from 'parseurl'\nimport {\n AsyncReportUrlData,\n LoadType,\n ReportType,\n RequestedReport,\n RequestFormData,\n RequestStatus,\n UserReportData,\n} from '../types/UserReports'\nimport Dict = NodeJS.Dict\nimport { ChildReportExecutionData, ExecutionData } from '../types/ExecutionData'\nimport { DashboardSection } from '../components/_dashboards/dashboard/types'\n\nclass UserStoreItemBuilder {\n userStoreItem: UserReportData\n\n requestFormData: RequestFormData | Record<string, never>\n\n constructor(\n reportData: {\n type: ReportType\n reportId: string\n reportName: string\n description: string\n id: string\n name: string\n },\n requestFormData?: RequestFormData,\n ) {\n this.requestFormData = requestFormData || {}\n this.userStoreItem = this.addReportData(reportData)\n }\n\n build = () => {\n return this.userStoreItem as RequestedReport\n }\n\n addReportData = ({\n type,\n reportId,\n reportName,\n description,\n id,\n name,\n }: {\n type: ReportType\n reportId: string\n reportName: string\n description: string\n id: string\n name: string\n }) => {\n return {\n type: type as ReportType,\n reportId,\n reportName,\n description,\n id,\n name,\n timestamp: {},\n }\n }\n\n addExecutionData = (executionData: ExecutionData) => {\n this.userStoreItem = {\n ...(<UserReportData>this.userStoreItem),\n ...executionData,\n }\n return this\n }\n\n addChildExecutionData = (childExecutionData: Array<ChildReportExecutionData>) => {\n this.userStoreItem = {\n ...(<UserReportData>this.userStoreItem),\n childExecutionData,\n }\n return this\n }\n\n addFilters = (filterData?: Record<string, string>) => {\n const filtersQueryString = new URLSearchParams(filterData).toString()\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n filters: {\n data: filterData,\n queryString: filtersQueryString,\n },\n },\n }\n return this\n }\n\n addSortData = (sortData: Record<string, string>) => {\n const sortByQueryString = new URLSearchParams(sortData).toString()\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n sortBy: {\n data: sortData,\n queryString: sortByQueryString,\n },\n },\n }\n return this\n }\n\n addRequestUrls = (req: Request) => {\n const { origin, pathname, search, href } = this.requestFormData\n const { executionId, dataProductDefinitionsPath, dpdPathFromQuery } = this.userStoreItem\n\n // Polling path\n let pollingPath = req.baseUrl.replace('/filters', `/${executionId}/status`)\n if (dpdPathFromQuery) {\n pollingPath = `${pollingPath}?dataProductDefinitionsPath=${dataProductDefinitionsPath}`\n }\n const pollingFullUrl = `${origin}${pollingPath}`\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n url: {\n origin,\n request: {\n fullUrl: href,\n pathname,\n search,\n },\n polling: {\n fullUrl: pollingFullUrl,\n pathname: pollingPath,\n },\n },\n },\n }\n\n return this\n }\n\n addAsyncUrls = (url: AsyncReportUrlData) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n url,\n },\n }\n\n return this\n }\n\n addReportUrls = (req: Request) => {\n const origin = req.get('host')\n const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`\n const urlData = parseUrl(req)\n\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n url: {\n origin: origin || this.userStoreItem.url?.origin || '',\n ...(this.userStoreItem.url?.request && { request: this.userStoreItem.url.request }),\n ...(this.userStoreItem.url?.polling && { polling: this.userStoreItem.url.polling }),\n report: {\n ...(this.userStoreItem.url?.report && this.userStoreItem.url.report),\n fullUrl,\n ...(urlData && urlData.search && { search: urlData.search }),\n },\n },\n },\n }\n\n return this\n }\n\n addLoadType = (loadType: LoadType) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n loadType,\n }\n\n return this\n }\n\n addQuery = (queryData?: { query: Dict<string | string[]>; querySummary: Array<Dict<string>> }) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n ...(queryData && {\n query: {\n data: queryData.query,\n summary: queryData.querySummary,\n },\n }),\n }\n return this\n }\n\n addInteractiveQuery = (queryData?: { query: Dict<string>; querySummary: Array<Dict<string>> }) => {\n if (queryData) {\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n interactiveQuery: {\n data: queryData.query,\n summary: queryData.querySummary,\n },\n },\n }\n }\n return this\n }\n\n addStatus = (status: RequestStatus) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n status,\n }\n return this\n }\n\n addMetrics = (metrics: DashboardSection[]) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n metrics: metrics.filter((metric) => metric.display).map((metric) => ({ name: metric.display || '' })),\n }\n return this\n }\n\n addTimestamp = () => {\n const { status } = this.userStoreItem\n const ts = new Date()\n switch (status) {\n case RequestStatus.FAILED:\n this.userStoreItem.timestamp.failed = ts\n break\n case RequestStatus.EXPIRED:\n this.userStoreItem.timestamp.expired = ts\n break\n case RequestStatus.ABORTED:\n this.userStoreItem.timestamp.aborted = ts\n break\n case RequestStatus.FINISHED:\n this.userStoreItem.timestamp.completed = ts\n break\n case RequestStatus.SUBMITTED:\n this.userStoreItem.timestamp.requested = ts\n break\n case RequestStatus.STARTED:\n case RequestStatus.PICKED:\n break\n default:\n this.userStoreItem.timestamp.lastViewed = ts\n break\n }\n return this\n }\n\n addDefinitionsPath = (definitionsPath: string, dpdPathFromQuery: boolean) => {\n if (definitionsPath) {\n this.userStoreItem = {\n ...this.userStoreItem,\n dataProductDefinitionsPath: definitionsPath,\n dpdPathFromQuery,\n }\n }\n return this\n }\n}\n\nexport { UserStoreItemBuilder }\nexport default UserStoreItemBuilder\n"],
4
+ "sourcesContent": ["import type { Request } from 'express'\nimport parseUrl from 'parseurl'\nimport {\n AsyncReportUrlData,\n LoadType,\n ReportType,\n RequestedReport,\n RequestFormData,\n RequestStatus,\n UserReportData,\n} from '../types/UserReports'\nimport Dict = NodeJS.Dict\nimport { ChildReportExecutionData, ExecutionData } from '../types/ExecutionData'\nimport { DashboardSection } from '../components/_dashboards/dashboard/types'\n\nclass UserStoreItemBuilder {\n userStoreItem: UserReportData\n\n requestFormData: RequestFormData | Record<string, never>\n\n constructor(\n reportData: {\n type: ReportType\n reportId: string\n reportName: string\n description: string\n id: string\n name: string\n },\n requestFormData?: RequestFormData,\n ) {\n this.requestFormData = requestFormData || {}\n this.userStoreItem = this.addReportData(reportData)\n }\n\n build = () => {\n return this.userStoreItem as RequestedReport\n }\n\n addReportData = ({\n type,\n reportId,\n reportName,\n description,\n id,\n name,\n }: {\n type: ReportType\n reportId: string\n reportName: string\n description: string\n id: string\n name: string\n }) => {\n return {\n type: type as ReportType,\n reportId,\n reportName,\n description,\n id,\n name,\n timestamp: {},\n }\n }\n\n addExecutionData = (executionData: ExecutionData) => {\n this.userStoreItem = {\n ...(<UserReportData>this.userStoreItem),\n ...executionData,\n }\n return this\n }\n\n addChildExecutionData = (childExecutionData: Array<ChildReportExecutionData>) => {\n this.userStoreItem = {\n ...(<UserReportData>this.userStoreItem),\n childExecutionData,\n }\n return this\n }\n\n addFilters = (filterData?: Record<string, string>) => {\n const filtersQueryString = new URLSearchParams(filterData).toString()\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n filters: {\n data: filterData,\n queryString: filtersQueryString,\n },\n },\n }\n return this\n }\n\n addSortData = (sortData: Record<string, string>) => {\n const sortByQueryString = new URLSearchParams(sortData).toString()\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n sortBy: {\n data: sortData,\n queryString: sortByQueryString,\n },\n },\n }\n return this\n }\n\n addRequestUrls = (req: Request) => {\n const { origin, pathname, search, href } = this.requestFormData\n const { executionId, dataProductDefinitionsPath, dpdPathFromQuery } = this.userStoreItem\n\n // Polling path\n let pollingPath = req.baseUrl.replace('/filters', `/${executionId}/status`)\n if (dpdPathFromQuery) {\n pollingPath = `${pollingPath}?dataProductDefinitionsPath=${dataProductDefinitionsPath}`\n }\n const pollingFullUrl = `${origin}${pollingPath}`\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n url: {\n origin,\n request: {\n fullUrl: href,\n pathname,\n search,\n },\n polling: {\n fullUrl: pollingFullUrl,\n pathname: pollingPath,\n },\n },\n },\n }\n\n return this\n }\n\n addAsyncUrls = (url: AsyncReportUrlData) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n url,\n },\n }\n\n return this\n }\n\n addReportUrls = (req: Request) => {\n const origin = req.get('host')\n const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`\n const urlData = parseUrl(req)\n\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n url: {\n origin: origin || this.userStoreItem.url?.origin || '',\n ...(this.userStoreItem.url?.request && { request: this.userStoreItem.url.request }),\n ...(this.userStoreItem.url?.polling && { polling: this.userStoreItem.url.polling }),\n report: {\n ...(this.userStoreItem.url?.report && this.userStoreItem.url.report),\n fullUrl,\n ...(urlData && urlData.search && { search: urlData.search }),\n },\n },\n },\n }\n\n return this\n }\n\n addLoadType = (loadType: LoadType) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n loadType,\n }\n\n return this\n }\n\n addQuery = (queryData?: { query: Dict<string | string[]>; querySummary: Array<Dict<string>> }) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n ...(queryData && {\n query: {\n data: queryData.query,\n summary: queryData.querySummary,\n },\n }),\n }\n return this\n }\n\n addInteractiveQuery = (queryData?: { query: Dict<string | string[]>; querySummary: Array<Dict<string>> }) => {\n if (queryData) {\n this.userStoreItem = {\n ...this.userStoreItem,\n ...{\n interactiveQuery: {\n data: queryData.query,\n summary: queryData.querySummary,\n },\n },\n }\n }\n return this\n }\n\n addStatus = (status: RequestStatus) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n status,\n }\n return this\n }\n\n addMetrics = (metrics: DashboardSection[]) => {\n this.userStoreItem = {\n ...this.userStoreItem,\n metrics: metrics.filter((metric) => metric.display).map((metric) => ({ name: metric.display || '' })),\n }\n return this\n }\n\n addTimestamp = () => {\n const { status } = this.userStoreItem\n const ts = new Date()\n switch (status) {\n case RequestStatus.FAILED:\n this.userStoreItem.timestamp.failed = ts\n break\n case RequestStatus.EXPIRED:\n this.userStoreItem.timestamp.expired = ts\n break\n case RequestStatus.ABORTED:\n this.userStoreItem.timestamp.aborted = ts\n break\n case RequestStatus.FINISHED:\n this.userStoreItem.timestamp.completed = ts\n break\n case RequestStatus.SUBMITTED:\n this.userStoreItem.timestamp.requested = ts\n break\n case RequestStatus.STARTED:\n case RequestStatus.PICKED:\n break\n default:\n this.userStoreItem.timestamp.lastViewed = ts\n break\n }\n return this\n }\n\n addDefinitionsPath = (definitionsPath: string, dpdPathFromQuery: boolean) => {\n if (definitionsPath) {\n this.userStoreItem = {\n ...this.userStoreItem,\n dataProductDefinitionsPath: definitionsPath,\n dpdPathFromQuery,\n }\n }\n return this\n }\n}\n\nexport { UserStoreItemBuilder }\nexport default UserStoreItemBuilder\n"],
5
5
  "mappings": "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",
6
6
  "names": ["UserStoreItemBuilder_exports", "__export", "UserStoreItemBuilder", "UserStoreItemBuilder_default", "__toCommonJS", "import_parseurl", "import_UserReports", "reportData", "requestFormData", "type", "reportId", "reportName", "description", "id", "name", "executionData", "childExecutionData", "filterData", "filtersQueryString", "sortData", "sortByQueryString", "req", "origin", "pathname", "search", "href", "executionId", "dataProductDefinitionsPath", "dpdPathFromQuery", "pollingPath", "pollingFullUrl", "url", "fullUrl", "urlData", "parseUrl", "loadType", "queryData", "status", "metrics", "metric", "ts", "definitionsPath"]
7
7
  }
@@ -195,7 +195,7 @@ class UserStoreItemBuilder {
195
195
  return this
196
196
  }
197
197
 
198
- addInteractiveQuery = (queryData?: { query: Dict<string>; querySummary: Array<Dict<string>> }) => {
198
+ addInteractiveQuery = (queryData?: { query: Dict<string | string[]>; querySummary: Array<Dict<string>> }) => {
199
199
  if (queryData) {
200
200
  this.userStoreItem = {
201
201
  ...this.userStoreItem,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ministryofjustice/hmpps-digital-prison-reporting-frontend",
3
3
  "description": "The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.",
4
- "version": "4.15.0",
4
+ "version": "4.15.1",
5
5
  "main": "dpr/all.mjs",
6
6
  "sass": "dpr/all.scss",
7
7
  "engines": {
@@ -1,2 +0,0 @@
1
- var y=Object.create;var m=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var w=(a,r)=>{for(var s in r)m(a,s,{get:r[s],enumerable:!0})},p=(a,r,s,e)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of C(r))!x.call(a,t)&&t!==s&&m(a,t,{get:()=>r[t],enumerable:!(e=Y(r,t))||e.enumerable});return a};var D=(a,r,s)=>(s=a!=null?y(g(a)):{},p(r||!a||!a.__esModule?m(s,"default",{value:a,enumerable:!0}):s,a)),k=a=>p(m({},"__esModule",{value:!0}),a);var S={};w(S,{createTimeseriesMatrixChart:()=>z});module.exports=k(S);var c=D(require("dayjs")),M=require("with-alpha-hex"),b=require("../../../_dashboards/dashboard/types"),f=D(require("../../../../utils/datasetHelper"));const V=(a,r,s)=>{const{measures:e}=s;return a.map(t=>{const{raw:o,rag:n}=t[0][e[1].id],u=Number(o),d=n!==void 0?Number(t[0][e[1].id].rag):void 0;let i,l;switch(r){case"hourly":break;case"weekly":i=(0,c.default)(t[0].ts.raw,"DD/MM/YYYY").format("ddd"),l=(0,c.default)(t[0].ts.raw,"DD/MM/YYYY").week();break;case"daily":i=(0,c.default)(t[0].ts.raw,"DD/MM/YYYY").format("MMM YY"),l=(0,c.default)(t[0].ts.raw,"DD/MM/YYYY").format("D");break;case"monthly":{const h=t[0].ts.raw.split(" ");i=h[1],l=h[0]}break;case"annually":i="year",l=t[0].ts.raw;break;default:i=(0,c.default)(t[0].ts.raw,"DD/MM/YYYY").format("MMM YY"),l=(0,c.default)(t[0].ts.raw,"DD/MM/YYYY").format("D");break}return{y:l,x:i,v:u,r:d}})},R=(a,r,s,e)=>{const{columns:t}=s;v(s);const o=T(t);let n=V(a,r,t);return n=A(n,e),[{label:o,data:n}]},v=a=>{const{id:r,columns:s,type:e}=a,t=[];if(s.measures.length!==2?t.push(`Measures should only have 2 columns defined. Only found ${s.measures.length}`):e===b.DashboardVisualisationType.MATRIX_TIMESERIES&&s.measures[0].id!=="ts"&&t.push(`measure at index 0 has incorrect ID. Expected ID to be "ts". Found "${s.measures[0].id}"`),t.length){const o=`Validation: Visualisaton definition: ID: ${r}, type: ${e}, errors: ${t.join(",")}`;throw new Error(o)}},T=a=>a.measures[1].display,A=(a,r)=>{const{useRagColours:s}=r,e=G(a),t=e?$(a):3,o=I(t,s);return e?E(a,o):B(a,o)},B=(a,r)=>{const s=N(a,r.length),e=r.slice().reverse();return a.map(t=>{let o=0;return s.forEach((n,u)=>{t.v<=n&&(o=u)}),{...t,r:o,c:e[o]}})},E=(a,r)=>a.map(s=>({...s,c:r[s.r]})),I=(a,r)=>r?["#00703c","#ffdd00"," #d4351c"]:O(a),O=a=>{const r="#1d70b8",s=1/a;return Array.from(Array(a)).map((e,t)=>{const o=s*(t+1);return(0,M.withAlphaHex)(r,o)})},$=a=>Math.max(...a.map(r=>r.r))+1,G=a=>a[0].r!==void 0,N=(a,r)=>{const s=a.map(n=>n.v),e=Math.min(...s),t=Math.max(...s),o=Math.ceil((t-e)/r);return Array.from(Array(r)).map((n,u)=>o*(u+1)).reverse()},z=(a,r,s)=>{const{columns:e,options:t}=a,{measures:o}=e,n=o[0].unit?o[0].unit:void 0,u=a.type.split("-")[0],d=f.default.groupRowsByTimestamp(r),i=R(d,s,a,t);return{type:u,unit:n,timeseries:!0,data:{datasets:i}}};0&&(module.exports={createTimeseriesMatrixChart});
2
- //# sourceMappingURL=utils.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../../src/dpr/components/_charts/chart/heatmap/utils.ts"],
4
- "sourcesContent": ["/* eslint-disable prefer-destructuring */\nimport dayjs from 'dayjs'\nimport { withAlphaHex } from 'with-alpha-hex'\nimport {\n DashboardVisualisation,\n DashboardVisualisationColumns,\n DashboardVisualisationType,\n MatrixDashboardVisualisationOptions,\n} from '../../../_dashboards/dashboard/types'\nimport { Granularity } from '../../../_inputs/granular-date-range/types'\nimport { ChartData, ChartDataset, ChartType, MatrixChartData } from '../../../../types/Charts'\nimport { DashboardDataResponse } from '../../../../types/Metrics'\nimport DatasetHelper from '../../../../utils/datasetHelper'\n\nconst initTimeseriesMatrixAxis = (\n timeBlockData: DashboardDataResponse[][],\n granularity: Granularity,\n columns: DashboardVisualisationColumns,\n): MatrixChartData[] => {\n const { measures } = columns\n return timeBlockData.map((tsData) => {\n const { raw, rag } = tsData[0][measures[1].id]\n const v = Number(raw)\n const r = rag !== undefined ? Number(tsData[0][measures[1].id].rag) : undefined\n let x\n let y\n switch (granularity) {\n case 'hourly':\n break\n case 'weekly':\n x = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('ddd')\n y = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').week()\n break\n case 'daily':\n x = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('MMM YY')\n y = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('D')\n break\n case 'monthly':\n {\n const ts = (<string>tsData[0].ts.raw).split(' ')\n x = ts[1]\n y = ts[0]\n }\n break\n case 'annually':\n x = 'year'\n y = <string>tsData[0].ts.raw\n break\n default:\n x = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('MMM YY')\n y = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('D')\n break\n }\n\n return { y, x, v, r }\n })\n}\n\nconst createMatrixDataSet = (\n timeBlockData: DashboardDataResponse[][],\n granularity: Granularity,\n chartDefinition: DashboardVisualisation,\n options: MatrixDashboardVisualisationOptions,\n) => {\n const { columns } = chartDefinition\n validateDefinition(chartDefinition)\n const label = getLabel(columns)\n let data: MatrixChartData[] = initTimeseriesMatrixAxis(timeBlockData, granularity, columns)\n data = addBucketData(data, options)\n\n return [{ label, data }]\n}\n\nconst validateDefinition = (chartDefinition: DashboardVisualisation) => {\n const { id, columns, type } = chartDefinition\n\n const errors = []\n if (columns.measures.length !== 2) {\n errors.push(`Measures should only have 2 columns defined. Only found ${columns.measures.length}`)\n } else if (type === DashboardVisualisationType.MATRIX_TIMESERIES) {\n if (columns.measures[0].id !== 'ts') {\n errors.push(`measure at index 0 has incorrect ID. Expected ID to be \"ts\". Found \"${columns.measures[0].id}\"`)\n }\n }\n if (errors.length) {\n const message = `Validation: Visualisaton definition: ID: ${id}, type: ${type}, errors: ${errors.join(',')}`\n throw new Error(message)\n }\n}\n\nconst getLabel = (columns: DashboardVisualisationColumns) => {\n return columns.measures[1].display\n}\n\nconst addBucketData = (matrixDataSets: MatrixChartData[], options: MatrixDashboardVisualisationOptions) => {\n const { useRagColours } = options\n const hasRag = hasRagNumber(matrixDataSets)\n const bucketCount = hasRag ? getBucketCount(matrixDataSets) : 3\n const bucketColours = createRagColours(bucketCount, useRagColours)\n return hasRag ? setColoursForRag(matrixDataSets, bucketColours) : setColoursWithoutRag(matrixDataSets, bucketColours)\n}\n\nconst setColoursWithoutRag = (matrixDataSets: MatrixChartData[], bucketColours: string[]) => {\n const bucketSizes = getBucketSizes(matrixDataSets, bucketColours.length)\n const colours = bucketColours.slice().reverse()\n\n return matrixDataSets.map((dataPoint) => {\n let bucketNumber = 0\n bucketSizes.forEach((bucket, i) => {\n if (dataPoint.v <= bucket) bucketNumber = i\n })\n return { ...dataPoint, r: bucketNumber, c: colours[bucketNumber] }\n })\n}\n\nconst setColoursForRag = (matrixDataSets: MatrixChartData[], bucketColours: string[]) => {\n return matrixDataSets.map((dataPoint) => {\n return { ...dataPoint, c: bucketColours[dataPoint.r] }\n })\n}\n\nconst createRagColours = (bucketCount: number, useRagColours: boolean) => {\n const ragColours = ['#00703c', '#ffdd00', '\t#d4351c']\n return useRagColours ? ragColours : generateBucketColours(bucketCount)\n}\n\nconst generateBucketColours = (bucketCount: number) => {\n const baseColour = '#1d70b8'\n const alphaDivision = 1 / bucketCount\n return Array.from(Array(bucketCount)).map((d, i) => {\n const division = alphaDivision * (i + 1)\n return withAlphaHex(baseColour, division)\n })\n}\n\nconst getBucketCount = (matrixDataSets: MatrixChartData[]) => {\n return Math.max(...matrixDataSets.map((o) => o.r)) + 1\n}\n\nconst hasRagNumber = (matrixDataSets: MatrixChartData[]) => {\n return matrixDataSets[0].r !== undefined\n}\n\nconst getBucketSizes = (matrixDataSets: MatrixChartData[], bucketCount: number) => {\n const values = matrixDataSets.map((dataPoint) => dataPoint.v)\n const min = Math.min(...values)\n const max = Math.max(...values)\n const threshholdSize = Math.ceil((max - min) / bucketCount)\n return Array.from(Array(bucketCount))\n .map((d, i) => {\n return threshholdSize * (i + 1)\n })\n .reverse()\n}\n\nexport const createTimeseriesMatrixChart = (\n chartDefinition: DashboardVisualisation,\n timeseriesData: DashboardDataResponse[],\n granularity: Granularity,\n): ChartData => {\n const { columns, options } = chartDefinition\n const { measures } = columns\n\n const unit = measures[0].unit ? measures[0].unit : undefined\n const type = chartDefinition.type.split('-')[0]\n const timeBlockData = DatasetHelper.groupRowsByTimestamp(timeseriesData)\n const matrixDataSets: ChartDataset[] = createMatrixDataSet(\n timeBlockData,\n granularity,\n chartDefinition,\n <MatrixDashboardVisualisationOptions>options,\n )\n\n return {\n type: type as unknown as ChartType,\n unit,\n timeseries: true,\n data: {\n datasets: matrixDataSets,\n },\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["utils_exports", "__export", "createTimeseriesMatrixChart", "__toCommonJS", "import_dayjs", "import_with_alpha_hex", "import_types", "import_datasetHelper", "initTimeseriesMatrixAxis", "timeBlockData", "granularity", "columns", "measures", "tsData", "raw", "rag", "v", "r", "x", "y", "dayjs", "ts", "createMatrixDataSet", "chartDefinition", "options", "validateDefinition", "label", "getLabel", "data", "addBucketData", "id", "type", "errors", "message", "matrixDataSets", "useRagColours", "hasRag", "hasRagNumber", "bucketCount", "getBucketCount", "bucketColours", "createRagColours", "setColoursForRag", "setColoursWithoutRag", "bucketSizes", "getBucketSizes", "colours", "dataPoint", "bucketNumber", "bucket", "i", "generateBucketColours", "baseColour", "alphaDivision", "d", "division", "o", "values", "min", "max", "threshholdSize", "timeseriesData", "unit", "DatasetHelper"]
7
- }
@@ -1,182 +0,0 @@
1
- /* eslint-disable prefer-destructuring */
2
- import dayjs from 'dayjs'
3
- import { withAlphaHex } from 'with-alpha-hex'
4
- import {
5
- DashboardVisualisation,
6
- DashboardVisualisationColumns,
7
- DashboardVisualisationType,
8
- MatrixDashboardVisualisationOptions,
9
- } from '../../../_dashboards/dashboard/types'
10
- import { Granularity } from '../../../_inputs/granular-date-range/types'
11
- import { ChartData, ChartDataset, ChartType, MatrixChartData } from '../../../../types/Charts'
12
- import { DashboardDataResponse } from '../../../../types/Metrics'
13
- import DatasetHelper from '../../../../utils/datasetHelper'
14
-
15
- const initTimeseriesMatrixAxis = (
16
- timeBlockData: DashboardDataResponse[][],
17
- granularity: Granularity,
18
- columns: DashboardVisualisationColumns,
19
- ): MatrixChartData[] => {
20
- const { measures } = columns
21
- return timeBlockData.map((tsData) => {
22
- const { raw, rag } = tsData[0][measures[1].id]
23
- const v = Number(raw)
24
- const r = rag !== undefined ? Number(tsData[0][measures[1].id].rag) : undefined
25
- let x
26
- let y
27
- switch (granularity) {
28
- case 'hourly':
29
- break
30
- case 'weekly':
31
- x = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('ddd')
32
- y = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').week()
33
- break
34
- case 'daily':
35
- x = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('MMM YY')
36
- y = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('D')
37
- break
38
- case 'monthly':
39
- {
40
- const ts = (<string>tsData[0].ts.raw).split(' ')
41
- x = ts[1]
42
- y = ts[0]
43
- }
44
- break
45
- case 'annually':
46
- x = 'year'
47
- y = <string>tsData[0].ts.raw
48
- break
49
- default:
50
- x = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('MMM YY')
51
- y = dayjs(tsData[0].ts.raw, 'DD/MM/YYYY').format('D')
52
- break
53
- }
54
-
55
- return { y, x, v, r }
56
- })
57
- }
58
-
59
- const createMatrixDataSet = (
60
- timeBlockData: DashboardDataResponse[][],
61
- granularity: Granularity,
62
- chartDefinition: DashboardVisualisation,
63
- options: MatrixDashboardVisualisationOptions,
64
- ) => {
65
- const { columns } = chartDefinition
66
- validateDefinition(chartDefinition)
67
- const label = getLabel(columns)
68
- let data: MatrixChartData[] = initTimeseriesMatrixAxis(timeBlockData, granularity, columns)
69
- data = addBucketData(data, options)
70
-
71
- return [{ label, data }]
72
- }
73
-
74
- const validateDefinition = (chartDefinition: DashboardVisualisation) => {
75
- const { id, columns, type } = chartDefinition
76
-
77
- const errors = []
78
- if (columns.measures.length !== 2) {
79
- errors.push(`Measures should only have 2 columns defined. Only found ${columns.measures.length}`)
80
- } else if (type === DashboardVisualisationType.MATRIX_TIMESERIES) {
81
- if (columns.measures[0].id !== 'ts') {
82
- errors.push(`measure at index 0 has incorrect ID. Expected ID to be "ts". Found "${columns.measures[0].id}"`)
83
- }
84
- }
85
- if (errors.length) {
86
- const message = `Validation: Visualisaton definition: ID: ${id}, type: ${type}, errors: ${errors.join(',')}`
87
- throw new Error(message)
88
- }
89
- }
90
-
91
- const getLabel = (columns: DashboardVisualisationColumns) => {
92
- return columns.measures[1].display
93
- }
94
-
95
- const addBucketData = (matrixDataSets: MatrixChartData[], options: MatrixDashboardVisualisationOptions) => {
96
- const { useRagColours } = options
97
- const hasRag = hasRagNumber(matrixDataSets)
98
- const bucketCount = hasRag ? getBucketCount(matrixDataSets) : 3
99
- const bucketColours = createRagColours(bucketCount, useRagColours)
100
- return hasRag ? setColoursForRag(matrixDataSets, bucketColours) : setColoursWithoutRag(matrixDataSets, bucketColours)
101
- }
102
-
103
- const setColoursWithoutRag = (matrixDataSets: MatrixChartData[], bucketColours: string[]) => {
104
- const bucketSizes = getBucketSizes(matrixDataSets, bucketColours.length)
105
- const colours = bucketColours.slice().reverse()
106
-
107
- return matrixDataSets.map((dataPoint) => {
108
- let bucketNumber = 0
109
- bucketSizes.forEach((bucket, i) => {
110
- if (dataPoint.v <= bucket) bucketNumber = i
111
- })
112
- return { ...dataPoint, r: bucketNumber, c: colours[bucketNumber] }
113
- })
114
- }
115
-
116
- const setColoursForRag = (matrixDataSets: MatrixChartData[], bucketColours: string[]) => {
117
- return matrixDataSets.map((dataPoint) => {
118
- return { ...dataPoint, c: bucketColours[dataPoint.r] }
119
- })
120
- }
121
-
122
- const createRagColours = (bucketCount: number, useRagColours: boolean) => {
123
- const ragColours = ['#00703c', '#ffdd00', ' #d4351c']
124
- return useRagColours ? ragColours : generateBucketColours(bucketCount)
125
- }
126
-
127
- const generateBucketColours = (bucketCount: number) => {
128
- const baseColour = '#1d70b8'
129
- const alphaDivision = 1 / bucketCount
130
- return Array.from(Array(bucketCount)).map((d, i) => {
131
- const division = alphaDivision * (i + 1)
132
- return withAlphaHex(baseColour, division)
133
- })
134
- }
135
-
136
- const getBucketCount = (matrixDataSets: MatrixChartData[]) => {
137
- return Math.max(...matrixDataSets.map((o) => o.r)) + 1
138
- }
139
-
140
- const hasRagNumber = (matrixDataSets: MatrixChartData[]) => {
141
- return matrixDataSets[0].r !== undefined
142
- }
143
-
144
- const getBucketSizes = (matrixDataSets: MatrixChartData[], bucketCount: number) => {
145
- const values = matrixDataSets.map((dataPoint) => dataPoint.v)
146
- const min = Math.min(...values)
147
- const max = Math.max(...values)
148
- const threshholdSize = Math.ceil((max - min) / bucketCount)
149
- return Array.from(Array(bucketCount))
150
- .map((d, i) => {
151
- return threshholdSize * (i + 1)
152
- })
153
- .reverse()
154
- }
155
-
156
- export const createTimeseriesMatrixChart = (
157
- chartDefinition: DashboardVisualisation,
158
- timeseriesData: DashboardDataResponse[],
159
- granularity: Granularity,
160
- ): ChartData => {
161
- const { columns, options } = chartDefinition
162
- const { measures } = columns
163
-
164
- const unit = measures[0].unit ? measures[0].unit : undefined
165
- const type = chartDefinition.type.split('-')[0]
166
- const timeBlockData = DatasetHelper.groupRowsByTimestamp(timeseriesData)
167
- const matrixDataSets: ChartDataset[] = createMatrixDataSet(
168
- timeBlockData,
169
- granularity,
170
- chartDefinition,
171
- <MatrixDashboardVisualisationOptions>options,
172
- )
173
-
174
- return {
175
- type: type as unknown as ChartType,
176
- unit,
177
- timeseries: true,
178
- data: {
179
- datasets: matrixDataSets,
180
- },
181
- }
182
- }