@adminforth/dashboard 1.3.0 → 1.4.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 +103 -15
- package/custom/api/dashboardApi.ts +9 -8
- package/custom/model/dashboard.types.ts +63 -270
- package/custom/model/dashboardTopics.ts +5 -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 +110 -3
- 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 +24 -18
- 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 -7
- package/dist/custom/api/dashboardApi.js +5 -0
- package/dist/custom/api/dashboardApi.ts +9 -8
- package/dist/custom/model/dashboard.types.d.ts +40 -31
- package/dist/custom/model/dashboard.types.js +13 -152
- package/dist/custom/model/dashboard.types.ts +63 -270
- package/dist/custom/model/dashboardTopics.d.ts +2 -0
- package/dist/custom/model/dashboardTopics.js +8 -0
- package/dist/custom/model/dashboardTopics.ts +5 -0
- package/dist/custom/queries/useDashboardConfig.d.ts +116 -96
- package/dist/custom/queries/useWidgetData.d.ts +116 -96
- 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 +110 -3
- 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 +24 -18
- 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 +0 -23
- package/dist/custom/widgets/chart/chart.types.ts +0 -28
- package/dist/endpoint/dashboard.d.ts +6 -2
- package/dist/endpoint/dashboard.js +29 -5
- package/dist/endpoint/groups.d.ts +2 -21
- package/dist/endpoint/groups.js +18 -16
- package/dist/endpoint/widgets.d.ts +2 -4
- package/dist/endpoint/widgets.js +28 -74
- package/dist/index.js +1 -3
- package/dist/schema/api.d.ts +2172 -500
- package/dist/schema/api.js +21 -13
- package/dist/schema/widget.d.ts +1076 -263
- package/dist/schema/widget.js +108 -49
- package/dist/services/dashboardConfigService.d.ts +0 -10
- package/dist/services/dashboardConfigService.js +6 -21
- package/dist/services/widgetDataService.d.ts +2 -1
- package/dist/services/widgetDataService.js +266 -206
- package/endpoint/dashboard.ts +47 -7
- package/endpoint/groups.ts +25 -42
- package/endpoint/widgets.ts +41 -96
- package/index.ts +0 -3
- package/package.json +3 -3
- package/schema/api.ts +23 -13
- package/schema/widget.ts +119 -55
- package/services/dashboardConfigService.ts +6 -25
- package/services/widgetDataService.ts +350 -237
- 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,17 +148,18 @@ const QueryCalcItemSchema = z.object({
|
|
|
144
148
|
as: z.string(),
|
|
145
149
|
}).strict()
|
|
146
150
|
|
|
147
|
-
const FormattingConfigSchema = z.record(z.string(),
|
|
151
|
+
const FormattingConfigSchema = z.record(z.string(), JsonValueSchema)
|
|
152
|
+
const VariablesConfigSchema = z.record(z.string(), JsonValueSchema)
|
|
148
153
|
|
|
149
154
|
export const QueryConfigSchema = z.object({
|
|
150
155
|
resource: z.string(),
|
|
151
156
|
select: z.array(QuerySelectItemSchema).optional(),
|
|
152
157
|
filters: FilterExpressionSchema.optional(),
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
group_by: z.array(QueryGroupByItemSchema).optional(),
|
|
159
|
+
order_by: z.array(QueryOrderByItemSchema).optional(),
|
|
155
160
|
limit: z.number().int().positive().optional(),
|
|
156
161
|
offset: z.number().int().nonnegative().optional(),
|
|
157
|
-
|
|
162
|
+
time_series: TimeSeriesConfigSchema.optional(),
|
|
158
163
|
period: PeriodConfigSchema.optional(),
|
|
159
164
|
bucket: BucketConfigSchema.optional(),
|
|
160
165
|
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
@@ -170,29 +175,34 @@ const FunnelQueryStepSchema = z.object({
|
|
|
170
175
|
|
|
171
176
|
export const FunnelQueryConfigSchema = z.object({
|
|
172
177
|
steps: z.array(FunnelQueryStepSchema).min(1),
|
|
178
|
+
calcs: z.array(QueryCalcItemSchema).optional(),
|
|
173
179
|
}).strict()
|
|
174
180
|
|
|
175
|
-
const
|
|
176
|
-
id: z.string().optional(),
|
|
177
|
-
group_id: z.string().optional(),
|
|
181
|
+
const EditableWidgetBaseSchema = z.object({
|
|
178
182
|
label: z.string().optional(),
|
|
183
|
+
variables: VariablesConfigSchema.optional(),
|
|
179
184
|
size: DashboardWidgetSizeSchema.optional(),
|
|
180
185
|
width: z.number().positive('Width must be greater than 0').optional(),
|
|
181
186
|
height: z.number().positive('Height must be greater than 0').optional(),
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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(),
|
|
185
195
|
})
|
|
186
196
|
|
|
187
197
|
const TableViewConfigSchema = z.object({
|
|
188
198
|
columns: z.array(FieldRefSchema).optional(),
|
|
189
199
|
pagination: z.boolean().optional(),
|
|
190
|
-
|
|
200
|
+
page_size: z.number().int().positive().optional(),
|
|
191
201
|
}).strict()
|
|
192
202
|
|
|
193
203
|
const ChartBaseSchema = z.object({
|
|
194
204
|
title: z.string().optional(),
|
|
195
|
-
})
|
|
205
|
+
}).strict()
|
|
196
206
|
|
|
197
207
|
const ChartBucketSchema = z.object({
|
|
198
208
|
label: z.string().min(1, 'Bucket label is required'),
|
|
@@ -224,8 +234,8 @@ const BarChartSchema = ChartBaseSchema.extend({
|
|
|
224
234
|
const StackedBarChartSchema = ChartBaseSchema.extend({
|
|
225
235
|
type: z.literal('stacked_bar'),
|
|
226
236
|
x: ChartFieldRefSchema,
|
|
227
|
-
y: ChartFieldRefSchema,
|
|
228
|
-
series: ChartSeriesRefSchema,
|
|
237
|
+
y: z.union([ChartFieldRefSchema, z.array(ChartFieldRefSchema).min(1)]),
|
|
238
|
+
series: ChartSeriesRefSchema.optional(),
|
|
229
239
|
colors: z.array(z.string()).optional(),
|
|
230
240
|
})
|
|
231
241
|
|
|
@@ -272,8 +282,8 @@ const KpiCardViewConfigSchema = z.object({
|
|
|
272
282
|
text: z.string().optional(),
|
|
273
283
|
field: z.string().optional(),
|
|
274
284
|
}).strict().optional(),
|
|
275
|
-
comparison:
|
|
276
|
-
sparkline:
|
|
285
|
+
comparison: JsonValueSchema.optional(),
|
|
286
|
+
sparkline: JsonValueSchema.optional(),
|
|
277
287
|
}).strict()
|
|
278
288
|
|
|
279
289
|
const GaugeCardViewConfigSchema = z.object({
|
|
@@ -290,9 +300,9 @@ const GaugeCardViewConfigSchema = z.object({
|
|
|
290
300
|
label: z.string().optional(),
|
|
291
301
|
}).strict().optional(),
|
|
292
302
|
progress: z.object({
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
303
|
+
value_field: z.string(),
|
|
304
|
+
target_value: z.number().optional(),
|
|
305
|
+
target_field: z.string().optional(),
|
|
296
306
|
format: ValueFormatSchema,
|
|
297
307
|
}).strict().optional(),
|
|
298
308
|
color: z.string().optional(),
|
|
@@ -309,17 +319,27 @@ const PivotTableViewConfigSchema = z.object({
|
|
|
309
319
|
}).strict()).min(1),
|
|
310
320
|
}).strict()
|
|
311
321
|
|
|
312
|
-
|
|
322
|
+
const EditableEmptyWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
323
|
+
target: z.literal('empty'),
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
export const EmptyWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
313
327
|
target: z.literal('empty'),
|
|
314
328
|
})
|
|
315
329
|
|
|
316
|
-
const
|
|
330
|
+
const EditableTableWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
317
331
|
target: z.literal('table'),
|
|
318
332
|
table: TableViewConfigSchema.optional(),
|
|
319
333
|
query: QueryConfigSchema,
|
|
320
334
|
})
|
|
321
335
|
|
|
322
|
-
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({
|
|
323
343
|
target: z.literal('chart'),
|
|
324
344
|
chart: ChartConfigSchema,
|
|
325
345
|
query: z.union([QueryConfigSchema, FunnelQueryConfigSchema]),
|
|
@@ -327,39 +347,83 @@ const ChartWidgetTargetConfigSchema = WidgetBaseSchema.extend({
|
|
|
327
347
|
const isFunnelChart = widget.chart.type === 'funnel'
|
|
328
348
|
const isFunnelQuery = 'steps' in widget.query
|
|
329
349
|
|
|
330
|
-
if (isFunnelChart
|
|
350
|
+
if (isFunnelChart && !isFunnelQuery) {
|
|
331
351
|
ctx.addIssue({
|
|
332
|
-
code:
|
|
352
|
+
code: 'custom',
|
|
333
353
|
path: ['query'],
|
|
334
|
-
message: 'Funnel charts must use steps query
|
|
354
|
+
message: 'Funnel charts must use steps query',
|
|
335
355
|
})
|
|
336
356
|
}
|
|
337
357
|
})
|
|
338
358
|
|
|
339
|
-
const
|
|
359
|
+
const ChartWidgetTargetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
360
|
+
target: z.literal('chart'),
|
|
361
|
+
chart: ChartConfigSchema,
|
|
362
|
+
query: z.union([QueryConfigSchema, FunnelQueryConfigSchema]),
|
|
363
|
+
}).superRefine((widget, ctx) => {
|
|
364
|
+
const isFunnelChart = widget.chart.type === 'funnel'
|
|
365
|
+
const isFunnelQuery = 'steps' in widget.query
|
|
366
|
+
|
|
367
|
+
if (isFunnelChart && !isFunnelQuery) {
|
|
368
|
+
ctx.addIssue({
|
|
369
|
+
code: 'custom',
|
|
370
|
+
path: ['query'],
|
|
371
|
+
message: 'Funnel charts must use steps query',
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
const EditableKpiCardWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
377
|
+
target: z.literal('kpi_card'),
|
|
378
|
+
card: KpiCardViewConfigSchema,
|
|
379
|
+
query: QueryConfigSchema,
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
const KpiCardWidgetConfigSchema = StoredWidgetBaseSchema.extend({
|
|
340
383
|
target: z.literal('kpi_card'),
|
|
341
384
|
card: KpiCardViewConfigSchema,
|
|
342
385
|
query: QueryConfigSchema,
|
|
343
386
|
})
|
|
344
387
|
|
|
345
|
-
const
|
|
388
|
+
const EditableGaugeCardWidgetConfigSchema = EditableWidgetBaseSchema.extend({
|
|
346
389
|
target: z.literal('gauge_card'),
|
|
347
390
|
card: GaugeCardViewConfigSchema,
|
|
348
391
|
query: QueryConfigSchema,
|
|
349
392
|
})
|
|
350
393
|
|
|
351
|
-
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({
|
|
352
401
|
target: z.literal('pivot_table'),
|
|
353
402
|
pivot: PivotTableViewConfigSchema,
|
|
354
403
|
query: QueryConfigSchema,
|
|
355
404
|
})
|
|
356
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
|
+
|
|
357
421
|
export const WidgetConfigSchema = z.discriminatedUnion('target', [
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
422
|
+
EditableTableWidgetConfigSchema,
|
|
423
|
+
EditableChartWidgetTargetConfigSchema,
|
|
424
|
+
EditableKpiCardWidgetConfigSchema,
|
|
425
|
+
EditableGaugeCardWidgetConfigSchema,
|
|
426
|
+
EditablePivotTableWidgetConfigSchema,
|
|
363
427
|
])
|
|
364
428
|
|
|
365
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
|
}
|