@adminforth/dashboard 1.2.0 → 1.3.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 +47 -39
- package/custom/composables/useElementSize.ts +17 -2
- package/custom/model/dashboard.types.ts +327 -234
- package/custom/skills/adminforth-dashboard/SKILL.md +6 -2
- package/custom/widgets/chart/ChartWidget.vue +23 -55
- package/custom/widgets/chart/bar/BarChart.vue +20 -12
- package/custom/widgets/chart/chart.types.ts +17 -66
- package/custom/widgets/chart/chart.utils.ts +11 -0
- package/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
- package/custom/widgets/chart/line/LineChart.vue +23 -15
- package/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
- package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -12
- package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
- package/custom/widgets/pivot-table/PivotTableWidget.vue +8 -7
- package/custom/widgets/table/TableWidget.vue +8 -3
- package/dist/custom/composables/useElementSize.js +14 -2
- package/dist/custom/composables/useElementSize.ts +17 -2
- package/dist/custom/model/dashboard.types.d.ts +178 -61
- package/dist/custom/model/dashboard.types.js +67 -92
- package/dist/custom/model/dashboard.types.ts +327 -234
- package/dist/custom/queries/useDashboardConfig.d.ts +832 -66
- package/dist/custom/queries/useWidgetData.d.ts +828 -62
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +6 -2
- package/dist/custom/widgets/chart/ChartWidget.vue +23 -55
- package/dist/custom/widgets/chart/bar/BarChart.vue +20 -12
- package/dist/custom/widgets/chart/chart.types.d.ts +13 -22
- package/dist/custom/widgets/chart/chart.types.js +2 -25
- package/dist/custom/widgets/chart/chart.types.ts +17 -66
- package/dist/custom/widgets/chart/chart.utils.d.ts +1 -0
- package/dist/custom/widgets/chart/chart.utils.js +7 -0
- package/dist/custom/widgets/chart/chart.utils.ts +11 -0
- package/dist/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
- package/dist/custom/widgets/chart/line/LineChart.vue +23 -15
- package/dist/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
- package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -12
- package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
- package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +8 -7
- package/dist/custom/widgets/table/TableWidget.vue +8 -3
- package/dist/endpoint/widgets.js +5 -2
- package/dist/schema/api.d.ts +2680 -736
- package/dist/schema/widget.d.ts +1588 -476
- package/dist/schema/widget.js +205 -139
- package/dist/services/widgetConfigValidator.js +16 -40
- package/dist/services/widgetDataService.js +359 -82
- package/endpoint/dashboard.ts +1 -1
- package/endpoint/widgets.ts +5 -2
- package/package.json +1 -1
- package/schema/widget.ts +222 -139
- package/services/widgetConfigValidator.ts +29 -53
- package/services/widgetDataService.ts +484 -100
|
@@ -7,124 +7,401 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { Filters, Sorts } from 'adminforth';
|
|
11
|
+
const NOW_MINUS_RE = /^(\d+)([dhw])$/;
|
|
12
|
+
const CALC_IDENTIFIER_RE = /\b[a-zA-Z_][a-zA-Z0-9_]*\b/g;
|
|
13
|
+
const SAFE_CALC_EXPRESSION_RE = /^[\d+\-*/().\s]+$/;
|
|
11
14
|
export function getWidgetData(adminforth_1, widget_1) {
|
|
12
15
|
return __awaiter(this, arguments, void 0, function* (adminforth, widget, options = {}) {
|
|
13
|
-
|
|
14
|
-
if (!dataSource) {
|
|
16
|
+
if (!('query' in widget)) {
|
|
15
17
|
return null;
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const data = 'steps' in widget.query
|
|
20
|
+
? yield getFunnelWidgetData(adminforth, widget.query)
|
|
21
|
+
: yield getQueryWidgetData(adminforth, widget.query);
|
|
22
|
+
if (widget.target !== 'table' || !options.pagination) {
|
|
23
|
+
return data;
|
|
19
24
|
}
|
|
20
|
-
|
|
25
|
+
const page = options.pagination.page;
|
|
26
|
+
const pageSize = options.pagination.pageSize;
|
|
27
|
+
const offset = (page - 1) * pageSize;
|
|
28
|
+
return Object.assign(Object.assign({}, data), { rows: data.rows.slice(offset, offset + pageSize), pagination: {
|
|
29
|
+
page,
|
|
30
|
+
pageSize,
|
|
31
|
+
total: data.rows.length,
|
|
32
|
+
totalPages: Math.max(Math.ceil(data.rows.length / pageSize), 1),
|
|
33
|
+
} });
|
|
21
34
|
});
|
|
22
35
|
}
|
|
23
|
-
function
|
|
36
|
+
function getFunnelWidgetData(adminforth, query) {
|
|
24
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
pageSize: pagination.pageSize,
|
|
39
|
-
total,
|
|
40
|
-
totalPages: Math.max(Math.ceil(total / pagination.pageSize), 1),
|
|
41
|
-
},
|
|
42
|
-
} : {}));
|
|
38
|
+
const rows = yield Promise.all(query.steps.map((step) => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const valueField = step.metric.as;
|
|
40
|
+
const sourceRows = yield getResourceRows(adminforth, step.resource, step.filters);
|
|
41
|
+
return {
|
|
42
|
+
name: step.name,
|
|
43
|
+
[valueField]: calculateAggregate(sourceRows, step.metric),
|
|
44
|
+
};
|
|
45
|
+
})));
|
|
46
|
+
return {
|
|
47
|
+
kind: 'aggregate',
|
|
48
|
+
columns: ['name', ...Array.from(new Set(query.steps.map((step) => step.metric.as)))],
|
|
49
|
+
rows,
|
|
50
|
+
};
|
|
43
51
|
});
|
|
44
52
|
}
|
|
45
|
-
function
|
|
53
|
+
function getQueryWidgetData(adminforth, query) {
|
|
46
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
-
var _a, _b;
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
columns: Object.keys(values),
|
|
59
|
-
rows: Object.keys(values).length ? [values] : [],
|
|
60
|
-
values,
|
|
61
|
-
};
|
|
55
|
+
var _a, _b, _c;
|
|
56
|
+
const rows = yield getResourceRows(adminforth, query.resource, query.filters, getBackendSort(query.orderBy));
|
|
57
|
+
const selectedRows = buildQueryRows(rows, query);
|
|
58
|
+
const orderedRows = sortRows(selectedRows, query.orderBy);
|
|
59
|
+
const slicedRows = typeof query.limit === 'number'
|
|
60
|
+
? orderedRows.slice((_a = query.offset) !== null && _a !== void 0 ? _a : 0, ((_b = query.offset) !== null && _b !== void 0 ? _b : 0) + query.limit)
|
|
61
|
+
: orderedRows.slice((_c = query.offset) !== null && _c !== void 0 ? _c : 0);
|
|
62
|
+
const columns = getColumns(slicedRows, query);
|
|
63
|
+
if (isAggregateQuery(query)) {
|
|
64
|
+
const values = slicedRows.length === 1 ? slicedRows[0] : undefined;
|
|
65
|
+
return Object.assign({ kind: 'aggregate', columns, rows: slicedRows }, (values ? { values } : {}));
|
|
62
66
|
}
|
|
63
67
|
return {
|
|
64
|
-
kind: '
|
|
68
|
+
kind: 'table',
|
|
65
69
|
columns,
|
|
66
|
-
rows,
|
|
70
|
+
rows: slicedRows,
|
|
67
71
|
};
|
|
68
72
|
});
|
|
69
73
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
return undefined;
|
|
74
|
+
function getResourceRows(adminforth, resourceId, filters, sort) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
return adminforth.resource(resourceId).list(normalizeFilters(filters), undefined, 0, sort);
|
|
77
|
+
});
|
|
75
78
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
function buildQueryRows(rows, query) {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
const select = (_a = query.select) !== null && _a !== void 0 ? _a : getDefaultSelect(rows);
|
|
82
|
+
const groupBy = (_b = query.groupBy) !== null && _b !== void 0 ? _b : [];
|
|
83
|
+
if (isAggregateQuery(query)) {
|
|
84
|
+
return buildGroupedRows(rows, select, groupBy, query.calcs);
|
|
85
|
+
}
|
|
86
|
+
return rows.map((row) => buildPlainRow(row, select, query.calcs));
|
|
80
87
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
function buildGroupedRows(rows, select, groupBy, calcs = []) {
|
|
89
|
+
var _a;
|
|
90
|
+
const groups = new Map();
|
|
91
|
+
const effectiveGroupBy = groupBy.length
|
|
92
|
+
? groupBy
|
|
93
|
+
: select.filter(isFieldSelectItem).map((item) => ({ field: item.field, as: item.as, grain: item.grain }));
|
|
94
|
+
if (!effectiveGroupBy.length) {
|
|
95
|
+
const values = calculateGroupValues(rows, select, calcs);
|
|
96
|
+
return Object.keys(values).length ? [values] : [];
|
|
84
97
|
}
|
|
85
|
-
|
|
86
|
-
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
const values = Object.fromEntries(effectiveGroupBy.map((item) => {
|
|
100
|
+
const field = getGroupByField(item);
|
|
101
|
+
const alias = getGroupByAlias(item);
|
|
102
|
+
const grain = getGroupByGrain(item);
|
|
103
|
+
return [alias, formatGroupValue(row[field], grain)];
|
|
104
|
+
}));
|
|
105
|
+
const key = JSON.stringify(values);
|
|
106
|
+
const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : { values, rows: [] };
|
|
107
|
+
group.rows.push(row);
|
|
108
|
+
groups.set(key, group);
|
|
87
109
|
}
|
|
88
|
-
return
|
|
110
|
+
return Array.from(groups.values()).map((group) => (Object.assign(Object.assign({}, group.values), calculateGroupValues(group.rows, select, calcs))));
|
|
89
111
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
function calculateGroupValues(rows, select, calcs) {
|
|
113
|
+
const values = {};
|
|
114
|
+
for (const item of select) {
|
|
115
|
+
if (isAggregateSelectItem(item)) {
|
|
116
|
+
const filteredRows = item.filters
|
|
117
|
+
? rows.filter((row) => matchesFilterExpression(row, item.filters))
|
|
118
|
+
: rows;
|
|
119
|
+
values[item.as] = calculateAggregate(filteredRows, item);
|
|
120
|
+
}
|
|
93
121
|
}
|
|
94
|
-
|
|
95
|
-
|
|
122
|
+
for (const item of [...select.filter(isCalcSelectItem), ...calcs]) {
|
|
123
|
+
values[item.as] = evaluateCalc(item.calc, values);
|
|
96
124
|
}
|
|
97
|
-
|
|
98
|
-
|
|
125
|
+
return values;
|
|
126
|
+
}
|
|
127
|
+
function buildPlainRow(row, select, calcs = []) {
|
|
128
|
+
var _a;
|
|
129
|
+
const values = {};
|
|
130
|
+
for (const item of select) {
|
|
131
|
+
if (isFieldSelectItem(item)) {
|
|
132
|
+
values[(_a = item.as) !== null && _a !== void 0 ? _a : item.field] = item.grain
|
|
133
|
+
? formatGroupValue(row[item.field], item.grain)
|
|
134
|
+
: row[item.field];
|
|
135
|
+
}
|
|
99
136
|
}
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
for (const item of [...select.filter(isCalcSelectItem), ...calcs]) {
|
|
138
|
+
values[item.as] = evaluateCalc(item.calc, values);
|
|
102
139
|
}
|
|
103
|
-
return
|
|
140
|
+
return values;
|
|
104
141
|
}
|
|
105
|
-
function
|
|
106
|
-
switch (
|
|
107
|
-
case 'sum':
|
|
108
|
-
return Aggregates.sum(rule.field);
|
|
142
|
+
function calculateAggregate(rows, item) {
|
|
143
|
+
switch (item.agg) {
|
|
109
144
|
case 'count':
|
|
110
|
-
return
|
|
145
|
+
return rows.length;
|
|
146
|
+
case 'count_distinct':
|
|
147
|
+
return new Set(rows.map((row) => row[item.field])).size;
|
|
148
|
+
case 'sum':
|
|
149
|
+
return aggregateNumbers(rows, item.field, (values) => values.reduce((sum, value) => sum + value, 0));
|
|
111
150
|
case 'avg':
|
|
112
|
-
return
|
|
151
|
+
return aggregateNumbers(rows, item.field, (values) => values.length
|
|
152
|
+
? values.reduce((sum, value) => sum + value, 0) / values.length
|
|
153
|
+
: 0);
|
|
113
154
|
case 'min':
|
|
114
|
-
return
|
|
155
|
+
return aggregateNumbers(rows, item.field, (values) => values.length ? Math.min(...values) : 0);
|
|
115
156
|
case 'max':
|
|
116
|
-
return
|
|
157
|
+
return aggregateNumbers(rows, item.field, (values) => values.length ? Math.max(...values) : 0);
|
|
117
158
|
case 'median':
|
|
118
|
-
return
|
|
159
|
+
return aggregateNumbers(rows, item.field, calculateMedian);
|
|
119
160
|
default:
|
|
120
|
-
throw new Error(`Unsupported aggregation operation: ${
|
|
161
|
+
throw new Error(`Unsupported aggregation operation: ${item.agg}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function aggregateNumbers(rows, field, aggregate) {
|
|
165
|
+
return aggregate(rows.map((row) => toFiniteNumber(row[field])).filter(Number.isFinite));
|
|
166
|
+
}
|
|
167
|
+
function calculateMedian(values) {
|
|
168
|
+
if (!values.length) {
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
172
|
+
const middle = Math.floor(sorted.length / 2);
|
|
173
|
+
return sorted.length % 2
|
|
174
|
+
? sorted[middle]
|
|
175
|
+
: (sorted[middle - 1] + sorted[middle]) / 2;
|
|
176
|
+
}
|
|
177
|
+
function evaluateCalc(calc, values) {
|
|
178
|
+
const expression = calc.replace(CALC_IDENTIFIER_RE, (name) => String(toFiniteNumber(values[name])));
|
|
179
|
+
if (!SAFE_CALC_EXPRESSION_RE.test(expression)) {
|
|
180
|
+
throw new Error(`Unsupported calc expression: ${calc}`);
|
|
181
|
+
}
|
|
182
|
+
return Function(`"use strict"; return (${expression});`)();
|
|
183
|
+
}
|
|
184
|
+
function sortRows(rows, orderBy = []) {
|
|
185
|
+
if (!orderBy.length) {
|
|
186
|
+
return rows;
|
|
187
|
+
}
|
|
188
|
+
return [...rows].sort((left, right) => {
|
|
189
|
+
for (const order of orderBy) {
|
|
190
|
+
const direction = order.direction === 'asc' ? 1 : -1;
|
|
191
|
+
const result = compareValues(left[order.field], right[order.field]);
|
|
192
|
+
if (result !== 0) {
|
|
193
|
+
return result * direction;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return 0;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function compareValues(left, right) {
|
|
200
|
+
if (typeof left === 'number' && typeof right === 'number') {
|
|
201
|
+
return left - right;
|
|
202
|
+
}
|
|
203
|
+
return String(left !== null && left !== void 0 ? left : '').localeCompare(String(right !== null && right !== void 0 ? right : ''));
|
|
204
|
+
}
|
|
205
|
+
function getBackendSort(orderBy) {
|
|
206
|
+
if (!(orderBy === null || orderBy === void 0 ? void 0 : orderBy.length)) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
return orderBy.map((order) => order.direction === 'asc'
|
|
210
|
+
? Sorts.ASC(order.field)
|
|
211
|
+
: Sorts.DESC(order.field));
|
|
212
|
+
}
|
|
213
|
+
function getColumns(rows, query) {
|
|
214
|
+
var _a, _b, _c, _d;
|
|
215
|
+
const selectColumns = [
|
|
216
|
+
...((_a = query.groupBy) !== null && _a !== void 0 ? _a : []).map(getGroupByAlias),
|
|
217
|
+
...((_b = query.select) !== null && _b !== void 0 ? _b : []).map(getSelectAlias),
|
|
218
|
+
...((_c = query.calcs) !== null && _c !== void 0 ? _c : []).map((item) => item.as),
|
|
219
|
+
].filter(Boolean);
|
|
220
|
+
return Array.from(new Set(selectColumns.length ? selectColumns : Object.keys((_d = rows[0]) !== null && _d !== void 0 ? _d : {})));
|
|
221
|
+
}
|
|
222
|
+
function getDefaultSelect(rows) {
|
|
223
|
+
var _a;
|
|
224
|
+
return Object.keys((_a = rows[0]) !== null && _a !== void 0 ? _a : {}).map((field) => ({ field }));
|
|
225
|
+
}
|
|
226
|
+
function isAggregateQuery(query) {
|
|
227
|
+
var _a, _b;
|
|
228
|
+
return Boolean(((_a = query.groupBy) === null || _a === void 0 ? void 0 : _a.length)
|
|
229
|
+
|| ((_b = query.select) === null || _b === void 0 ? void 0 : _b.some((item) => isAggregateSelectItem(item))));
|
|
230
|
+
}
|
|
231
|
+
function isFieldSelectItem(item) {
|
|
232
|
+
return 'field' in item && !('agg' in item);
|
|
233
|
+
}
|
|
234
|
+
function isAggregateSelectItem(item) {
|
|
235
|
+
return 'agg' in item;
|
|
236
|
+
}
|
|
237
|
+
function isCalcSelectItem(item) {
|
|
238
|
+
return 'calc' in item;
|
|
239
|
+
}
|
|
240
|
+
function getSelectAlias(item) {
|
|
241
|
+
var _a;
|
|
242
|
+
if (isFieldSelectItem(item)) {
|
|
243
|
+
return (_a = item.as) !== null && _a !== void 0 ? _a : item.field;
|
|
244
|
+
}
|
|
245
|
+
return item.as;
|
|
246
|
+
}
|
|
247
|
+
function getGroupByField(item) {
|
|
248
|
+
return typeof item === 'string' ? item : item.field;
|
|
249
|
+
}
|
|
250
|
+
function getGroupByAlias(item) {
|
|
251
|
+
var _a;
|
|
252
|
+
return typeof item === 'string' ? item : (_a = item.as) !== null && _a !== void 0 ? _a : item.field;
|
|
253
|
+
}
|
|
254
|
+
function getGroupByGrain(item) {
|
|
255
|
+
return typeof item === 'string' ? undefined : item.grain;
|
|
256
|
+
}
|
|
257
|
+
function formatGroupValue(value, grain) {
|
|
258
|
+
if (!grain) {
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
const date = new Date(String(value));
|
|
262
|
+
if (!Number.isFinite(date.getTime())) {
|
|
263
|
+
return value;
|
|
264
|
+
}
|
|
265
|
+
if (grain === 'year') {
|
|
266
|
+
return `${date.getUTCFullYear()}`;
|
|
267
|
+
}
|
|
268
|
+
if (grain === 'quarter') {
|
|
269
|
+
return `${date.getUTCFullYear()}-Q${Math.floor(date.getUTCMonth() / 3) + 1}`;
|
|
270
|
+
}
|
|
271
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
272
|
+
if (grain === 'month') {
|
|
273
|
+
return `${date.getUTCFullYear()}-${month}`;
|
|
274
|
+
}
|
|
275
|
+
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
276
|
+
if (grain === 'week') {
|
|
277
|
+
const weekStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
278
|
+
weekStart.setUTCDate(weekStart.getUTCDate() - weekStart.getUTCDay());
|
|
279
|
+
return weekStart.toISOString().slice(0, 10);
|
|
280
|
+
}
|
|
281
|
+
if (grain === 'day') {
|
|
282
|
+
return `${date.getUTCFullYear()}-${month}-${day}`;
|
|
283
|
+
}
|
|
284
|
+
const hour = String(date.getUTCHours()).padStart(2, '0');
|
|
285
|
+
return `${date.getUTCFullYear()}-${month}-${day}T${hour}:00:00.000Z`;
|
|
286
|
+
}
|
|
287
|
+
function normalizeFilters(filters) {
|
|
288
|
+
if (Array.isArray(filters)) {
|
|
289
|
+
return filters.map((filter) => normalizeFilterNode(filter));
|
|
290
|
+
}
|
|
291
|
+
if (isRecord(filters)) {
|
|
292
|
+
return normalizeFilterNode(filters);
|
|
293
|
+
}
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
function normalizeFilterNode(filter) {
|
|
297
|
+
if (!isRecord(filter)) {
|
|
298
|
+
return filter;
|
|
299
|
+
}
|
|
300
|
+
if (Array.isArray(filter.and)) {
|
|
301
|
+
return Filters.AND(filter.and.map((item) => normalizeFilterNode(item)));
|
|
302
|
+
}
|
|
303
|
+
if (Array.isArray(filter.or)) {
|
|
304
|
+
return Filters.OR(filter.or.map((item) => normalizeFilterNode(item)));
|
|
305
|
+
}
|
|
306
|
+
if (typeof filter.field === 'string') {
|
|
307
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'eq')) {
|
|
308
|
+
return Filters.EQ(filter.field, normalizeFilterValue(filter.eq));
|
|
309
|
+
}
|
|
310
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'neq')) {
|
|
311
|
+
return Filters.NEQ(filter.field, normalizeFilterValue(filter.neq));
|
|
312
|
+
}
|
|
313
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'gt')) {
|
|
314
|
+
return Filters.GT(filter.field, normalizeFilterValue(filter.gt));
|
|
315
|
+
}
|
|
316
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'gte')) {
|
|
317
|
+
return Filters.GTE(filter.field, normalizeFilterValue(filter.gte));
|
|
318
|
+
}
|
|
319
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'lt')) {
|
|
320
|
+
return Filters.LT(filter.field, normalizeFilterValue(filter.lt));
|
|
321
|
+
}
|
|
322
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'lte')) {
|
|
323
|
+
return Filters.LTE(filter.field, normalizeFilterValue(filter.lte));
|
|
324
|
+
}
|
|
325
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'in')) {
|
|
326
|
+
return Filters.IN(filter.field, normalizeFilterValue(filter.in));
|
|
327
|
+
}
|
|
328
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'not_in')) {
|
|
329
|
+
return Filters.NOT_IN(filter.field, normalizeFilterValue(filter.not_in));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return filter;
|
|
333
|
+
}
|
|
334
|
+
function matchesFilterExpression(row, filter) {
|
|
335
|
+
var _a, _b, _c, _d;
|
|
336
|
+
if (Array.isArray(filter)) {
|
|
337
|
+
return filter.every((item) => matchesFilterExpression(row, item));
|
|
338
|
+
}
|
|
339
|
+
if ('and' in filter) {
|
|
340
|
+
return filter.and.every((item) => matchesFilterExpression(row, item));
|
|
341
|
+
}
|
|
342
|
+
if ('or' in filter) {
|
|
343
|
+
return filter.or.some((item) => matchesFilterExpression(row, item));
|
|
344
|
+
}
|
|
345
|
+
const value = row[filter.field];
|
|
346
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'eq')) {
|
|
347
|
+
return value === normalizeFilterValue(filter.eq);
|
|
348
|
+
}
|
|
349
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'neq')) {
|
|
350
|
+
return value !== normalizeFilterValue(filter.neq);
|
|
351
|
+
}
|
|
352
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'gt')) {
|
|
353
|
+
return compareComparableValues(value, normalizeFilterValue(filter.gt)) > 0;
|
|
121
354
|
}
|
|
355
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'gte')) {
|
|
356
|
+
return compareComparableValues(value, normalizeFilterValue(filter.gte)) >= 0;
|
|
357
|
+
}
|
|
358
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'lt')) {
|
|
359
|
+
return compareComparableValues(value, normalizeFilterValue(filter.lt)) < 0;
|
|
360
|
+
}
|
|
361
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'lte')) {
|
|
362
|
+
return compareComparableValues(value, normalizeFilterValue(filter.lte)) <= 0;
|
|
363
|
+
}
|
|
364
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'in')) {
|
|
365
|
+
return (_b = (_a = filter.in) === null || _a === void 0 ? void 0 : _a.includes(value)) !== null && _b !== void 0 ? _b : false;
|
|
366
|
+
}
|
|
367
|
+
if (Object.prototype.hasOwnProperty.call(filter, 'not_in')) {
|
|
368
|
+
return !((_d = (_c = filter.not_in) === null || _c === void 0 ? void 0 : _c.includes(value)) !== null && _d !== void 0 ? _d : false);
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
function compareComparableValues(left, right) {
|
|
373
|
+
const leftNumber = Number(left);
|
|
374
|
+
const rightNumber = Number(right);
|
|
375
|
+
if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) {
|
|
376
|
+
return leftNumber - rightNumber;
|
|
377
|
+
}
|
|
378
|
+
return String(left !== null && left !== void 0 ? left : '').localeCompare(String(right !== null && right !== void 0 ? right : ''));
|
|
122
379
|
}
|
|
123
|
-
function
|
|
124
|
-
if (
|
|
125
|
-
return
|
|
380
|
+
function normalizeFilterValue(value) {
|
|
381
|
+
if (!isRecord(value) || typeof value.now_minus !== 'string') {
|
|
382
|
+
return value;
|
|
383
|
+
}
|
|
384
|
+
const match = value.now_minus.match(NOW_MINUS_RE);
|
|
385
|
+
if (!match) {
|
|
386
|
+
return value;
|
|
387
|
+
}
|
|
388
|
+
const amount = Number(match[1]);
|
|
389
|
+
const unit = match[2];
|
|
390
|
+
const date = new Date();
|
|
391
|
+
if (unit === 'h') {
|
|
392
|
+
date.setHours(date.getHours() - amount);
|
|
126
393
|
}
|
|
127
|
-
|
|
394
|
+
else if (unit === 'w') {
|
|
395
|
+
date.setDate(date.getDate() - amount * 7);
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
date.setDate(date.getDate() - amount);
|
|
399
|
+
}
|
|
400
|
+
return date.toISOString();
|
|
401
|
+
}
|
|
402
|
+
function toFiniteNumber(value) {
|
|
403
|
+
const numberValue = typeof value === 'number' ? value : Number(value);
|
|
404
|
+
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
128
405
|
}
|
|
129
406
|
function isRecord(value) {
|
|
130
407
|
return typeof value === 'object' && value !== null;
|
package/endpoint/dashboard.ts
CHANGED
package/endpoint/widgets.ts
CHANGED
|
@@ -53,10 +53,13 @@ function formatWidgetConfigFieldPath(field: string) {
|
|
|
53
53
|
const fieldAliases = new Map([
|
|
54
54
|
['minWidth', 'min_width'],
|
|
55
55
|
['maxWidth', 'max_width'],
|
|
56
|
-
['dataSource', 'data_source'],
|
|
57
|
-
['resourceId', 'resource_id'],
|
|
58
56
|
['groupBy', 'group_by'],
|
|
57
|
+
['orderBy', 'order_by'],
|
|
59
58
|
['pageSize', 'page_size'],
|
|
59
|
+
['timeSeries', 'time_series'],
|
|
60
|
+
['valueField', 'value_field'],
|
|
61
|
+
['targetValue', 'target_value'],
|
|
62
|
+
['targetField', 'target_field'],
|
|
60
63
|
]);
|
|
61
64
|
|
|
62
65
|
return field
|