@adminforth/dashboard 1.11.2 → 1.12.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 +43 -2
- package/custom/api/dashboardApi.ts +72 -10
- package/custom/model/dashboard.types.ts +6 -0
- package/custom/runtime/DashboardGroup.vue +15 -68
- package/custom/runtime/DashboardToolbarButton.vue +32 -0
- package/custom/runtime/DashboardToolbarIcon.vue +52 -0
- package/custom/runtime/WidgetShell.vue +15 -68
- package/custom/skills/adminforth-dashboard/SKILL.md +63 -13
- package/custom/widgets/chart/StackedBarChart.vue +64 -7
- package/dist/custom/api/dashboardApi.js +59 -10
- package/dist/custom/api/dashboardApi.ts +72 -10
- package/dist/custom/model/dashboard.types.d.ts +9 -0
- package/dist/custom/model/dashboard.types.ts +6 -0
- package/dist/custom/queries/useDashboardConfig.d.ts +80 -0
- package/dist/custom/queries/useWidgetData.d.ts +80 -0
- package/dist/custom/runtime/DashboardGroup.vue +15 -68
- package/dist/custom/runtime/DashboardToolbarButton.vue +32 -0
- package/dist/custom/runtime/DashboardToolbarIcon.vue +52 -0
- package/dist/custom/runtime/WidgetShell.vue +15 -68
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +63 -13
- package/dist/custom/widgets/chart/StackedBarChart.vue +64 -7
- package/dist/schema/api.d.ts +742 -802
- package/dist/schema/api.js +2 -2
- package/dist/schema/widget.d.ts +75 -81
- package/dist/schema/widget.js +1 -1
- package/dist/schema/widgets/charts.d.ts +84 -160
- package/dist/schema/widgets/charts.js +2 -2
- package/dist/schema/widgets/common.d.ts +115 -0
- package/dist/schema/widgets/common.js +17 -1
- package/dist/schema/widgets/gauge-card.d.ts +8 -0
- package/dist/schema/widgets/kpi-card.d.ts +8 -0
- package/dist/schema/widgets/pivot-table.d.ts +8 -0
- package/dist/schema/widgets/table.d.ts +8 -0
- package/dist/services/widgetDataService.js +42 -0
- package/package.json +3 -3
- package/schema/api.ts +2 -1
- package/schema/widget.ts +2 -0
- package/schema/widgets/charts.ts +2 -1
- package/schema/widgets/common.ts +19 -1
- package/services/widgetDataService.ts +68 -0
|
@@ -117,6 +117,113 @@ export declare const QueryCalcItemSchema: z.ZodObject<{
|
|
|
117
117
|
calc: z.ZodString;
|
|
118
118
|
as: z.ZodString;
|
|
119
119
|
}, z.core.$strict>;
|
|
120
|
+
export declare const ResourceQueryConfigSchema: z.ZodObject<{
|
|
121
|
+
source: z.ZodOptional<z.ZodLiteral<"resource">>;
|
|
122
|
+
resource: z.ZodString;
|
|
123
|
+
select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
124
|
+
field: z.ZodString;
|
|
125
|
+
as: z.ZodOptional<z.ZodString>;
|
|
126
|
+
grain: z.ZodOptional<z.ZodEnum<{
|
|
127
|
+
day: "day";
|
|
128
|
+
week: "week";
|
|
129
|
+
month: "month";
|
|
130
|
+
year: "year";
|
|
131
|
+
}>>;
|
|
132
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
133
|
+
agg: z.ZodEnum<{
|
|
134
|
+
sum: "sum";
|
|
135
|
+
count: "count";
|
|
136
|
+
count_distinct: "count_distinct";
|
|
137
|
+
avg: "avg";
|
|
138
|
+
min: "min";
|
|
139
|
+
max: "max";
|
|
140
|
+
median: "median";
|
|
141
|
+
}>;
|
|
142
|
+
field: z.ZodOptional<z.ZodString>;
|
|
143
|
+
as: z.ZodString;
|
|
144
|
+
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
145
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
146
|
+
calc: z.ZodString;
|
|
147
|
+
as: z.ZodString;
|
|
148
|
+
}, z.core.$strict>]>>>;
|
|
149
|
+
sparkline: z.ZodOptional<z.ZodObject<{
|
|
150
|
+
field: z.ZodString;
|
|
151
|
+
grain: z.ZodEnum<{
|
|
152
|
+
day: "day";
|
|
153
|
+
week: "week";
|
|
154
|
+
month: "month";
|
|
155
|
+
year: "year";
|
|
156
|
+
}>;
|
|
157
|
+
as: z.ZodString;
|
|
158
|
+
fill_missing: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
159
|
+
}, z.core.$strict>>;
|
|
160
|
+
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
161
|
+
group_by: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
162
|
+
field: z.ZodString;
|
|
163
|
+
as: z.ZodOptional<z.ZodString>;
|
|
164
|
+
grain: z.ZodOptional<z.ZodEnum<{
|
|
165
|
+
day: "day";
|
|
166
|
+
week: "week";
|
|
167
|
+
month: "month";
|
|
168
|
+
year: "year";
|
|
169
|
+
}>>;
|
|
170
|
+
timezone: z.ZodOptional<z.ZodString>;
|
|
171
|
+
}, z.core.$strict>]>>>;
|
|
172
|
+
order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
173
|
+
field: z.ZodString;
|
|
174
|
+
direction: z.ZodOptional<z.ZodEnum<{
|
|
175
|
+
asc: "asc";
|
|
176
|
+
desc: "desc";
|
|
177
|
+
}>>;
|
|
178
|
+
}, z.core.$strict>>>;
|
|
179
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
180
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
181
|
+
bucket: z.ZodOptional<z.ZodObject<{
|
|
182
|
+
field: z.ZodString;
|
|
183
|
+
buckets: z.ZodArray<z.ZodObject<{
|
|
184
|
+
label: z.ZodString;
|
|
185
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
186
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
187
|
+
}, z.core.$strict>>;
|
|
188
|
+
}, z.core.$strict>>;
|
|
189
|
+
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
190
|
+
calc: z.ZodString;
|
|
191
|
+
as: z.ZodString;
|
|
192
|
+
}, z.core.$strict>>>;
|
|
193
|
+
formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
194
|
+
}, z.core.$strict>;
|
|
195
|
+
export declare const HistogramResourceQueryConfigSchema: z.ZodObject<{
|
|
196
|
+
source: z.ZodOptional<z.ZodLiteral<"resource">>;
|
|
197
|
+
resource: z.ZodString;
|
|
198
|
+
select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
199
|
+
field: z.ZodString;
|
|
200
|
+
as: z.ZodOptional<z.ZodString>;
|
|
201
|
+
grain: z.ZodOptional<z.ZodEnum<{
|
|
202
|
+
day: "day";
|
|
203
|
+
week: "week";
|
|
204
|
+
month: "month";
|
|
205
|
+
year: "year";
|
|
206
|
+
}>>;
|
|
207
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
208
|
+
calc: z.ZodString;
|
|
209
|
+
as: z.ZodString;
|
|
210
|
+
}, z.core.$strict>]>>>;
|
|
211
|
+
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
212
|
+
order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
213
|
+
field: z.ZodString;
|
|
214
|
+
direction: z.ZodOptional<z.ZodEnum<{
|
|
215
|
+
asc: "asc";
|
|
216
|
+
desc: "desc";
|
|
217
|
+
}>>;
|
|
218
|
+
}, z.core.$strict>>>;
|
|
219
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
220
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
221
|
+
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
222
|
+
calc: z.ZodString;
|
|
223
|
+
as: z.ZodString;
|
|
224
|
+
}, z.core.$strict>>>;
|
|
225
|
+
formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
226
|
+
}, z.core.$strict>;
|
|
120
227
|
export declare const QueryConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
121
228
|
source: z.ZodOptional<z.ZodLiteral<"resource">>;
|
|
122
229
|
resource: z.ZodString;
|
|
@@ -212,6 +319,14 @@ export declare const QueryConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
212
319
|
}, z.core.$strict>>;
|
|
213
320
|
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
214
321
|
}, z.core.$strict>>;
|
|
322
|
+
bucket: z.ZodOptional<z.ZodObject<{
|
|
323
|
+
field: z.ZodString;
|
|
324
|
+
buckets: z.ZodArray<z.ZodObject<{
|
|
325
|
+
label: z.ZodString;
|
|
326
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
327
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
328
|
+
}, z.core.$strict>>;
|
|
329
|
+
}, z.core.$strict>>;
|
|
215
330
|
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
216
331
|
calc: z.ZodString;
|
|
217
332
|
as: z.ZodString;
|
|
@@ -123,7 +123,7 @@ export const QueryCalcItemSchema = z.object({
|
|
|
123
123
|
calc: z.string(),
|
|
124
124
|
as: z.string(),
|
|
125
125
|
}).strict();
|
|
126
|
-
const ResourceQueryConfigSchema = z.object({
|
|
126
|
+
export const ResourceQueryConfigSchema = z.object({
|
|
127
127
|
source: z.literal('resource').optional(),
|
|
128
128
|
resource: z.string(),
|
|
129
129
|
select: z.array(QuerySelectItemSchema).optional(),
|
|
@@ -142,6 +142,21 @@ const ResourceQueryConfigSchema = z.object({
|
|
|
142
142
|
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
143
143
|
formatting: z.record(z.string(), z.unknown()).optional(),
|
|
144
144
|
}).strict();
|
|
145
|
+
const HistogramQuerySelectItemSchema = z.union([
|
|
146
|
+
QueryFieldSelectItemSchema,
|
|
147
|
+
QueryCalcSelectItemSchema,
|
|
148
|
+
]);
|
|
149
|
+
export const HistogramResourceQueryConfigSchema = z.object({
|
|
150
|
+
source: z.literal('resource').optional(),
|
|
151
|
+
resource: z.string(),
|
|
152
|
+
select: z.array(HistogramQuerySelectItemSchema).optional(),
|
|
153
|
+
filters: FilterExpressionSchema.optional(),
|
|
154
|
+
order_by: z.array(QueryOrderByItemSchema).optional(),
|
|
155
|
+
limit: z.number().int().positive().optional(),
|
|
156
|
+
offset: z.number().int().nonnegative().optional(),
|
|
157
|
+
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
158
|
+
formatting: z.record(z.string(), z.unknown()).optional(),
|
|
159
|
+
}).strict();
|
|
145
160
|
const StepsQuerySelectStepSchema = z.object({
|
|
146
161
|
name: z.string(),
|
|
147
162
|
resource: z.string(),
|
|
@@ -153,6 +168,7 @@ export const QueryConfigSchema = z.union([
|
|
|
153
168
|
z.object({
|
|
154
169
|
source: z.literal('steps'),
|
|
155
170
|
steps: z.array(StepsQuerySelectStepSchema).min(1),
|
|
171
|
+
bucket: BucketConfigSchema.optional(),
|
|
156
172
|
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
157
173
|
order_by: z.array(QueryOrderByItemSchema).optional(),
|
|
158
174
|
limit: z.number().int().positive().optional(),
|
|
@@ -190,6 +190,14 @@ export declare const GaugeCardWidgetConfigSchema: z.ZodObject<{
|
|
|
190
190
|
}, z.core.$strict>>;
|
|
191
191
|
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
192
192
|
}, z.core.$strict>>;
|
|
193
|
+
bucket: z.ZodOptional<z.ZodObject<{
|
|
194
|
+
field: z.ZodString;
|
|
195
|
+
buckets: z.ZodArray<z.ZodObject<{
|
|
196
|
+
label: z.ZodString;
|
|
197
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
198
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
199
|
+
}, z.core.$strict>>;
|
|
200
|
+
}, z.core.$strict>>;
|
|
193
201
|
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
194
202
|
calc: z.ZodString;
|
|
195
203
|
as: z.ZodString;
|
|
@@ -230,6 +230,14 @@ export declare const KpiCardWidgetConfigSchema: z.ZodObject<{
|
|
|
230
230
|
}, z.core.$strict>>;
|
|
231
231
|
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
232
232
|
}, z.core.$strict>>;
|
|
233
|
+
bucket: z.ZodOptional<z.ZodObject<{
|
|
234
|
+
field: z.ZodString;
|
|
235
|
+
buckets: z.ZodArray<z.ZodObject<{
|
|
236
|
+
label: z.ZodString;
|
|
237
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
238
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
239
|
+
}, z.core.$strict>>;
|
|
240
|
+
}, z.core.$strict>>;
|
|
233
241
|
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
234
242
|
calc: z.ZodString;
|
|
235
243
|
as: z.ZodString;
|
|
@@ -214,6 +214,14 @@ export declare const PivotTableWidgetConfigSchema: z.ZodObject<{
|
|
|
214
214
|
}, z.core.$strict>>;
|
|
215
215
|
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
216
216
|
}, z.core.$strict>>;
|
|
217
|
+
bucket: z.ZodOptional<z.ZodObject<{
|
|
218
|
+
field: z.ZodString;
|
|
219
|
+
buckets: z.ZodArray<z.ZodObject<{
|
|
220
|
+
label: z.ZodString;
|
|
221
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
222
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
223
|
+
}, z.core.$strict>>;
|
|
224
|
+
}, z.core.$strict>>;
|
|
217
225
|
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
218
226
|
calc: z.ZodString;
|
|
219
227
|
as: z.ZodString;
|
|
@@ -148,6 +148,14 @@ export declare const TableWidgetConfigSchema: z.ZodObject<{
|
|
|
148
148
|
}, z.core.$strict>>;
|
|
149
149
|
filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
150
150
|
}, z.core.$strict>>;
|
|
151
|
+
bucket: z.ZodOptional<z.ZodObject<{
|
|
152
|
+
field: z.ZodString;
|
|
153
|
+
buckets: z.ZodArray<z.ZodObject<{
|
|
154
|
+
label: z.ZodString;
|
|
155
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
156
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
157
|
+
}, z.core.$strict>>;
|
|
158
|
+
}, z.core.$strict>>;
|
|
151
159
|
calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
152
160
|
calc: z.ZodString;
|
|
153
161
|
as: z.ZodString;
|
|
@@ -63,6 +63,9 @@ function getQueryWidgetData(adminforth, query, variables) {
|
|
|
63
63
|
function getStepsQueryData(adminforth, query, variables) {
|
|
64
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
65
65
|
var _a, _b, _c, _d;
|
|
66
|
+
if (query.bucket) {
|
|
67
|
+
return getBucketedStepsQueryData(adminforth, query, query.bucket, variables);
|
|
68
|
+
}
|
|
66
69
|
const rows = yield Promise.all(query.steps.map((step) => __awaiter(this, void 0, void 0, function* () {
|
|
67
70
|
const select = getStepSelect(step);
|
|
68
71
|
const [values = {}] = yield getAggregateRows(adminforth, step.resource, step.filters, select, []);
|
|
@@ -86,6 +89,35 @@ function getStepsQueryData(adminforth, query, variables) {
|
|
|
86
89
|
};
|
|
87
90
|
});
|
|
88
91
|
}
|
|
92
|
+
function getBucketedStepsQueryData(adminforth, query, bucketConfig, variables) {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
var _a, _b, _c, _d;
|
|
95
|
+
const rows = (yield Promise.all(query.steps.map((step) => __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
const select = getStepSelect(step);
|
|
97
|
+
const stepRows = yield Promise.all(bucketConfig.buckets.map((bucket) => __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const [values = {}] = yield getAggregateRows(adminforth, step.resource, mergeFilters(step.filters, getBucketFilter(bucketConfig, bucket)), select, []);
|
|
99
|
+
return buildCalculatedRow(Object.assign({ label: bucket.label, name: step.name, resource: step.resource }, values), select, query.calcs, variables);
|
|
100
|
+
})));
|
|
101
|
+
return stepRows;
|
|
102
|
+
})))).flat();
|
|
103
|
+
const orderedRows = sortRows(rows, query.order_by);
|
|
104
|
+
const slicedRows = typeof query.limit === 'number'
|
|
105
|
+
? orderedRows.slice((_a = query.offset) !== null && _a !== void 0 ? _a : 0, ((_b = query.offset) !== null && _b !== void 0 ? _b : 0) + query.limit)
|
|
106
|
+
: orderedRows.slice((_c = query.offset) !== null && _c !== void 0 ? _c : 0);
|
|
107
|
+
const columns = Array.from(new Set([
|
|
108
|
+
'label',
|
|
109
|
+
'name',
|
|
110
|
+
'resource',
|
|
111
|
+
...query.steps.flatMap((step) => getStepSelect(step).map((item) => item.as)),
|
|
112
|
+
...((_d = query.calcs) !== null && _d !== void 0 ? _d : []).map((item) => item.as),
|
|
113
|
+
]));
|
|
114
|
+
return {
|
|
115
|
+
kind: 'aggregate',
|
|
116
|
+
columns,
|
|
117
|
+
rows: slicedRows,
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
|
89
121
|
function getSingleAggregateWidgetData(adminforth, query, aggregate) {
|
|
90
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
91
123
|
var _a;
|
|
@@ -256,6 +288,16 @@ function getSingleAggregateSelectItem(query) {
|
|
|
256
288
|
function isStepsQuery(query) {
|
|
257
289
|
return query.source === 'steps';
|
|
258
290
|
}
|
|
291
|
+
function getBucketFilter(bucketConfig, bucket) {
|
|
292
|
+
const filters = [];
|
|
293
|
+
if (typeof bucket.min === 'number') {
|
|
294
|
+
filters.push({ field: bucketConfig.field, gte: bucket.min });
|
|
295
|
+
}
|
|
296
|
+
if (typeof bucket.max === 'number') {
|
|
297
|
+
filters.push({ field: bucketConfig.field, lt: bucket.max });
|
|
298
|
+
}
|
|
299
|
+
return filters.length ? { and: filters } : undefined;
|
|
300
|
+
}
|
|
259
301
|
function getStepSelect(step) {
|
|
260
302
|
return step.select;
|
|
261
303
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/dashboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
"description": "Dashboard plugin for AdminForth",
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "latest",
|
|
24
|
-
"adminforth": "2.
|
|
24
|
+
"adminforth": "2.71.1",
|
|
25
25
|
"semantic-release": "^24.2.1",
|
|
26
26
|
"semantic-release-slack-bot": "^4.0.2",
|
|
27
27
|
"typescript": "^5.7.3",
|
|
28
28
|
"vue-tsc": "^3.3.2"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"adminforth": "
|
|
31
|
+
"adminforth": "2.71.1"
|
|
32
32
|
},
|
|
33
33
|
"release": {
|
|
34
34
|
"plugins": [
|
package/schema/api.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
BarChartSchema,
|
|
4
4
|
FunnelChartSchema,
|
|
5
5
|
GaugeCardViewConfigSchema,
|
|
6
|
+
HistogramResourceQueryConfigSchema,
|
|
6
7
|
HistogramChartSchema,
|
|
7
8
|
KpiCardViewConfigSchema,
|
|
8
9
|
LineChartSchema,
|
|
@@ -151,7 +152,7 @@ const ConfigurablePieChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
|
|
|
151
152
|
const ConfigurableHistogramChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
|
|
152
153
|
target: z.literal('chart'),
|
|
153
154
|
chart: HistogramChartSchema,
|
|
154
|
-
query:
|
|
155
|
+
query: HistogramResourceQueryConfigSchema,
|
|
155
156
|
})
|
|
156
157
|
|
|
157
158
|
const ConfigurableFunnelChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
|
package/schema/widget.ts
CHANGED
|
@@ -33,7 +33,9 @@ export {
|
|
|
33
33
|
} from './widgets/table.js'
|
|
34
34
|
export {
|
|
35
35
|
EmptyWidgetConfigSchema,
|
|
36
|
+
HistogramResourceQueryConfigSchema,
|
|
36
37
|
QueryConfigSchema,
|
|
38
|
+
ResourceQueryConfigSchema,
|
|
37
39
|
WidgetEditableBaseSchema,
|
|
38
40
|
} from './widgets/common.js'
|
|
39
41
|
import { ChartWidgetTargetConfigSchema } from './widgets/charts.js'
|
package/schema/widgets/charts.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import {
|
|
3
3
|
ChartFieldRefSchema,
|
|
4
|
+
HistogramResourceQueryConfigSchema,
|
|
4
5
|
QueryConfigSchema,
|
|
5
6
|
WidgetBaseSchema,
|
|
6
7
|
} from './common.js'
|
|
@@ -93,7 +94,7 @@ export const PieChartWidgetConfigSchema = WidgetBaseSchema.extend({
|
|
|
93
94
|
export const HistogramChartWidgetConfigSchema = WidgetBaseSchema.extend({
|
|
94
95
|
target: z.literal('chart'),
|
|
95
96
|
chart: HistogramChartSchema,
|
|
96
|
-
query:
|
|
97
|
+
query: HistogramResourceQueryConfigSchema,
|
|
97
98
|
})
|
|
98
99
|
|
|
99
100
|
export const FunnelChartWidgetConfigSchema = WidgetBaseSchema.extend({
|
package/schema/widgets/common.ts
CHANGED
|
@@ -140,7 +140,7 @@ export const QueryCalcItemSchema = z.object({
|
|
|
140
140
|
as: z.string(),
|
|
141
141
|
}).strict()
|
|
142
142
|
|
|
143
|
-
const ResourceQueryConfigSchema = z.object({
|
|
143
|
+
export const ResourceQueryConfigSchema = z.object({
|
|
144
144
|
source: z.literal('resource').optional(),
|
|
145
145
|
resource: z.string(),
|
|
146
146
|
select: z.array(QuerySelectItemSchema).optional(),
|
|
@@ -160,6 +160,23 @@ const ResourceQueryConfigSchema = z.object({
|
|
|
160
160
|
formatting: z.record(z.string(), z.unknown()).optional(),
|
|
161
161
|
}).strict()
|
|
162
162
|
|
|
163
|
+
const HistogramQuerySelectItemSchema = z.union([
|
|
164
|
+
QueryFieldSelectItemSchema,
|
|
165
|
+
QueryCalcSelectItemSchema,
|
|
166
|
+
])
|
|
167
|
+
|
|
168
|
+
export const HistogramResourceQueryConfigSchema = z.object({
|
|
169
|
+
source: z.literal('resource').optional(),
|
|
170
|
+
resource: z.string(),
|
|
171
|
+
select: z.array(HistogramQuerySelectItemSchema).optional(),
|
|
172
|
+
filters: FilterExpressionSchema.optional(),
|
|
173
|
+
order_by: z.array(QueryOrderByItemSchema).optional(),
|
|
174
|
+
limit: z.number().int().positive().optional(),
|
|
175
|
+
offset: z.number().int().nonnegative().optional(),
|
|
176
|
+
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
177
|
+
formatting: z.record(z.string(), z.unknown()).optional(),
|
|
178
|
+
}).strict()
|
|
179
|
+
|
|
163
180
|
const StepsQuerySelectStepSchema = z.object({
|
|
164
181
|
name: z.string(),
|
|
165
182
|
resource: z.string(),
|
|
@@ -172,6 +189,7 @@ export const QueryConfigSchema = z.union([
|
|
|
172
189
|
z.object({
|
|
173
190
|
source: z.literal('steps'),
|
|
174
191
|
steps: z.array(StepsQuerySelectStepSchema).min(1),
|
|
192
|
+
bucket: BucketConfigSchema.optional(),
|
|
175
193
|
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
176
194
|
order_by: z.array(QueryOrderByItemSchema).optional(),
|
|
177
195
|
limit: z.number().int().positive().optional(),
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
FilterExpression,
|
|
11
11
|
QueryAggregateSelectItem,
|
|
12
12
|
QueryCalcSelectItem,
|
|
13
|
+
QueryBucketConfig,
|
|
13
14
|
QueryConfig,
|
|
14
15
|
QueryFieldSelectItem,
|
|
15
16
|
QueryGroupByItem,
|
|
@@ -153,6 +154,10 @@ async function getStepsQueryData(
|
|
|
153
154
|
query: Extract<QueryConfig, { source: 'steps' }>,
|
|
154
155
|
variables: DashboardVariables,
|
|
155
156
|
): Promise<DashboardWidgetData> {
|
|
157
|
+
if (query.bucket) {
|
|
158
|
+
return getBucketedStepsQueryData(adminforth, query, query.bucket, variables);
|
|
159
|
+
}
|
|
160
|
+
|
|
156
161
|
const rows = await Promise.all(query.steps.map(async (step) => {
|
|
157
162
|
const select = getStepSelect(step);
|
|
158
163
|
const [values = {}] = await getAggregateRows(
|
|
@@ -188,6 +193,52 @@ async function getStepsQueryData(
|
|
|
188
193
|
};
|
|
189
194
|
}
|
|
190
195
|
|
|
196
|
+
async function getBucketedStepsQueryData(
|
|
197
|
+
adminforth: IAdminForth,
|
|
198
|
+
query: Extract<QueryConfig, { source: 'steps' }>,
|
|
199
|
+
bucketConfig: QueryBucketConfig,
|
|
200
|
+
variables: DashboardVariables,
|
|
201
|
+
): Promise<DashboardWidgetData> {
|
|
202
|
+
const rows = (await Promise.all(query.steps.map(async (step) => {
|
|
203
|
+
const select = getStepSelect(step);
|
|
204
|
+
const stepRows = await Promise.all(bucketConfig.buckets.map(async (bucket) => {
|
|
205
|
+
const [values = {}] = await getAggregateRows(
|
|
206
|
+
adminforth,
|
|
207
|
+
step.resource,
|
|
208
|
+
mergeFilters(step.filters, getBucketFilter(bucketConfig, bucket)),
|
|
209
|
+
select,
|
|
210
|
+
[],
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
return buildCalculatedRow({
|
|
214
|
+
label: bucket.label,
|
|
215
|
+
name: step.name,
|
|
216
|
+
resource: step.resource,
|
|
217
|
+
...values,
|
|
218
|
+
}, select, query.calcs, variables);
|
|
219
|
+
}));
|
|
220
|
+
|
|
221
|
+
return stepRows;
|
|
222
|
+
}))).flat();
|
|
223
|
+
const orderedRows = sortRows(rows, query.order_by);
|
|
224
|
+
const slicedRows = typeof query.limit === 'number'
|
|
225
|
+
? orderedRows.slice(query.offset ?? 0, (query.offset ?? 0) + query.limit)
|
|
226
|
+
: orderedRows.slice(query.offset ?? 0);
|
|
227
|
+
const columns = Array.from(new Set([
|
|
228
|
+
'label',
|
|
229
|
+
'name',
|
|
230
|
+
'resource',
|
|
231
|
+
...query.steps.flatMap((step) => getStepSelect(step).map((item) => item.as)),
|
|
232
|
+
...(query.calcs ?? []).map((item) => item.as),
|
|
233
|
+
]));
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
kind: 'aggregate',
|
|
237
|
+
columns,
|
|
238
|
+
rows: slicedRows,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
191
242
|
async function getSingleAggregateWidgetData(
|
|
192
243
|
adminforth: IAdminForth,
|
|
193
244
|
query: ResourceQueryConfig,
|
|
@@ -447,6 +498,23 @@ function isStepsQuery(query: QueryConfig): query is Extract<QueryConfig, { sourc
|
|
|
447
498
|
return query.source === 'steps';
|
|
448
499
|
}
|
|
449
500
|
|
|
501
|
+
function getBucketFilter(
|
|
502
|
+
bucketConfig: QueryBucketConfig,
|
|
503
|
+
bucket: QueryBucketConfig['buckets'][number],
|
|
504
|
+
): FilterExpression | undefined {
|
|
505
|
+
const filters: FilterExpression[] = [];
|
|
506
|
+
|
|
507
|
+
if (typeof bucket.min === 'number') {
|
|
508
|
+
filters.push({ field: bucketConfig.field, gte: bucket.min });
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (typeof bucket.max === 'number') {
|
|
512
|
+
filters.push({ field: bucketConfig.field, lt: bucket.max });
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return filters.length ? { and: filters } : undefined;
|
|
516
|
+
}
|
|
517
|
+
|
|
450
518
|
function getStepSelect(step: StepsQueryStepConfig): QueryAggregateSelectItem[] {
|
|
451
519
|
return step.select;
|
|
452
520
|
}
|