@ministryofjustice/hmpps-digital-prison-reporting-frontend
Version:
The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.
245 lines (240 loc) • 9.76 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var dayjs = require('dayjs');
var weekOfYear = require('../../../_virtual/weekOfYear.js');
var VisualisationDatasetHelper = require('../../utils/Dashboards/VisualisationDatasetHelper.js');
var VisualisationUnitHelper = require('../../utils/Dashboards/VisualisationUnitHelper.js');
var utils = require('../_dashboards/dashboard-list/utils.js');
var types$1 = require('../_dashboards/dashboard-visualisation/types.js');
var types = require('../_inputs/granular-date-range/types.js');
var BarTimeseriesChart = require('./chart/bar-timeseries/BarTimeseriesChart.js');
var BarChart = require('./chart/bar/BarChart.js');
var DoughnutChart = require('./chart/doughnut/DoughnutChart.js');
var HeatmapChart = require('./chart/heatmap/HeatmapChart.js');
var LineTimeseriesChart = require('./chart/line-timeseries/LineTimeseriesChart.js');
var LineChart = require('./chart/line/LineChart.js');
dayjs.extend(weekOfYear);
const createChart = (chartDefinition, rawData, type) => {
let table;
let chart;
let details;
const { dataSetRows, snapshotData } = getDataForSnapshotCharts(chartDefinition, rawData);
if (dataSetRows.length) {
switch (type) {
case types$1.DashboardVisualisationType.BAR:
chart = new BarChart.BarChart().withDefinition(chartDefinition).withData(snapshotData).build();
break;
case types$1.DashboardVisualisationType.DONUT:
chart = new DoughnutChart.DoughnutChart().withDefinition(chartDefinition).withData(snapshotData).build();
break;
case types$1.DashboardVisualisationType.LINE:
chart = new LineChart.LineChart().withDefinition(chartDefinition).withData(snapshotData).build();
break;
}
table = createSnapshotTable(chartDefinition, dataSetRows);
details = getChartDetails(chartDefinition, dataSetRows);
}
return {
details,
table,
chart,
};
};
const createTimeseriesCharts = (chartDefinition, rawData, type, query, partialDate) => {
let table;
let chart;
let details;
let granularity = types.Granularity.DAILY;
if (query) {
Object.keys(query).forEach(key => {
if (key.includes('granularity')) {
granularity = query[key];
}
});
}
const { latestData, dataSetRows, timeseriesData } = getDataForTimeseriesCharts(chartDefinition, rawData);
if (dataSetRows.length) {
switch (type) {
case types$1.DashboardVisualisationType.MATRIX_TIMESERIES:
chart = new HeatmapChart.HeatmapChart()
.withDefinition(chartDefinition)
.withGranularity(granularity)
.withData(timeseriesData)
.build();
break;
case types$1.DashboardVisualisationType.LINE_TIMESERIES:
chart = new LineTimeseriesChart.LineTimeseriesChart()
.withDefinition(chartDefinition)
.withData(timeseriesData)
.withPartialDate(partialDate)
.build();
break;
case types$1.DashboardVisualisationType.BAR_TIMESERIES:
chart = new BarTimeseriesChart.BarTimeseriesChart()
.withDefinition(chartDefinition)
.withData(timeseriesData)
.withPartialDate(partialDate)
.build();
break;
}
table = createTimeseriesTable(chartDefinition, timeseriesData);
details = getChartDetails(chartDefinition, latestData, true);
}
return {
details,
table,
chart,
};
};
const getDataForSnapshotCharts = (chartDefinition, rawData) => {
const { columns } = chartDefinition;
const dateColumn = VisualisationDatasetHelper.default.getTimestampColumn(columns);
const data = VisualisationDatasetHelper.default.getLastestDataset(rawData, dateColumn);
const dataSetRows = VisualisationDatasetHelper.default.getDatasetRows(chartDefinition, data);
const snapshotData = VisualisationDatasetHelper.default.filterRowsByDisplayColumns(chartDefinition, dataSetRows, true);
return {
dataSetRows,
snapshotData,
};
};
const getDataForTimeseriesCharts = (chartDefinition, rawData) => {
const dateMeasure = VisualisationDatasetHelper.default.getTimestampMeasure(chartDefinition.columns.measures);
const latestData = VisualisationDatasetHelper.default.getLastestDataset(rawData, dateMeasure);
const dataSetRows = VisualisationDatasetHelper.default.getDatasetRows(chartDefinition, rawData);
const timeseriesData = VisualisationDatasetHelper.default.filterRowsByDisplayColumns(chartDefinition, dataSetRows, true);
return {
latestData,
dataSetRows,
timeseriesData,
};
};
const getChartDetails = (chartDefinition, data, timeseries = false) => {
const { columns } = chartDefinition;
const meta = [];
const headlines = createHeadlines(chartDefinition, data, timeseries);
const dateColumn = VisualisationDatasetHelper.getTimestampColumn(columns);
const dateData = VisualisationDatasetHelper.getDateValue(data, dateColumn);
if (dateData) {
const { value } = dateData;
meta.push({
label: 'Values for:',
value,
});
}
return {
meta,
headlines,
};
};
const createHeadlines = (chartDefinition, data, timeseries = false) => {
const headlines = [];
const { columns } = chartDefinition;
const { measures } = columns;
const isListChart = !!measures.find(col => col.axis);
let headline;
let headlineColumn;
let value;
let label = '';
if (timeseries) {
headlineColumn = measures.find(col => col.type !== 'timestamp');
if (headlineColumn) {
const { id } = headlineColumn;
const rawValue = data[0][id]?.raw;
const dateColumn = VisualisationDatasetHelper.getTimestampMeasure(measures);
const dateData = VisualisationDatasetHelper.getDateValue(data, dateColumn);
if (dateData) {
label = dateData.value;
}
const numericValue = Number(rawValue);
value = Number.isNaN(numericValue) ? undefined : numericValue;
if (value) {
headline = {
label,
value,
};
}
}
}
else {
headlineColumn = !isListChart ? measures[0] : measures.find(col => col.axis && col.axis === 'y');
if (headlineColumn) {
const display = headlineColumn.display?.toLowerCase();
label = display ? `Total ${display}` : 'Total';
value = data.reduce((acc, d) => {
if (headlineColumn) {
const { id } = headlineColumn;
const { raw } = d[id];
if (raw) {
return acc + Number(raw);
}
}
return acc;
}, 0);
headline = {
label,
value,
};
}
}
if (headline)
headlines.push(headline);
return headlines;
};
const mapTableHead = (headerColumns) => {
return headerColumns.map(column => {
const unitSymbol = VisualisationUnitHelper.mapUnitToSymbol(column.unit);
const headText = unitSymbol ? `${column.display} (${unitSymbol})` : column.display;
return { text: headText || '' };
});
};
const createSnapshotTable = (chartDefinition, data) => {
const { columns } = chartDefinition;
const { measures } = columns;
const keys = columns.keys || [];
const head = mapTableHead([...keys, ...measures]);
const filteredRowData = VisualisationDatasetHelper.default.filterRowsByDisplayColumns(chartDefinition, data, true);
const rows = utils.default.createTableRows(filteredRowData);
return {
head,
rows,
};
};
/**
* Creates the a table representation for a timeseries chart
* - ensures the Date column is always at index 0 when there are multiple rows
*
* @param {components['schemas']['DashboardVisualisationDefinition']} chartDefinition
* @param {DashboardDataResponse[]} timeseriesData
* @return {*} {MoJTable}
*/
const createTimeseriesTable = (chartDefinition, timeseriesData) => {
const { columns } = chartDefinition;
const { keys, measures = [] } = columns;
const safeKeys = keys ?? [];
let flatTimeseriesData = timeseriesData.flat();
let tableColumns;
if (timeseriesData.length > 1) {
const tsMeasures = measures.filter(m => m.type === 'timestamp');
if (tsMeasures.length !== 1) {
throw new Error('Multi-timeseries tables require exactly one date measure');
}
const [tsColumn] = tsMeasures;
const valueColumns = measures.filter(m => m.id !== tsColumn.id);
tableColumns = [tsColumn, ...safeKeys, ...valueColumns];
}
else {
flatTimeseriesData = VisualisationDatasetHelper.default.filterRowsByDisplayColumns(chartDefinition, flatTimeseriesData);
tableColumns = measures;
}
const head = mapTableHead(tableColumns);
const rows = utils.default.createTableRows(flatTimeseriesData, tableColumns);
return { head, rows };
};
var ChartUtils = {
createChart,
createTimeseriesCharts,
};
exports.createChart = createChart;
exports.createTimeseriesCharts = createTimeseriesCharts;
exports.default = ChartUtils;
//# sourceMappingURL=utils.js.map