@adminforth/dashboard 1.4.0 → 1.4.2
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 +23 -4
- package/custom/api/dashboardApi.ts +6 -9
- package/custom/model/dashboard.types.ts +60 -275
- package/custom/model/dashboardTopics.ts +5 -0
- package/custom/package.json +1 -0
- package/custom/runtime/DashboardGroup.vue +2 -2
- package/custom/runtime/DashboardPage.vue +17 -7
- package/custom/runtime/DashboardRuntime.vue +20 -8
- package/custom/runtime/WidgetRenderer.vue +1 -2
- package/custom/runtime/WidgetShell.vue +3 -3
- package/custom/skills/adminforth-dashboard/SKILL.md +2 -2
- package/custom/widgets/{gauge-card/GaugeCardWidget.vue → GaugeCardWidget.vue} +63 -61
- package/custom/widgets/{kpi-card/KpiCardWidget.vue → KpiCardWidget.vue} +35 -33
- package/custom/widgets/{pivot-table/PivotTableWidget.vue → PivotTableWidget.vue} +71 -68
- package/custom/widgets/{table/TableWidget.vue → TableWidget.vue} +5 -5
- package/custom/widgets/chart/{bar/BarChart.vue → BarChart.vue} +2 -2
- package/custom/widgets/chart/ChartWidget.vue +4 -15
- package/{dist/custom/widgets/chart/funnel → custom/widgets/chart}/FunnelChart.vue +80 -78
- package/{dist/custom/widgets/chart/line → custom/widgets/chart}/LineChart.vue +2 -2
- package/custom/widgets/chart/{pie/PieChart.vue → PieChart.vue} +2 -2
- package/{dist/custom/widgets/chart/stacked-bar → custom/widgets/chart}/StackedBarChart.vue +97 -95
- package/custom/widgets/chart/chart.types.ts +0 -28
- package/dist/custom/api/dashboardApi.d.ts +4 -8
- package/dist/custom/api/dashboardApi.js +2 -6
- package/dist/custom/api/dashboardApi.ts +6 -9
- package/dist/custom/composables/useElementSize.js +7 -10
- package/dist/custom/model/dashboard.types.d.ts +38 -32
- package/dist/custom/model/dashboard.types.js +4 -161
- package/dist/custom/model/dashboard.types.ts +60 -275
- package/dist/custom/model/dashboardTopics.d.ts +2 -0
- package/dist/custom/model/dashboardTopics.js +4 -0
- package/dist/custom/model/dashboardTopics.ts +5 -0
- package/dist/custom/package.json +1 -0
- package/dist/custom/queries/useDashboardConfig.d.ts +96 -96
- package/dist/custom/queries/useDashboardConfig.js +9 -12
- package/dist/custom/queries/useWidgetData.d.ts +96 -96
- package/dist/custom/queries/useWidgetData.js +9 -12
- package/dist/custom/runtime/DashboardGroup.vue +2 -2
- package/dist/custom/runtime/DashboardPage.vue +17 -7
- package/dist/custom/runtime/DashboardRuntime.vue +20 -8
- package/dist/custom/runtime/WidgetRenderer.vue +1 -2
- package/dist/custom/runtime/WidgetShell.vue +3 -3
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +2 -2
- package/dist/custom/widgets/{gauge-card/GaugeCardWidget.vue → GaugeCardWidget.vue} +63 -61
- package/dist/custom/widgets/{kpi-card/KpiCardWidget.vue → KpiCardWidget.vue} +35 -33
- package/dist/custom/widgets/{pivot-table/PivotTableWidget.vue → PivotTableWidget.vue} +71 -68
- package/dist/custom/widgets/{table/TableWidget.vue → TableWidget.vue} +5 -5
- package/dist/custom/widgets/chart/{bar/BarChart.vue → BarChart.vue} +2 -2
- package/dist/custom/widgets/chart/ChartWidget.vue +4 -15
- package/{custom/widgets/chart/funnel → dist/custom/widgets/chart}/FunnelChart.vue +80 -78
- package/{custom/widgets/chart/line → dist/custom/widgets/chart}/LineChart.vue +2 -2
- package/dist/custom/widgets/chart/{pie/PieChart.vue → PieChart.vue} +2 -2
- package/{custom/widgets/chart/stacked-bar → dist/custom/widgets/chart}/StackedBarChart.vue +97 -95
- package/dist/custom/widgets/chart/chart.types.d.ts +0 -2
- package/dist/custom/widgets/chart/chart.types.js +1 -25
- package/dist/custom/widgets/chart/chart.types.ts +0 -28
- package/dist/custom/widgets/chart/chart.utils.js +6 -14
- package/dist/custom/widgets/registry.js +14 -22
- package/dist/endpoint/dashboard.d.ts +2 -3
- package/dist/endpoint/dashboard.js +12 -32
- package/dist/endpoint/groups.d.ts +2 -21
- package/dist/endpoint/groups.js +18 -16
- package/dist/endpoint/widgets.d.ts +0 -3
- package/dist/endpoint/widgets.js +27 -74
- package/dist/index.js +1 -3
- package/dist/schema/api.d.ts +2090 -511
- package/dist/schema/api.js +18 -15
- package/dist/schema/widget.d.ts +1003 -250
- package/dist/schema/widget.js +102 -46
- package/dist/services/dashboardConfigService.d.ts +0 -10
- package/dist/services/dashboardConfigService.js +6 -21
- package/dist/services/widgetDataService.js +226 -196
- package/endpoint/dashboard.ts +13 -46
- package/endpoint/groups.ts +25 -42
- package/endpoint/widgets.ts +36 -95
- package/index.ts +0 -3
- package/package.json +3 -3
- package/schema/api.ts +19 -15
- package/schema/widget.ts +113 -52
- package/services/dashboardConfigService.ts +6 -25
- package/services/widgetDataService.ts +304 -229
- package/custom/widgets/chart/histogram/HistogramChart.vue +0 -21
- package/dist/custom/widgets/chart/histogram/HistogramChart.vue +0 -21
- package/dist/services/widgetConfigValidator.d.ts +0 -8
- package/dist/services/widgetConfigValidator.js +0 -27
- package/services/widgetConfigValidator.ts +0 -61
package/schema/widget.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
export type DashboardWidgetConfigValidationError = {
|
|
4
|
-
field: string
|
|
5
|
-
message: string
|
|
6
|
-
}
|
|
7
|
-
|
|
2
|
+
export type { DashboardWidgetConfigValidationError } from '../custom/model/dashboard.types.js'
|
|
8
3
|
const DashboardWidgetSizeSchema = z.enum([
|
|
9
4
|
'small',
|
|
10
5
|
'medium',
|
|
@@ -38,6 +33,15 @@ const FieldRefSchema = z.union([
|
|
|
38
33
|
}).strict(),
|
|
39
34
|
])
|
|
40
35
|
|
|
36
|
+
const JsonValueSchema: z.ZodType = z.lazy(() => z.union([
|
|
37
|
+
z.string(),
|
|
38
|
+
z.number(),
|
|
39
|
+
z.boolean(),
|
|
40
|
+
z.null(),
|
|
41
|
+
z.array(JsonValueSchema),
|
|
42
|
+
z.record(z.string(), JsonValueSchema),
|
|
43
|
+
]))
|
|
44
|
+
|
|
41
45
|
const FilterExpressionSchema: z.ZodType = z.lazy(() => z.union([
|
|
42
46
|
z.array(FilterExpressionSchema),
|
|
43
47
|
z.object({
|
|
@@ -48,16 +52,16 @@ const FilterExpressionSchema: z.ZodType = z.lazy(() => z.union([
|
|
|
48
52
|
}).strict(),
|
|
49
53
|
z.object({
|
|
50
54
|
field: z.string(),
|
|
51
|
-
eq:
|
|
52
|
-
neq:
|
|
53
|
-
gt:
|
|
54
|
-
gte:
|
|
55
|
-
lt:
|
|
56
|
-
lte:
|
|
57
|
-
in: z.array(
|
|
58
|
-
not_in: z.array(
|
|
59
|
-
like:
|
|
60
|
-
ilike:
|
|
55
|
+
eq: JsonValueSchema.optional(),
|
|
56
|
+
neq: JsonValueSchema.optional(),
|
|
57
|
+
gt: JsonValueSchema.optional(),
|
|
58
|
+
gte: JsonValueSchema.optional(),
|
|
59
|
+
lt: JsonValueSchema.optional(),
|
|
60
|
+
lte: JsonValueSchema.optional(),
|
|
61
|
+
in: z.array(JsonValueSchema).optional(),
|
|
62
|
+
not_in: z.array(JsonValueSchema).optional(),
|
|
63
|
+
like: JsonValueSchema.optional(),
|
|
64
|
+
ilike: JsonValueSchema.optional(),
|
|
61
65
|
}).strict(),
|
|
62
66
|
]))
|
|
63
67
|
|
|
@@ -74,7 +78,7 @@ const QueryAggregateOperationSchema = z.enum([
|
|
|
74
78
|
const QueryFieldSelectItemSchema = z.object({
|
|
75
79
|
field: z.string(),
|
|
76
80
|
as: z.string().optional(),
|
|
77
|
-
grain: z.enum(['
|
|
81
|
+
grain: z.enum(['day', 'week', 'month', 'year']).optional(),
|
|
78
82
|
}).strict()
|
|
79
83
|
|
|
80
84
|
const QueryAggregateSelectItemSchema = z.object({
|
|
@@ -85,7 +89,7 @@ const QueryAggregateSelectItemSchema = z.object({
|
|
|
85
89
|
}).strict().superRefine((item, ctx) => {
|
|
86
90
|
if (!['count'].includes(item.agg) && !item.field) {
|
|
87
91
|
ctx.addIssue({
|
|
88
|
-
code:
|
|
92
|
+
code: 'custom',
|
|
89
93
|
path: ['field'],
|
|
90
94
|
message: `field is required for ${item.agg}`,
|
|
91
95
|
})
|
|
@@ -108,7 +112,7 @@ const QueryGroupByItemSchema = z.union([
|
|
|
108
112
|
z.object({
|
|
109
113
|
field: z.string(),
|
|
110
114
|
as: z.string().optional(),
|
|
111
|
-
grain: z.enum(['
|
|
115
|
+
grain: z.enum(['day', 'week', 'month', 'year']).optional(),
|
|
112
116
|
timezone: z.string().optional(),
|
|
113
117
|
}).strict(),
|
|
114
118
|
])
|
|
@@ -120,14 +124,14 @@ const QueryOrderByItemSchema = z.object({
|
|
|
120
124
|
|
|
121
125
|
const TimeSeriesConfigSchema = z.object({
|
|
122
126
|
field: z.string(),
|
|
123
|
-
grain: z.enum(['
|
|
127
|
+
grain: z.enum(['day', 'week', 'month', 'year']),
|
|
124
128
|
timezone: z.string().optional(),
|
|
125
129
|
}).strict()
|
|
126
130
|
|
|
127
131
|
const PeriodConfigSchema = z.object({
|
|
128
132
|
field: z.string(),
|
|
129
|
-
gte:
|
|
130
|
-
lt:
|
|
133
|
+
gte: JsonValueSchema.optional(),
|
|
134
|
+
lt: JsonValueSchema.optional(),
|
|
131
135
|
}).strict()
|
|
132
136
|
|
|
133
137
|
const BucketConfigSchema = z.object({
|
|
@@ -144,18 +148,18 @@ const QueryCalcItemSchema = z.object({
|
|
|
144
148
|
as: z.string(),
|
|
145
149
|
}).strict()
|
|
146
150
|
|
|
147
|
-
const FormattingConfigSchema = z.record(z.string(),
|
|
148
|
-
const VariablesConfigSchema = z.record(z.string(),
|
|
151
|
+
const FormattingConfigSchema = z.record(z.string(), JsonValueSchema)
|
|
152
|
+
const VariablesConfigSchema = z.record(z.string(), JsonValueSchema)
|
|
149
153
|
|
|
150
154
|
export const QueryConfigSchema = z.object({
|
|
151
155
|
resource: z.string(),
|
|
152
156
|
select: z.array(QuerySelectItemSchema).optional(),
|
|
153
157
|
filters: FilterExpressionSchema.optional(),
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
group_by: z.array(QueryGroupByItemSchema).optional(),
|
|
159
|
+
order_by: z.array(QueryOrderByItemSchema).optional(),
|
|
156
160
|
limit: z.number().int().positive().optional(),
|
|
157
161
|
offset: z.number().int().nonnegative().optional(),
|
|
158
|
-
|
|
162
|
+
time_series: TimeSeriesConfigSchema.optional(),
|
|
159
163
|
period: PeriodConfigSchema.optional(),
|
|
160
164
|
bucket: BucketConfigSchema.optional(),
|
|
161
165
|
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
@@ -174,28 +178,31 @@ export const FunnelQueryConfigSchema = z.object({
|
|
|
174
178
|
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
175
179
|
}).strict()
|
|
176
180
|
|
|
177
|
-
const
|
|
178
|
-
id: z.string().optional(),
|
|
179
|
-
group_id: z.string().optional(),
|
|
181
|
+
const EditableWidgetBaseSchema = z.object({
|
|
180
182
|
label: z.string().optional(),
|
|
181
183
|
variables: VariablesConfigSchema.optional(),
|
|
182
184
|
size: DashboardWidgetSizeSchema.optional(),
|
|
183
185
|
width: z.number().positive('Width must be greater than 0').optional(),
|
|
184
186
|
height: z.number().positive('Height must be greater than 0').optional(),
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
min_width: z.number().nonnegative('Min width must be a non-negative number').optional(),
|
|
188
|
+
max_width: z.number().nonnegative('Max width must be a non-negative number').nullable().optional(),
|
|
189
|
+
}).strict()
|
|
190
|
+
|
|
191
|
+
const StoredWidgetBaseSchema = EditableWidgetBaseSchema.extend({
|
|
192
|
+
id: z.string(),
|
|
193
|
+
group_id: z.string(),
|
|
194
|
+
order: z.number(),
|
|
188
195
|
})
|
|
189
196
|
|
|
190
197
|
const TableViewConfigSchema = z.object({
|
|
191
198
|
columns: z.array(FieldRefSchema).optional(),
|
|
192
199
|
pagination: z.boolean().optional(),
|
|
193
|
-
|
|
200
|
+
page_size: z.number().int().positive().optional(),
|
|
194
201
|
}).strict()
|
|
195
202
|
|
|
196
203
|
const ChartBaseSchema = z.object({
|
|
197
204
|
title: z.string().optional(),
|
|
198
|
-
})
|
|
205
|
+
}).strict()
|
|
199
206
|
|
|
200
207
|
const ChartBucketSchema = z.object({
|
|
201
208
|
label: z.string().min(1, 'Bucket label is required'),
|
|
@@ -275,8 +282,8 @@ const KpiCardViewConfigSchema = z.object({
|
|
|
275
282
|
text: z.string().optional(),
|
|
276
283
|
field: z.string().optional(),
|
|
277
284
|
}).strict().optional(),
|
|
278
|
-
comparison:
|
|
279
|
-
sparkline:
|
|
285
|
+
comparison: JsonValueSchema.optional(),
|
|
286
|
+
sparkline: JsonValueSchema.optional(),
|
|
280
287
|
}).strict()
|
|
281
288
|
|
|
282
289
|
const GaugeCardViewConfigSchema = z.object({
|
|
@@ -293,9 +300,9 @@ const GaugeCardViewConfigSchema = z.object({
|
|
|
293
300
|
label: z.string().optional(),
|
|
294
301
|
}).strict().optional(),
|
|
295
302
|
progress: z.object({
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
303
|
+
value_field: z.string(),
|
|
304
|
+
target_value: z.number().optional(),
|
|
305
|
+
target_field: z.string().optional(),
|
|
299
306
|
format: ValueFormatSchema,
|
|
300
307
|
}).strict().optional(),
|
|
301
308
|
color: z.string().optional(),
|
|
@@ -312,17 +319,44 @@ const PivotTableViewConfigSchema = z.object({
|
|
|
312
319
|
}).strict()).min(1),
|
|
313
320
|
}).strict()
|
|
314
321
|
|
|
315
|
-
|
|
322
|
+
const EditableEmptyWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
316
323
|
target: z.literal('empty'),
|
|
317
324
|
})
|
|
318
325
|
|
|
319
|
-
const
|
|
326
|
+
export const EmptyWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
327
|
+
target: z.literal('empty'),
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
const EditableTableWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
320
331
|
target: z.literal('table'),
|
|
321
332
|
table: TableViewConfigSchema.optional(),
|
|
322
333
|
query: QueryConfigSchema,
|
|
323
334
|
})
|
|
324
335
|
|
|
325
|
-
const
|
|
336
|
+
const TableWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
337
|
+
target: z.literal('table'),
|
|
338
|
+
table: TableViewConfigSchema.optional(),
|
|
339
|
+
query: QueryConfigSchema,
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
const EditableChartWidgetTargetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
343
|
+
target: z.literal('chart'),
|
|
344
|
+
chart: ChartConfigSchema,
|
|
345
|
+
query: z.union([QueryConfigSchema, FunnelQueryConfigSchema]),
|
|
346
|
+
}).superRefine((widget, ctx) => {
|
|
347
|
+
const isFunnelChart = widget.chart.type === 'funnel'
|
|
348
|
+
const isFunnelQuery = 'steps' in widget.query
|
|
349
|
+
|
|
350
|
+
if (isFunnelChart && !isFunnelQuery) {
|
|
351
|
+
ctx.addIssue({
|
|
352
|
+
code: 'custom',
|
|
353
|
+
path: ['query'],
|
|
354
|
+
message: 'Funnel charts must use steps query',
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
const ChartWidgetTargetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
326
360
|
target: z.literal('chart'),
|
|
327
361
|
chart: ChartConfigSchema,
|
|
328
362
|
query: z.union([QueryConfigSchema, FunnelQueryConfigSchema]),
|
|
@@ -332,37 +366,64 @@ const ChartWidgetTargetConfigSchema = WidgetBaseSchema.extend({
|
|
|
332
366
|
|
|
333
367
|
if (isFunnelChart && !isFunnelQuery) {
|
|
334
368
|
ctx.addIssue({
|
|
335
|
-
code:
|
|
369
|
+
code: 'custom',
|
|
336
370
|
path: ['query'],
|
|
337
371
|
message: 'Funnel charts must use steps query',
|
|
338
372
|
})
|
|
339
373
|
}
|
|
340
374
|
})
|
|
341
375
|
|
|
342
|
-
const
|
|
376
|
+
const EditableKpiCardWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
377
|
+
target: z.literal('kpi_card'),
|
|
378
|
+
card: KpiCardViewConfigSchema,
|
|
379
|
+
query: QueryConfigSchema,
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
const KpiCardWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
343
383
|
target: z.literal('kpi_card'),
|
|
344
384
|
card: KpiCardViewConfigSchema,
|
|
345
385
|
query: QueryConfigSchema,
|
|
346
386
|
})
|
|
347
387
|
|
|
348
|
-
const
|
|
388
|
+
const EditableGaugeCardWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
349
389
|
target: z.literal('gauge_card'),
|
|
350
390
|
card: GaugeCardViewConfigSchema,
|
|
351
391
|
query: QueryConfigSchema,
|
|
352
392
|
})
|
|
353
393
|
|
|
354
|
-
const
|
|
394
|
+
const GaugeCardWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
395
|
+
target: z.literal('gauge_card'),
|
|
396
|
+
card: GaugeCardViewConfigSchema,
|
|
397
|
+
query: QueryConfigSchema,
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
const EditablePivotTableWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
355
401
|
target: z.literal('pivot_table'),
|
|
356
402
|
pivot: PivotTableViewConfigSchema,
|
|
357
403
|
query: QueryConfigSchema,
|
|
358
404
|
})
|
|
359
405
|
|
|
406
|
+
const PivotTableWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
407
|
+
target: z.literal('pivot_table'),
|
|
408
|
+
pivot: PivotTableViewConfigSchema,
|
|
409
|
+
query: QueryConfigSchema,
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
export const EditableDashboardWidgetConfigSchema = z.discriminatedUnion('target', [
|
|
413
|
+
EditableEmptyWidgetConfigSchema,
|
|
414
|
+
EditableTableWidgetConfigSchema,
|
|
415
|
+
EditableChartWidgetTargetConfigSchema,
|
|
416
|
+
EditableKpiCardWidgetConfigSchema,
|
|
417
|
+
EditableGaugeCardWidgetConfigSchema,
|
|
418
|
+
EditablePivotTableWidgetConfigSchema,
|
|
419
|
+
])
|
|
420
|
+
|
|
360
421
|
export const WidgetConfigSchema = z.discriminatedUnion('target', [
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
422
|
+
EditableTableWidgetConfigSchema,
|
|
423
|
+
EditableChartWidgetTargetConfigSchema,
|
|
424
|
+
EditableKpiCardWidgetConfigSchema,
|
|
425
|
+
EditableGaugeCardWidgetConfigSchema,
|
|
426
|
+
EditablePivotTableWidgetConfigSchema,
|
|
366
427
|
])
|
|
367
428
|
|
|
368
429
|
export const StoredWidgetConfigSchema = z.discriminatedUnion('target', [
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Filters } from 'adminforth';
|
|
2
2
|
import type { IAdminForth } from 'adminforth';
|
|
3
|
-
import { normalizeDashboardConfig } from '../custom/model/dashboard.types.js';
|
|
4
3
|
import type { DashboardConfig, DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { getDashboardConfigUpdatedTopic } from '../custom/model/dashboardTopics.js';
|
|
5
|
+
import { DashboardConfigZodSchema } from '../schema/api.js';
|
|
7
6
|
|
|
8
7
|
export type DashboardRecord = {
|
|
9
8
|
id: string;
|
|
@@ -14,21 +13,9 @@ export type DashboardRecord = {
|
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
export function parseStoredDashboardConfig(config: unknown): DashboardConfig {
|
|
17
|
-
|
|
18
|
-
return normalizeDashboardConfig(JSON.parse(config));
|
|
19
|
-
}
|
|
16
|
+
const parsedConfig = typeof config === 'string' ? JSON.parse(config) : config;
|
|
20
17
|
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function buildDashboardResponse(dashboard: DashboardRecord) {
|
|
25
|
-
return {
|
|
26
|
-
id: dashboard.id,
|
|
27
|
-
slug: dashboard.slug,
|
|
28
|
-
label: dashboard.label,
|
|
29
|
-
revision: dashboard.revision,
|
|
30
|
-
config: parseStoredDashboardConfig(dashboard.config),
|
|
31
|
-
};
|
|
18
|
+
return DashboardConfigZodSchema.parse(parsedConfig) as DashboardConfig;
|
|
32
19
|
}
|
|
33
20
|
|
|
34
21
|
export type PersistedDashboardResponse = {
|
|
@@ -39,11 +26,7 @@ export type PersistedDashboardResponse = {
|
|
|
39
26
|
config: DashboardConfig;
|
|
40
27
|
};
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
return `${DASHBOARD_CONFIG_UPDATED_TOPIC_PREFIX}/${slug}`;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function normalizeDashboardOrder(config: DashboardConfig): DashboardConfig {
|
|
29
|
+
function normalizeDashboardOrder(config: DashboardConfig): DashboardConfig {
|
|
47
30
|
const widgetsByGroupId = new Map<string, DashboardWidgetConfig[]>();
|
|
48
31
|
|
|
49
32
|
for (const widget of config.widgets) {
|
|
@@ -93,7 +76,7 @@ export async function persistDashboardConfig(
|
|
|
93
76
|
revision: dashboard.revision + 1,
|
|
94
77
|
});
|
|
95
78
|
|
|
96
|
-
await adminforth.websocket.publish(
|
|
79
|
+
await adminforth.websocket.publish(getDashboardConfigUpdatedTopic(dashboard.slug), {
|
|
97
80
|
id: dashboard.id,
|
|
98
81
|
slug: dashboard.slug,
|
|
99
82
|
revision: dashboard.revision + 1,
|
|
@@ -115,7 +98,6 @@ export type DashboardConfigService = {
|
|
|
115
98
|
dashboard: DashboardRecord,
|
|
116
99
|
config: DashboardConfig,
|
|
117
100
|
) => Promise<PersistedDashboardResponse>;
|
|
118
|
-
buildDashboardResponse: typeof buildDashboardResponse;
|
|
119
101
|
};
|
|
120
102
|
|
|
121
103
|
export function createDashboardConfigService(
|
|
@@ -131,6 +113,5 @@ export function createDashboardConfigService(
|
|
|
131
113
|
dashboard,
|
|
132
114
|
config,
|
|
133
115
|
),
|
|
134
|
-
buildDashboardResponse,
|
|
135
116
|
};
|
|
136
117
|
}
|