@isoftdata/utility-dashboard-backend 2.0.2 → 2.1.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.
- package/README.md +19 -6
- package/dist/chart-helper.d.ts +32 -0
- package/dist/chart-helper.js +238 -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 +296 -0
- package/dist/style-templates.d.ts +4 -0
- package/dist/style-templates.js +31 -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,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatterTemplates = exports.handleFormattingTemplates = exports.parameterizeQuery = exports.loadDataTableAndProcessedFormatting = exports.loadDataTable = exports.loadOutputParameterValues = exports.formatChartDataForReport = exports.formatReportMetadata = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const db = require('@isoftdata/utility-db');
|
|
6
|
+
const chart_helper_js_1 = require("./chart-helper.js");
|
|
7
|
+
Object.defineProperty(exports, "handleFormattingTemplates", { enumerable: true, get: function () { return chart_helper_js_1.handleFormattingTemplates; } });
|
|
8
|
+
const utility_date_time_1 = require("@isoftdata/utility-date-time");
|
|
9
|
+
const formatterTemplates = tslib_1.__importStar(require("./formatting-templates"));
|
|
10
|
+
exports.formatterTemplates = formatterTemplates;
|
|
11
|
+
const formatDate = require('date-fns/format');
|
|
12
|
+
const camelcase_1 = tslib_1.__importDefault(require("camelcase"));
|
|
13
|
+
const mysql = require('mysql');
|
|
14
|
+
const deepmerge = require('deepmerge');
|
|
15
|
+
const handleChartTypeSpecificQuirks = (chartType, resultSet) => {
|
|
16
|
+
if (resultSet.length) {
|
|
17
|
+
switch (chartType) {
|
|
18
|
+
case 'PieChart':
|
|
19
|
+
resultSet = (0, chart_helper_js_1.makeNegativeNumbericValuesZero)(resultSet);
|
|
20
|
+
break;
|
|
21
|
+
case 'TreeMap':
|
|
22
|
+
resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[1], resultSet);
|
|
23
|
+
if (resultSet.length === 1) {
|
|
24
|
+
resultSet[0].id = 'No Data';
|
|
25
|
+
}
|
|
26
|
+
break;
|
|
27
|
+
default:
|
|
28
|
+
resultSet = (0, chart_helper_js_1.coerceNullColumn)(Object.keys(resultSet[0])[0], resultSet);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return resultSet;
|
|
32
|
+
};
|
|
33
|
+
async function loadChartData(mysqlConnection, chart, queryObject) {
|
|
34
|
+
let { formatting, chartWrapper, multiSeries, table, supertype, cumulative, ...theRest } = chart;
|
|
35
|
+
if (!chartWrapper) {
|
|
36
|
+
chartWrapper = {
|
|
37
|
+
chartType: supertype,
|
|
38
|
+
options: {
|
|
39
|
+
height: 450, width: 800,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
cumulative = cumulative || (chartWrapper?.chartType === 'AreaChart' && cumulative !== false);
|
|
44
|
+
let dataTable = {}, processedFormatting = {};
|
|
45
|
+
try {
|
|
46
|
+
const dataTableAndProcessedFormatting = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType: chartWrapper?.chartType, cumulative, table });
|
|
47
|
+
dataTable = dataTableAndProcessedFormatting.dataTable;
|
|
48
|
+
processedFormatting = dataTableAndProcessedFormatting.processedFormatting;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error('Error loading dataTable / processedFormatting');
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
if (chartWrapper?.chartType === 'Table') {
|
|
55
|
+
return {
|
|
56
|
+
...theRest,
|
|
57
|
+
supertype,
|
|
58
|
+
chartWrapper,
|
|
59
|
+
table: { ...table, ...dataTable },
|
|
60
|
+
formatting: processedFormatting,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
...theRest,
|
|
65
|
+
cumulative,
|
|
66
|
+
supertype,
|
|
67
|
+
chartWrapper: {
|
|
68
|
+
...chartWrapper,
|
|
69
|
+
dataTable: dataTable,
|
|
70
|
+
},
|
|
71
|
+
formatting: processedFormatting,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType, cumulative = false, table = {} }) {
|
|
75
|
+
let { results: queryResultSet, fields } = (queryObject?.sql) ? await (0, chart_helper_js_1.queryWithFields)(mysqlConnection, queryObject) : { fields: {}, results: [] };
|
|
76
|
+
queryResultSet = queryResultSet;
|
|
77
|
+
let data = handleChartTypeSpecificQuirks(chartType, queryResultSet);
|
|
78
|
+
if (multiSeries) {
|
|
79
|
+
({ data, formatting, fields } = (0, chart_helper_js_1.getMultiSeriesData)({
|
|
80
|
+
data,
|
|
81
|
+
seriesOptions: multiSeries,
|
|
82
|
+
formatting,
|
|
83
|
+
fields,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
const processedFormatting = (0, chart_helper_js_1.handleFormattingTemplates)(formatting);
|
|
87
|
+
if (chartType?.toLowerCase() === 'table') {
|
|
88
|
+
return { dataTable: (0, chart_helper_js_1.getRactiveTableDataFormat)(data, fields, processedFormatting, table?.style), processedFormatting };
|
|
89
|
+
}
|
|
90
|
+
let dataTable = (0, chart_helper_js_1.getDataTableFormat)(data, fields, multiSeries);
|
|
91
|
+
if (cumulative || chartType === 'AreaChart') {
|
|
92
|
+
dataTable = (0, chart_helper_js_1.makeDataCumulative)(dataTable, cumulative);
|
|
93
|
+
}
|
|
94
|
+
return { dataTable, processedFormatting };
|
|
95
|
+
}
|
|
96
|
+
exports.loadDataTableAndProcessedFormatting = loadDataTableAndProcessedFormatting;
|
|
97
|
+
async function loadDataTable(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType }) {
|
|
98
|
+
const { dataTable } = await loadDataTableAndProcessedFormatting(mysqlConnection, { query: queryObject, multiSeries, formatting, chartType });
|
|
99
|
+
return dataTable;
|
|
100
|
+
}
|
|
101
|
+
exports.loadDataTable = loadDataTable;
|
|
102
|
+
const loadOptionList = async (mysqlConnection, optionListQuery, optionList = []) => {
|
|
103
|
+
return [
|
|
104
|
+
...optionList,
|
|
105
|
+
...(optionListQuery && await db.query(mysqlConnection, optionListQuery)) || [],
|
|
106
|
+
];
|
|
107
|
+
};
|
|
108
|
+
async function loadOutputParameterValues(mysqlConnection, { definitionList = [], selectionList = [], forClient = false, session, site = 'store', siteIdColumn, siteNameColumn }) {
|
|
109
|
+
if (!(definitionList instanceof Array) || !definitionList.length) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
const parameterValues = [];
|
|
113
|
+
for (const definition of definitionList) {
|
|
114
|
+
const matchingParameterSelection = selectionList.find(param => param.name === definition.name);
|
|
115
|
+
let typedParameter;
|
|
116
|
+
const baseParameter = {
|
|
117
|
+
name: definition.name,
|
|
118
|
+
title: definition.title || definition.name,
|
|
119
|
+
default: definition.default,
|
|
120
|
+
value: (matchingParameterSelection?.value) ?? definition.default,
|
|
121
|
+
queryValues: {},
|
|
122
|
+
};
|
|
123
|
+
if (definition.type === 'dateRange') {
|
|
124
|
+
baseParameter.value = baseParameter.value || 'Last 30 Days';
|
|
125
|
+
typedParameter = {
|
|
126
|
+
...baseParameter,
|
|
127
|
+
type: 'dateRange',
|
|
128
|
+
dates: matchingParameterSelection?.dates ?? (0, utility_date_time_1.datesFromRange)(baseParameter.value),
|
|
129
|
+
};
|
|
130
|
+
if (typedParameter.value !== 'Custom') {
|
|
131
|
+
typedParameter.dates = (0, utility_date_time_1.datesFromRange)(typedParameter.value);
|
|
132
|
+
}
|
|
133
|
+
if (!forClient) {
|
|
134
|
+
typedParameter.queryValues = {
|
|
135
|
+
[`${typedParameter.name}_start_date`]: typedParameter.dates.from,
|
|
136
|
+
[`${typedParameter.name}_end_date`]: typedParameter.dates.to,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else if (definition.type === 'selection') {
|
|
141
|
+
typedParameter = {
|
|
142
|
+
...baseParameter,
|
|
143
|
+
type: 'selection',
|
|
144
|
+
optionListQuery: definition?.optionListQuery,
|
|
145
|
+
optionList: definition?.optionList,
|
|
146
|
+
};
|
|
147
|
+
typedParameter.optionList = await loadOptionList(mysqlConnection, typedParameter.optionListQuery, typedParameter.optionList);
|
|
148
|
+
if (!typedParameter.optionList.some(option => option.id?.toString() === typedParameter.value?.toString())) {
|
|
149
|
+
typedParameter.value = typedParameter.optionList?.[0]?.id?.toString();
|
|
150
|
+
}
|
|
151
|
+
const option = typedParameter.optionList.find(option => option.id.toString() === typedParameter.value);
|
|
152
|
+
if (!forClient) {
|
|
153
|
+
typedParameter.queryValues = {
|
|
154
|
+
[typedParameter.name]: option?.rawSql ? mysql.raw(typedParameter.value) : typedParameter.value,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (definition.type === 'siteSelection') {
|
|
159
|
+
typedParameter = {
|
|
160
|
+
...baseParameter,
|
|
161
|
+
type: 'siteSelection',
|
|
162
|
+
permission: definition?.permission,
|
|
163
|
+
optionList: definition?.optionList,
|
|
164
|
+
};
|
|
165
|
+
typedParameter.value = typedParameter.value ?? (session.siteId ?? session[`${site}Id`]);
|
|
166
|
+
siteIdColumn = siteIdColumn ? mysqlConnection.escapeId(siteIdColumn) : mysqlConnection.escapeId(`${site}id`);
|
|
167
|
+
siteNameColumn = siteNameColumn ? mysqlConnection.escapeId(siteNameColumn) : 'name';
|
|
168
|
+
const siteTableName = mysqlConnection.escapeId(site);
|
|
169
|
+
if (typedParameter.permission) {
|
|
170
|
+
typedParameter.optionList = await db.query(mysqlConnection, {
|
|
171
|
+
sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_check_user_permission(?, ?, ${siteIdColumn})`,
|
|
172
|
+
values: [session.userAccountId, definition.permission],
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
typedParameter.optionList = await db.query(mysqlConnection, {
|
|
177
|
+
sql: `SELECT ${siteIdColumn} AS id, ${siteNameColumn} AS \`name\` FROM ${siteTableName} WHERE f_useraccount_has_site_access(?, ${siteIdColumn})`,
|
|
178
|
+
values: [session.userAccountId],
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (typedParameter.optionList.length > 1) {
|
|
182
|
+
typedParameter.optionList.unshift({ id: 0, name: 'All' });
|
|
183
|
+
}
|
|
184
|
+
if (!typedParameter.optionList.some(option => option.id?.toString() === baseParameter.value?.toString())) {
|
|
185
|
+
typedParameter.value = typedParameter.optionList?.[0]?.id.toString();
|
|
186
|
+
}
|
|
187
|
+
if (!forClient && typedParameter.value?.toString() === '0') {
|
|
188
|
+
typedParameter.queryValues = {
|
|
189
|
+
[typedParameter.name]: typedParameter.optionList
|
|
190
|
+
.filter(({ id }) => id > 0)
|
|
191
|
+
.map(({ id }) => id?.toString()),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
else if (!forClient) {
|
|
195
|
+
typedParameter.queryValues = {
|
|
196
|
+
[typedParameter.name]: [typedParameter.value],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (definition.type === 'date') {
|
|
201
|
+
typedParameter = {
|
|
202
|
+
...baseParameter,
|
|
203
|
+
type: 'date',
|
|
204
|
+
};
|
|
205
|
+
typedParameter.value = typedParameter.value || formatDate(new Date(), 'yyyy-MM-dd');
|
|
206
|
+
if (!forClient) {
|
|
207
|
+
typedParameter.queryValues = {
|
|
208
|
+
[typedParameter.name]: typedParameter.value,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (definition.type === 'session') {
|
|
213
|
+
typedParameter = {
|
|
214
|
+
...baseParameter,
|
|
215
|
+
type: 'session',
|
|
216
|
+
};
|
|
217
|
+
const parameterName = (0, camelcase_1.default)(definition.name);
|
|
218
|
+
baseParameter.value = (session[parameterName] ?? '').toString();
|
|
219
|
+
if (!forClient) {
|
|
220
|
+
typedParameter.queryValues = {
|
|
221
|
+
[typedParameter.name]: typedParameter.value,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
throw new Error(`Parameter type mismatch for ${baseParameter.name}`);
|
|
227
|
+
}
|
|
228
|
+
parameterValues.push(typedParameter);
|
|
229
|
+
}
|
|
230
|
+
return parameterValues;
|
|
231
|
+
}
|
|
232
|
+
exports.loadOutputParameterValues = loadOutputParameterValues;
|
|
233
|
+
const parameterizeQuery = (queryString, parameterValues) => {
|
|
234
|
+
if (!queryString) {
|
|
235
|
+
return {
|
|
236
|
+
sql: '',
|
|
237
|
+
values: [],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const queryParameterValues = parameterValues.reduce((acc, val) => {
|
|
241
|
+
return val.queryValues ? {
|
|
242
|
+
...acc,
|
|
243
|
+
...val.queryValues,
|
|
244
|
+
} : acc;
|
|
245
|
+
}, {});
|
|
246
|
+
const regexp = /\${([^}]+)}/g;
|
|
247
|
+
const queryParameterKeys = [...queryString.matchAll(regexp)].map(([, insideToken]) => insideToken.trim());
|
|
248
|
+
const queryParameters = queryParameterKeys.map(key => queryParameterValues[key] || null);
|
|
249
|
+
return {
|
|
250
|
+
sql: queryString.replace(regexp, '?'),
|
|
251
|
+
values: queryParameters,
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
exports.parameterizeQuery = parameterizeQuery;
|
|
255
|
+
async function formatReportMetadata(mysqlConnection, { report, chartsInReport, session = {}, site, siteIdColumn, siteNameColumn }) {
|
|
256
|
+
try {
|
|
257
|
+
const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: report.parameters, forClient: true, session, site, siteIdColumn, siteNameColumn });
|
|
258
|
+
return {
|
|
259
|
+
dashboardReportId: report.dashboardReportId,
|
|
260
|
+
name: report.reportName,
|
|
261
|
+
title: report.reportTitle,
|
|
262
|
+
charts: chartsInReport,
|
|
263
|
+
parameterValues,
|
|
264
|
+
ownerId: report.ownerId,
|
|
265
|
+
autoRefreshInterval: report.autoRefreshInterval,
|
|
266
|
+
description: report.description ?? '',
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
console.error(err);
|
|
271
|
+
throw err;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
exports.formatReportMetadata = formatReportMetadata;
|
|
275
|
+
async function formatChartDataForReport(mysqlConnection, { reportParameters, chart, reportChart, parameterSelectionList, session = {}, site, siteIdColumn, siteNameColumn }) {
|
|
276
|
+
try {
|
|
277
|
+
const parameterValues = await loadOutputParameterValues(mysqlConnection, { definitionList: reportParameters, selectionList: parameterSelectionList, session, site, siteIdColumn, siteNameColumn });
|
|
278
|
+
if (reportChart?.jsonOverride?.chartWrapper?.dataTable) {
|
|
279
|
+
const { dataTable, ...chartWrapper } = reportChart.jsonOverride.chartWrapper;
|
|
280
|
+
reportChart.jsonOverride.chartWrapper = chartWrapper;
|
|
281
|
+
}
|
|
282
|
+
const combinedChart = deepmerge(chart, reportChart.jsonOverride ?? {});
|
|
283
|
+
return await loadChartData(mysqlConnection, {
|
|
284
|
+
...combinedChart,
|
|
285
|
+
rank: reportChart.rank,
|
|
286
|
+
reportChartId: reportChart.reportChartId,
|
|
287
|
+
description: combinedChart.description ?? '',
|
|
288
|
+
}, parameterizeQuery(chart.query, parameterValues));
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
console.error(err);
|
|
292
|
+
throw err;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
exports.formatChartDataForReport = formatChartDataForReport;
|
|
296
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFBO0FBQzNDLHVEQVM2QztBQXdhNUMsMEdBN2FBLDJDQUF5QixPQTZhQTtBQXZhMUIsb0VBQTZEO0FBQzdELG1GQUE0RDtBQXVhM0QsZ0RBQWtCO0FBdGFuQixNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtBQUM3QyxrRUFBaUM7QUFDakMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0FBQzlCLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQTtBQU10QyxNQUFNLDZCQUE2QixHQUFHLENBQUMsU0FBaUIsRUFBRSxTQUEwQixFQUFFLEVBQUU7SUFDdkYsSUFBSSxTQUFTLENBQUMsTUFBTSxFQUFFO1FBQ3JCLFFBQVEsU0FBUyxFQUFFO1lBQ2xCLEtBQUssVUFBVTtnQkFFZCxTQUFTLEdBQUcsSUFBQSxnREFBOEIsRUFBQyxTQUFTLENBQUMsQ0FBQTtnQkFDckQsTUFBSztZQUNOLEtBQUssU0FBUztnQkFFYixTQUFTLEdBQUcsSUFBQSxrQ0FBZ0IsRUFBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFBO2dCQUNyRSxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO29CQUMzQixTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLFNBQVMsQ0FBQTtpQkFDM0I7Z0JBQ0QsTUFBSztZQUNOO2dCQUVDLFNBQVMsR0FBRyxJQUFBLGtDQUFnQixFQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FB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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const mathjs_1 = require("mathjs");
|
|
5
|
+
const snakecase_keys_1 = tslib_1.__importDefault(require("snakecase-keys"));
|
|
6
|
+
const klona_1 = require("klona");
|
|
7
|
+
function handleMathJsCellStyleTemplate(row, columnToStyle, templates) {
|
|
8
|
+
const outCell = { value: row[columnToStyle]?.toString() };
|
|
9
|
+
if (columnToStyle in templates) {
|
|
10
|
+
const scope = (0, snakecase_keys_1.default)((0, klona_1.klona)(row), { deep: true });
|
|
11
|
+
for (const key in templates[columnToStyle]) {
|
|
12
|
+
try {
|
|
13
|
+
const expression = templates[columnToStyle][key] ?? '';
|
|
14
|
+
outCell[key] = (0, mathjs_1.evaluate)(expression, scope);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error(`Error evaluating expression: '${templates[columnToStyle][key]}'\n`, err);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return outCell;
|
|
22
|
+
}
|
|
23
|
+
function styleRow(row, templates) {
|
|
24
|
+
const outRow = {};
|
|
25
|
+
for (const columnName in row) {
|
|
26
|
+
outRow[columnName] = handleMathJsCellStyleTemplate(row, columnName, templates);
|
|
27
|
+
}
|
|
28
|
+
return outRow;
|
|
29
|
+
}
|
|
30
|
+
exports.default = styleRow;
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3R5bGUtdGVtcGxhdGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3N0eWxlLXRlbXBsYXRlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFJQSxtQ0FBaUM7QUFFakMsNEVBQTBDO0FBQzFDLGlDQUE2QjtBQUU3QixTQUFTLDZCQUE2QixDQUFDLEdBQWtCLEVBQUUsYUFBcUIsRUFBRSxTQUFtQztJQUNwSCxNQUFNLE9BQU8sR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsYUFBYSxDQUFDLEVBQUUsUUFBUSxFQUFFLEVBQXFDLENBQUE7SUFDNUYsSUFBSSxhQUFhLElBQUksU0FBUyxFQUFFO1FBRS9CLE1BQU0sS0FBSyxHQUFHLElBQUEsd0JBQWEsRUFBQyxJQUFBLGFBQUssRUFBQyxHQUFHLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQ3ZELEtBQUssTUFBTSxHQUFHLElBQUksU0FBUyxDQUFDLGFBQWEsQ0FBQyxFQUFFO1lBQzNDLElBQUk7Z0JBQ0gsTUFBTSxVQUFVLEdBQUcsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtnQkFDdEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUEsaUJBQVEsRUFBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLENBQUE7YUFDMUM7WUFBQyxPQUFPLEdBQUcsRUFBRTtnQkFHYixPQUFPLENBQUMsS0FBSyxDQUFDLGlDQUFpQyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQTthQUN2RjtTQUNEO0tBQ0Q7SUFDRCxPQUFPLE9BQU8sQ0FBQTtBQUNmLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBQyxHQUFrQixFQUFFLFNBQW1DO0lBQ3hFLE1BQU0sTUFBTSxHQUFHLEVBQW1CLENBQUE7SUFDbEMsS0FBSyxNQUFNLFVBQVUsSUFBSSxHQUFHLEVBQUU7UUFDN0IsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLDZCQUE2QixDQUFDLEdBQUcsRUFBRSxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUE7S0FDOUU7SUFDRCxPQUFPLE1BQU0sQ0FBQTtBQUNkLENBQUM7QUFFRCxrQkFBZSxRQUFRLENBQUEifQ==
|
|
@@ -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.
|
|
3
|
+
"version": "2.1.1",
|
|
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": "^6.3.0",
|
|
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