@isoftdata/utility-dashboard-backend 2.0.2 → 2.1.0
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.
- package/README.md +19 -6
- package/dist/chart-helper.d.ts +32 -0
- package/dist/chart-helper.js +240 -0
- package/dist/formatting-templates.d.ts +3 -0
- package/dist/formatting-templates.js +17 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +321 -0
- package/dist/style-templates.d.ts +4 -0
- package/dist/style-templates.js +33 -0
- package/dist/types/chart.d.ts +91 -0
- package/dist/types/chart.js +3 -0
- package/dist/types/parameter.d.ts +37 -0
- package/dist/types/parameter.js +3 -0
- package/dist/types/report.d.ts +24 -0
- package/dist/types/report.js +3 -0
- package/dist/types/session.d.ts +9 -0
- package/dist/types/session.js +3 -0
- package/package.json +26 -5
- package/.gitattributes +0 -2
- package/chart-helper.js +0 -268
- package/empty dashboard schema.sql +0 -65
- package/formatter-templates.json +0 -15
- package/index.js +0 -284
- package/schema.md +0 -125
- package/style-templates.js +0 -31
- package/stylingTest.jsonc +0 -37
package/dist/index.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.formatterTemplates = exports.handleFormattingTemplates = exports.parameterizeQuery = exports.loadDataTableAndProcessedFormatting = exports.loadDataTable = exports.loadOutputParameterValues = exports.formatChartDataForReport = exports.formatReportMetadata = void 0;
|
|
30
|
+
const db = require('@isoftdata/utility-db');
|
|
31
|
+
const chart_helper_js_1 = require("./chart-helper.js");
|
|
32
|
+
Object.defineProperty(exports, "handleFormattingTemplates", { enumerable: true, get: function () { return chart_helper_js_1.handleFormattingTemplates; } });
|
|
33
|
+
const utility_date_time_1 = require("@isoftdata/utility-date-time");
|
|
34
|
+
const formatterTemplates = __importStar(require("./formatting-templates"));
|
|
35
|
+
exports.formatterTemplates = formatterTemplates;
|
|
36
|
+
const formatDate = require('date-fns/format');
|
|
37
|
+
const camelcase_1 = __importDefault(require("camelcase"));
|
|
38
|
+
const mysql = require('mysql');
|
|
39
|
+
const deepmerge = require('deepmerge');
|
|
40
|
+
const handleChartTypeSpecificQuirks = (chartType, resultSet) => {
|
|
41
|
+
if (resultSet.length) {
|
|
42
|
+
switch (chartType) {
|
|
43
|
+
case 'PieChart':
|
|
44
|
+
resultSet = (0, chart_helper_js_1.makeNegativeNumbericValuesZero)(resultSet);
|
|
45
|
+
break;
|
|
46
|
+
case 'TreeMap':
|
|
47
|
+
resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[1], resultSet);
|
|
48
|
+
if (resultSet.length === 1) {
|
|
49
|
+
resultSet[0].id = 'No Data';
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[0], resultSet);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return resultSet;
|
|
57
|
+
};
|
|
58
|
+
async function loadChartData(mysqlConnection, chart, queryObject) {
|
|
59
|
+
let { formatting, chartWrapper, multiSeries, table, supertype, cumulative, ...theRest } = chart;
|
|
60
|
+
if (!chartWrapper) {
|
|
61
|
+
chartWrapper = {
|
|
62
|
+
chartType: supertype,
|
|
63
|
+
options: {
|
|
64
|
+
height: 450, width: 800,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
cumulative = cumulative || (chartWrapper?.chartType === 'AreaChart' && cumulative !== false);
|
|
69
|
+
let dataTable = {}, processedFormatting = {};
|
|
70
|
+
try {
|
|
71
|
+
const dataTableAndProcessedFormatting = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType: chartWrapper?.chartType, cumulative, table });
|
|
72
|
+
dataTable = dataTableAndProcessedFormatting.dataTable;
|
|
73
|
+
processedFormatting = dataTableAndProcessedFormatting.processedFormatting;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error('Error loading dataTable / processedFormatting');
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
if (chartWrapper?.chartType === 'Table') {
|
|
80
|
+
return {
|
|
81
|
+
...theRest,
|
|
82
|
+
supertype,
|
|
83
|
+
chartWrapper,
|
|
84
|
+
table: { ...table, ...dataTable },
|
|
85
|
+
formatting: processedFormatting,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
...theRest,
|
|
90
|
+
cumulative,
|
|
91
|
+
supertype,
|
|
92
|
+
chartWrapper: {
|
|
93
|
+
...chartWrapper,
|
|
94
|
+
dataTable: dataTable,
|
|
95
|
+
},
|
|
96
|
+
formatting: processedFormatting,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
async function loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType, cumulative = false, table = {} }) {
|
|
100
|
+
let { results: queryResultSet, fields } = (queryObject?.sql) ? await (0, chart_helper_js_1.queryWithFields)(mysqlConnection, queryObject) : { fields: {}, results: [] };
|
|
101
|
+
queryResultSet = queryResultSet;
|
|
102
|
+
let data = handleChartTypeSpecificQuirks(chartType, queryResultSet);
|
|
103
|
+
if (multiSeries) {
|
|
104
|
+
({ data, formatting, fields } = (0, chart_helper_js_1.getMultiSeriesData)({
|
|
105
|
+
data,
|
|
106
|
+
seriesOptions: multiSeries,
|
|
107
|
+
formatting,
|
|
108
|
+
fields,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
const processedFormatting = (0, chart_helper_js_1.handleFormattingTemplates)(formatting);
|
|
112
|
+
if (chartType?.toLowerCase() === 'table') {
|
|
113
|
+
return { dataTable: (0, chart_helper_js_1.getRactiveTableDataFormat)(data, fields, processedFormatting, table?.style), processedFormatting };
|
|
114
|
+
}
|
|
115
|
+
let dataTable = (0, chart_helper_js_1.getDataTableFormat)(data, fields, multiSeries);
|
|
116
|
+
if (cumulative || chartType === 'AreaChart') {
|
|
117
|
+
dataTable = (0, chart_helper_js_1.makeDataCumulative)(dataTable, cumulative);
|
|
118
|
+
}
|
|
119
|
+
return { dataTable, processedFormatting };
|
|
120
|
+
}
|
|
121
|
+
exports.loadDataTableAndProcessedFormatting = loadDataTableAndProcessedFormatting;
|
|
122
|
+
async function loadDataTable(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType }) {
|
|
123
|
+
const { dataTable } = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType });
|
|
124
|
+
return dataTable;
|
|
125
|
+
}
|
|
126
|
+
exports.loadDataTable = loadDataTable;
|
|
127
|
+
const loadOptionList = async (mysqlConnection, optionListQuery, optionList = []) => {
|
|
128
|
+
return [
|
|
129
|
+
...optionList,
|
|
130
|
+
...(optionListQuery && await db.query(mysqlConnection, optionListQuery)) || [],
|
|
131
|
+
];
|
|
132
|
+
};
|
|
133
|
+
async function loadOutputParameterValues(mysqlConnection, { definitionList = [], selectionList = [], forClient = false, session, site = 'store', siteIdColumn, siteNameColumn }) {
|
|
134
|
+
if (!(definitionList instanceof Array) || !definitionList.length) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
const parameterValues = [];
|
|
138
|
+
for (const definition of definitionList) {
|
|
139
|
+
const matchingParameterSelection = selectionList.find(param => param.name === definition.name);
|
|
140
|
+
let typedParameter;
|
|
141
|
+
const baseParameter = {
|
|
142
|
+
name: definition.name,
|
|
143
|
+
title: definition.title || definition.name,
|
|
144
|
+
default: definition.default,
|
|
145
|
+
value: (matchingParameterSelection?.value) ?? definition.default,
|
|
146
|
+
queryValues: {},
|
|
147
|
+
};
|
|
148
|
+
if (definition.type === 'dateRange') {
|
|
149
|
+
baseParameter.value = baseParameter.value || 'Last 30 Days';
|
|
150
|
+
typedParameter = {
|
|
151
|
+
...baseParameter,
|
|
152
|
+
type: 'dateRange',
|
|
153
|
+
dates: matchingParameterSelection?.dates ?? (0, utility_date_time_1.datesFromRange)(baseParameter.value),
|
|
154
|
+
};
|
|
155
|
+
if (typedParameter.value !== 'Custom') {
|
|
156
|
+
typedParameter.dates = (0, utility_date_time_1.datesFromRange)(typedParameter.value);
|
|
157
|
+
}
|
|
158
|
+
if (!forClient) {
|
|
159
|
+
typedParameter.queryValues = {
|
|
160
|
+
[`${typedParameter.name}_start_date`]: typedParameter.dates.from,
|
|
161
|
+
[`${typedParameter.name}_end_date`]: typedParameter.dates.to,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (definition.type === 'selection') {
|
|
166
|
+
typedParameter = {
|
|
167
|
+
...baseParameter,
|
|
168
|
+
type: 'selection',
|
|
169
|
+
optionListQuery: definition?.optionListQuery,
|
|
170
|
+
optionList: definition?.optionList,
|
|
171
|
+
};
|
|
172
|
+
typedParameter.optionList = await loadOptionList(mysqlConnection, typedParameter.optionListQuery, typedParameter.optionList);
|
|
173
|
+
if (!typedParameter.optionList.some(option => option.id?.toString() === typedParameter.value?.toString())) {
|
|
174
|
+
typedParameter.value = typedParameter.optionList?.[0]?.id?.toString();
|
|
175
|
+
}
|
|
176
|
+
const option = typedParameter.optionList.find(option => option.id.toString() === typedParameter.value);
|
|
177
|
+
if (!forClient) {
|
|
178
|
+
typedParameter.queryValues = {
|
|
179
|
+
[typedParameter.name]: option?.rawSql ? mysql.raw(typedParameter.value) : typedParameter.value,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (definition.type === 'siteSelection') {
|
|
184
|
+
typedParameter = {
|
|
185
|
+
...baseParameter,
|
|
186
|
+
type: 'siteSelection',
|
|
187
|
+
permission: definition?.permission,
|
|
188
|
+
optionList: definition?.optionList,
|
|
189
|
+
};
|
|
190
|
+
typedParameter.value = typedParameter.value ?? (session.siteId ?? session[`${site}Id`]);
|
|
191
|
+
siteIdColumn = siteIdColumn ? mysqlConnection.escapeId(siteIdColumn) : mysqlConnection.escapeId(`${site}id`);
|
|
192
|
+
siteNameColumn = siteNameColumn ? mysqlConnection.escapeId(siteNameColumn) : 'name';
|
|
193
|
+
const siteTableName = mysqlConnection.escapeId(site);
|
|
194
|
+
if (typedParameter.permission) {
|
|
195
|
+
typedParameter.optionList = await db.query(mysqlConnection, {
|
|
196
|
+
sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_check_user_permission(?, ?, ${siteIdColumn})`,
|
|
197
|
+
values: [session.userAccountId, definition.permission],
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
typedParameter.optionList = await db.query(mysqlConnection, {
|
|
202
|
+
sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_useraccount_has_site_access(?, ${siteIdColumn})`,
|
|
203
|
+
values: [session.userAccountId],
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (typedParameter.optionList.length > 1) {
|
|
207
|
+
typedParameter.optionList.unshift({ id: 0, name: 'All' });
|
|
208
|
+
}
|
|
209
|
+
if (!typedParameter.optionList.some(option => option.id?.toString() === baseParameter.value?.toString())) {
|
|
210
|
+
typedParameter.value = typedParameter.optionList?.[0]?.id.toString();
|
|
211
|
+
}
|
|
212
|
+
if (!forClient && typedParameter.value?.toString() === '0') {
|
|
213
|
+
typedParameter.queryValues = {
|
|
214
|
+
[typedParameter.name]: typedParameter.optionList
|
|
215
|
+
.filter(({ id }) => id > 0)
|
|
216
|
+
.map(({ id }) => id?.toString()),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
else if (!forClient) {
|
|
220
|
+
typedParameter.queryValues = {
|
|
221
|
+
[typedParameter.name]: [typedParameter.value],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else if (definition.type === 'date') {
|
|
226
|
+
typedParameter = {
|
|
227
|
+
...baseParameter,
|
|
228
|
+
type: 'date',
|
|
229
|
+
};
|
|
230
|
+
typedParameter.value = typedParameter.value || formatDate(new Date(), 'yyyy-MM-dd');
|
|
231
|
+
if (!forClient) {
|
|
232
|
+
typedParameter.queryValues = {
|
|
233
|
+
[typedParameter.name]: typedParameter.value,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else if (definition.type === 'session') {
|
|
238
|
+
typedParameter = {
|
|
239
|
+
...baseParameter,
|
|
240
|
+
type: 'session',
|
|
241
|
+
};
|
|
242
|
+
const parameterName = (0, camelcase_1.default)(definition.name);
|
|
243
|
+
baseParameter.value = (session[parameterName] ?? '').toString();
|
|
244
|
+
if (!forClient) {
|
|
245
|
+
typedParameter.queryValues = {
|
|
246
|
+
[typedParameter.name]: typedParameter.value,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
throw new Error(`Parameter type mismatch for ${baseParameter.name}`);
|
|
252
|
+
}
|
|
253
|
+
parameterValues.push(typedParameter);
|
|
254
|
+
}
|
|
255
|
+
return parameterValues;
|
|
256
|
+
}
|
|
257
|
+
exports.loadOutputParameterValues = loadOutputParameterValues;
|
|
258
|
+
const parameterizeQuery = (queryString, parameterValues) => {
|
|
259
|
+
if (!queryString) {
|
|
260
|
+
return {
|
|
261
|
+
sql: '',
|
|
262
|
+
values: [],
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const queryParameterValues = parameterValues.reduce((acc, val) => {
|
|
266
|
+
return val.queryValues ? {
|
|
267
|
+
...acc,
|
|
268
|
+
...val.queryValues,
|
|
269
|
+
} : acc;
|
|
270
|
+
}, {});
|
|
271
|
+
const regexp = /\${([^}]+)}/g;
|
|
272
|
+
const queryParameterKeys = [...queryString.matchAll(regexp)].map(([, insideToken]) => insideToken.trim());
|
|
273
|
+
const queryParameters = queryParameterKeys.map(key => queryParameterValues[key] || null);
|
|
274
|
+
return {
|
|
275
|
+
sql: queryString.replace(regexp, '?'),
|
|
276
|
+
values: queryParameters,
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
exports.parameterizeQuery = parameterizeQuery;
|
|
280
|
+
async function formatReportMetadata(mysqlConnection, { report, chartsInReport, session = {}, site, siteIdColumn, siteNameColumn }) {
|
|
281
|
+
try {
|
|
282
|
+
const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: report.parameters, forClient: true, session, site, siteIdColumn, siteNameColumn });
|
|
283
|
+
return {
|
|
284
|
+
dashboardReportId: report.dashboardReportId,
|
|
285
|
+
name: report.reportName,
|
|
286
|
+
title: report.reportTitle,
|
|
287
|
+
charts: chartsInReport,
|
|
288
|
+
parameterValues,
|
|
289
|
+
ownerId: report.ownerId,
|
|
290
|
+
autoRefreshInterval: report.autoRefreshInterval,
|
|
291
|
+
description: report.description ?? '',
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
console.error(err);
|
|
296
|
+
throw err;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
exports.formatReportMetadata = formatReportMetadata;
|
|
300
|
+
async function formatChartDataForReport(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList, session = {}, site, siteIdColumn, siteNameColumn }) {
|
|
301
|
+
try {
|
|
302
|
+
const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: reportParameters, selectionList: parameterSelectionList, session, site, siteIdColumn, siteNameColumn });
|
|
303
|
+
if (reportChart?.jsonOverride?.chartWrapper?.dataTable) {
|
|
304
|
+
const { dataTable, ...chartWrapper } = reportChart.jsonOverride.chartWrapper;
|
|
305
|
+
reportChart.jsonOverride.chartWrapper = chartWrapper;
|
|
306
|
+
}
|
|
307
|
+
const combinedChart = deepmerge(chart, reportChart.jsonOverride ?? {});
|
|
308
|
+
return await loadChartData(mysqlConnection, {
|
|
309
|
+
...combinedChart,
|
|
310
|
+
rank: reportChart.rank,
|
|
311
|
+
reportChartId: reportChart.reportChartId,
|
|
312
|
+
description: combinedChart.description ?? '',
|
|
313
|
+
}, parameterizeQuery(chart.query, parameterValues));
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
console.error(err);
|
|
317
|
+
throw err;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
exports.formatChartDataForReport = formatChartDataForReport;
|
|
321
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQTtBQUMzQyx1REFTNkM7QUF3YTVDLDBHQTdhQSwyQ0FBeUIsT0E2YUE7QUF2YTFCLG9FQUE2RDtBQUM3RCwyRUFBNEQ7QUF1YTNELGdEQUFrQjtBQXRhbkIsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUE7QUFDN0MsMERBQWlDO0FBQ2pDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQTtBQUM5QixNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUE7QUFNdEMsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLFNBQWlCLEVBQUUsU0FBMEIsRUFBRSxFQUFFO0lBQ3ZGLElBQUksU0FBUyxDQUFDLE1BQU0sRUFBRTtRQUNyQixRQUFRLFNBQVMsRUFBRTtZQUNsQixLQUFLLFVBQVU7Z0JBRWQsU0FBUyxHQUFHLElBQUEsZ0RBQThCLEVBQUMsU0FBUyxDQUFDLENBQUE7Z0JBQ3JELE1BQUs7WUFDTixLQUFLLFNBQVM7Z0JBRWIsU0FBUyxHQUFHLElBQUEsa0NBQWdCLEVBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQTtnQkFDckUsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtvQkFDM0IsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUE7aUJBQzNCO2dCQUNELE1BQUs7WUFDTjtnQkFFQyxTQUFTLEdBQUcsSUFBQSxrQ0FBZ0IsRUFBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FB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
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mathjs_1 = require("mathjs");
|
|
7
|
+
const snakecase_keys_1 = __importDefault(require("snakecase-keys"));
|
|
8
|
+
const klona_1 = require("klona");
|
|
9
|
+
function handleMathJsCellStyleTemplate(row, columnToStyle, templates) {
|
|
10
|
+
const outCell = { value: row[columnToStyle]?.toString() };
|
|
11
|
+
if (columnToStyle in templates) {
|
|
12
|
+
const scope = (0, snakecase_keys_1.default)((0, klona_1.klona)(row), { deep: true });
|
|
13
|
+
for (const key in templates[columnToStyle]) {
|
|
14
|
+
try {
|
|
15
|
+
const expression = templates[columnToStyle][key] ?? '';
|
|
16
|
+
outCell[key] = (0, mathjs_1.evaluate)(expression, scope);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
console.error(`Error evaluating expression: '${templates[columnToStyle][key]}'\n`, err);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return outCell;
|
|
24
|
+
}
|
|
25
|
+
function styleRow(row, templates) {
|
|
26
|
+
const outRow = {};
|
|
27
|
+
for (const columnName in row) {
|
|
28
|
+
outRow[columnName] = handleMathJsCellStyleTemplate(row, columnName, templates);
|
|
29
|
+
}
|
|
30
|
+
return outRow;
|
|
31
|
+
}
|
|
32
|
+
exports.default = styleRow;
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3R5bGUtdGVtcGxhdGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3N0eWxlLXRlbXBsYXRlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUlBLG1DQUFpQztBQUVqQyxvRUFBMEM7QUFDMUMsaUNBQTZCO0FBRTdCLFNBQVMsNkJBQTZCLENBQUMsR0FBa0IsRUFBRSxhQUFxQixFQUFFLFNBQW1DO0lBQ3BILE1BQU0sT0FBTyxHQUFHLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxhQUFhLENBQUMsRUFBRSxRQUFRLEVBQUUsRUFBcUMsQ0FBQTtJQUM1RixJQUFJLGFBQWEsSUFBSSxTQUFTLEVBQUU7UUFFL0IsTUFBTSxLQUFLLEdBQUcsSUFBQSx3QkFBYSxFQUFDLElBQUEsYUFBSyxFQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUE7UUFDdkQsS0FBSyxNQUFNLEdBQUcsSUFBSSxTQUFTLENBQUMsYUFBYSxDQUFDLEVBQUU7WUFDM0MsSUFBSTtnQkFDSCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFBO2dCQUN0RCxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBQSxpQkFBUSxFQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQTthQUMxQztZQUFDLE9BQU8sR0FBRyxFQUFFO2dCQUdiLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFBO2FBQ3ZGO1NBQ0Q7S0FDRDtJQUNELE9BQU8sT0FBTyxDQUFBO0FBQ2YsQ0FBQztBQUVELFNBQVMsUUFBUSxDQUFDLEdBQWtCLEVBQUUsU0FBbUM7SUFDeEUsTUFBTSxNQUFNLEdBQUcsRUFBbUIsQ0FBQTtJQUNsQyxLQUFLLE1BQU0sVUFBVSxJQUFJLEdBQUcsRUFBRTtRQUM3QixNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsNkJBQTZCLENBQUMsR0FBRyxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQUMsQ0FBQTtLQUM5RTtJQUNELE9BQU8sTUFBTSxDQUFBO0FBQ2QsQ0FBQztBQUVELGtCQUFlLFFBQVEsQ0FBQSJ9
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export type GoogleDataTableCell = {
|
|
2
|
+
v?: any;
|
|
3
|
+
f?: string | undefined;
|
|
4
|
+
p?: any;
|
|
5
|
+
};
|
|
6
|
+
export type GoogleDataTableColumn = {
|
|
7
|
+
type: string;
|
|
8
|
+
id?: string | undefined;
|
|
9
|
+
label?: string | undefined;
|
|
10
|
+
pattern?: string | undefined;
|
|
11
|
+
p?: any;
|
|
12
|
+
};
|
|
13
|
+
export type GoogleDataTableRow = {
|
|
14
|
+
c: GoogleDataTableCell[];
|
|
15
|
+
p?: any;
|
|
16
|
+
};
|
|
17
|
+
export type GoogleDataTable = {
|
|
18
|
+
cols: GoogleDataTableColumn[];
|
|
19
|
+
rows: GoogleDataTableRow[];
|
|
20
|
+
p?: any;
|
|
21
|
+
};
|
|
22
|
+
export type ChartWrapper = {
|
|
23
|
+
options: Record<string, unknown>;
|
|
24
|
+
dataTable?: GoogleDataTable;
|
|
25
|
+
chartType: string;
|
|
26
|
+
};
|
|
27
|
+
export type MultiSeriesOptions = {
|
|
28
|
+
value: string;
|
|
29
|
+
series: string;
|
|
30
|
+
groupXAxisBy: string;
|
|
31
|
+
tooltip?: string;
|
|
32
|
+
};
|
|
33
|
+
export type FormattingRule = {
|
|
34
|
+
type: string;
|
|
35
|
+
format: string;
|
|
36
|
+
};
|
|
37
|
+
export type Formatting = Record<string, FormattingRule>;
|
|
38
|
+
export type FormattingTemplates = Record<string, FormattingTemplate>;
|
|
39
|
+
export type FormattingTemplate = {
|
|
40
|
+
prefix?: string;
|
|
41
|
+
fractionDigits?: number;
|
|
42
|
+
groupingSymbol?: string;
|
|
43
|
+
format?: string;
|
|
44
|
+
};
|
|
45
|
+
export type ProcessedFormatting = {
|
|
46
|
+
[key: string]: {
|
|
47
|
+
type: string;
|
|
48
|
+
format: FormattingTemplate | null;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export type TableColumn = {
|
|
52
|
+
property: string;
|
|
53
|
+
name: string;
|
|
54
|
+
class: string;
|
|
55
|
+
};
|
|
56
|
+
export type TableRow = {
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
};
|
|
59
|
+
export type Table = {
|
|
60
|
+
rows: TableRow[];
|
|
61
|
+
columns: TableColumn[];
|
|
62
|
+
style?: TableStyleTemplateObject;
|
|
63
|
+
filterEnabled?: boolean;
|
|
64
|
+
perPageCount?: number;
|
|
65
|
+
};
|
|
66
|
+
export type TableStyleTemplateObject = Record<string, TableStyleTemplate>;
|
|
67
|
+
export type TableStyleTemplate = {
|
|
68
|
+
class?: string;
|
|
69
|
+
html?: string;
|
|
70
|
+
[key: string]: string | undefined;
|
|
71
|
+
};
|
|
72
|
+
export type ChartSuperType = 'google' | 'table' | 'embed';
|
|
73
|
+
export type Chart = {
|
|
74
|
+
chartId: string;
|
|
75
|
+
query: string;
|
|
76
|
+
multiSeries?: MultiSeriesOptions;
|
|
77
|
+
formatting?: Formatting;
|
|
78
|
+
chartWrapper: ChartWrapper;
|
|
79
|
+
table?: Table;
|
|
80
|
+
cumulative?: boolean;
|
|
81
|
+
greedyHeight?: boolean;
|
|
82
|
+
greedyWidth?: boolean;
|
|
83
|
+
hideTitle?: boolean;
|
|
84
|
+
name: string;
|
|
85
|
+
showChart: boolean;
|
|
86
|
+
supertype: ChartSuperType;
|
|
87
|
+
title: string;
|
|
88
|
+
description?: string;
|
|
89
|
+
rank?: number;
|
|
90
|
+
reportChartId?: number;
|
|
91
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMvY2hhcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface OptionListEntry {
|
|
2
|
+
id: number | string;
|
|
3
|
+
name: string;
|
|
4
|
+
rawSql?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export type OptionList = Array<OptionListEntry>;
|
|
7
|
+
export interface DashboardReportBaseParameter {
|
|
8
|
+
name: string;
|
|
9
|
+
title: string;
|
|
10
|
+
default: string;
|
|
11
|
+
value: string;
|
|
12
|
+
queryValues: Record<string, string | string[]>;
|
|
13
|
+
}
|
|
14
|
+
export interface DashboardReportDateParameter extends DashboardReportBaseParameter {
|
|
15
|
+
type: 'date';
|
|
16
|
+
}
|
|
17
|
+
export interface DashboardReportDateRangeParameter extends DashboardReportBaseParameter {
|
|
18
|
+
type: 'dateRange';
|
|
19
|
+
dates: {
|
|
20
|
+
from: string;
|
|
21
|
+
to: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface DashboardReportSelectionParameter extends DashboardReportBaseParameter {
|
|
25
|
+
type: 'selection';
|
|
26
|
+
optionList: OptionList;
|
|
27
|
+
optionListQuery?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface DashboardReportSiteSelectionParameter extends DashboardReportBaseParameter {
|
|
30
|
+
type: 'siteSelection';
|
|
31
|
+
optionList: OptionList;
|
|
32
|
+
permission?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DashboardReportSessionParameter extends DashboardReportBaseParameter {
|
|
35
|
+
type: 'session';
|
|
36
|
+
}
|
|
37
|
+
export type DashboardReportParameter = DashboardReportDateParameter | DashboardReportSelectionParameter | DashboardReportSiteSelectionParameter | DashboardReportDateRangeParameter | DashboardReportSessionParameter;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyYW1ldGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3R5cGVzL3BhcmFtZXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Chart } from './chart';
|
|
2
|
+
import { DashboardReportParameter } from './parameter';
|
|
3
|
+
export interface Report {
|
|
4
|
+
dashboardReportId: number;
|
|
5
|
+
name: string;
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
charts: Chart[];
|
|
9
|
+
ownerId: number | null;
|
|
10
|
+
parameterValues: DashboardReportParameter[];
|
|
11
|
+
autoRefreshInterval: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface ReportInput {
|
|
14
|
+
dashboardReportId: number;
|
|
15
|
+
reportName: string;
|
|
16
|
+
reportTitle: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
shareId: number | null;
|
|
19
|
+
shareType: ShareType;
|
|
20
|
+
ownerId: number | null;
|
|
21
|
+
autoRefreshInterval: number | null;
|
|
22
|
+
parameters: DashboardReportParameter[];
|
|
23
|
+
}
|
|
24
|
+
export type ShareType = 'everyone' | 'owner' | 'user' | 'group';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3R5cGVzL3JlcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy9zZXNzaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ==
|
package/package.json
CHANGED
|
@@ -1,24 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isoftdata/utility-dashboard-backend",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A utility for formatting chart and report data to be usable by the frontend dashboard component.",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "npx tsc",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
8
10
|
},
|
|
9
11
|
"author": "Charles Kaup",
|
|
10
12
|
"license": "ISC",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist/**/*.*"
|
|
15
|
+
],
|
|
16
|
+
"eslintConfig": {
|
|
17
|
+
"extends": "@isoftdata/typescript",
|
|
18
|
+
"ignorePatterns": "dist/**",
|
|
19
|
+
"rules": {
|
|
20
|
+
"@typescript-eslint/no-var-requires": 0
|
|
21
|
+
}
|
|
22
|
+
},
|
|
11
23
|
"dependencies": {
|
|
12
24
|
"@isoftdata/utility-date-time": "^2.0.3",
|
|
13
25
|
"@isoftdata/utility-db": "^1.4.0",
|
|
14
|
-
"camelcase": "^
|
|
26
|
+
"camelcase": "^7.0.1",
|
|
15
27
|
"date-fns": "^2.23.0",
|
|
16
28
|
"deepmerge": "^4.2.2",
|
|
17
|
-
"klona": "^
|
|
29
|
+
"klona": "^2.0.5",
|
|
18
30
|
"mathjs": "^11.5.0",
|
|
19
31
|
"mysql": "^2.18.1",
|
|
20
32
|
"snakecase-keys": "^5.4.4",
|
|
21
33
|
"snakeize": "^0.1.0",
|
|
22
34
|
"to-snake-case": "^1.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@isoftdata/eslint-config-typescript": "^1.0.13",
|
|
38
|
+
"@types/google.visualization": "^0.0.68",
|
|
39
|
+
"@types/mysql": "github:types/mysql",
|
|
40
|
+
"@types/node": "^18.11.18",
|
|
41
|
+
"eslint": "^7.32.0",
|
|
42
|
+
"package-preview": "^4.0.0",
|
|
43
|
+
"typescript": "^4.9.4"
|
|
23
44
|
}
|
|
24
45
|
}
|
package/.gitattributes
DELETED