@adminforth/dashboard 1.4.2 → 1.6.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.
Files changed (60) hide show
  1. package/custom/api/dashboardApi.ts +137 -5
  2. package/custom/model/dashboard.types.ts +32 -22
  3. package/custom/runtime/DashboardRuntime.vue +2 -3
  4. package/custom/skills/adminforth-dashboard/SKILL.md +165 -179
  5. package/custom/widgets/KpiCardWidget.vue +172 -9
  6. package/custom/widgets/chart/ChartWidget.vue +5 -5
  7. package/custom/widgets/registry.ts +4 -4
  8. package/dist/custom/api/dashboardApi.d.ts +46 -2
  9. package/dist/custom/api/dashboardApi.js +90 -5
  10. package/dist/custom/api/dashboardApi.ts +137 -5
  11. package/dist/custom/model/dashboard.types.d.ts +30 -14
  12. package/dist/custom/model/dashboard.types.js +2 -2
  13. package/dist/custom/model/dashboard.types.ts +32 -22
  14. package/dist/custom/queries/useDashboardConfig.d.ts +106 -104
  15. package/dist/custom/queries/useWidgetData.d.ts +106 -104
  16. package/dist/custom/runtime/DashboardRuntime.vue +2 -3
  17. package/dist/custom/skills/adminforth-dashboard/SKILL.md +165 -179
  18. package/dist/custom/widgets/KpiCardWidget.vue +172 -9
  19. package/dist/custom/widgets/chart/ChartWidget.vue +5 -5
  20. package/dist/custom/widgets/registry.js +4 -4
  21. package/dist/custom/widgets/registry.ts +4 -4
  22. package/dist/endpoint/dashboard.d.ts +2 -4
  23. package/dist/endpoint/dashboard.js +1 -21
  24. package/dist/endpoint/groups.d.ts +1 -0
  25. package/dist/endpoint/groups.js +61 -48
  26. package/dist/endpoint/widgets.d.ts +1 -0
  27. package/dist/endpoint/widgets.js +167 -64
  28. package/dist/schema/api.d.ts +11710 -2785
  29. package/dist/schema/api.js +118 -26
  30. package/dist/schema/widget.d.ts +425 -1980
  31. package/dist/schema/widget.js +13 -374
  32. package/dist/schema/widgets/charts.d.ts +1689 -0
  33. package/dist/schema/widgets/charts.js +92 -0
  34. package/dist/schema/widgets/common.d.ts +275 -0
  35. package/dist/schema/widgets/common.js +171 -0
  36. package/dist/schema/widgets/gauge-card.d.ts +172 -0
  37. package/dist/schema/widgets/gauge-card.js +28 -0
  38. package/dist/schema/widgets/kpi-card.d.ts +212 -0
  39. package/dist/schema/widgets/kpi-card.js +43 -0
  40. package/dist/schema/widgets/pivot-table.d.ts +196 -0
  41. package/dist/schema/widgets/pivot-table.js +17 -0
  42. package/dist/schema/widgets/table.d.ts +130 -0
  43. package/dist/schema/widgets/table.js +12 -0
  44. package/dist/services/dashboardConfigService.d.ts +4 -0
  45. package/dist/services/dashboardConfigService.js +46 -0
  46. package/dist/services/widgetDataService.js +96 -2
  47. package/endpoint/dashboard.ts +2 -33
  48. package/endpoint/groups.ts +91 -72
  49. package/endpoint/widgets.ts +260 -87
  50. package/package.json +1 -1
  51. package/schema/api.ts +148 -28
  52. package/schema/widget.ts +43 -425
  53. package/schema/widgets/charts.ts +113 -0
  54. package/schema/widgets/common.ts +194 -0
  55. package/schema/widgets/gauge-card.ts +34 -0
  56. package/schema/widgets/kpi-card.ts +49 -0
  57. package/schema/widgets/pivot-table.ts +24 -0
  58. package/schema/widgets/table.ts +18 -0
  59. package/services/dashboardConfigService.ts +73 -0
  60. package/services/widgetDataService.ts +129 -3
@@ -1,12 +1,26 @@
1
1
  import type { AdminUser, IHttpServer } from 'adminforth';
2
2
  import { randomUUID } from 'crypto';
3
3
  import type {
4
+ ChartDashboardWidgetConfig,
4
5
  DashboardConfig,
5
6
  DashboardVariables,
6
7
  DashboardWidgetConfig,
7
- EditableDashboardWidgetConfig,
8
+ GaugeCardWidgetConfig,
9
+ KpiCardWidgetConfig,
10
+ PivotTableWidgetConfig,
11
+ TableWidgetConfig,
8
12
  } from '../custom/model/dashboard.types.js';
9
13
  import {
14
+ ConfigureBarChartWidgetRequestSchema,
15
+ ConfigureFunnelChartWidgetRequestSchema,
16
+ ConfigureGaugeCardWidgetRequestSchema,
17
+ ConfigureHistogramChartWidgetRequestSchema,
18
+ ConfigureKpiCardWidgetRequestSchema,
19
+ ConfigureLineChartWidgetRequestSchema,
20
+ ConfigurePieChartWidgetRequestSchema,
21
+ ConfigurePivotTableWidgetRequestSchema,
22
+ ConfigureStackedBarChartWidgetRequestSchema,
23
+ ConfigureTableWidgetRequestSchema,
10
24
  DashboardApiResponseSchema,
11
25
  DashboardWidgetDataResponseSchema,
12
26
  GroupIdRequestSchema,
@@ -17,6 +31,21 @@ import {
17
31
  } from '../schema/api.js';
18
32
  import type { DashboardRecord, PersistedDashboardResponse } from '../services/dashboardConfigService.js';
19
33
 
34
+ type ConfigurableWidgetConfig =
35
+ | Omit<TableWidgetConfig, 'id' | 'group_id' | 'order'>
36
+ | Omit<KpiCardWidgetConfig, 'id' | 'group_id' | 'order'>
37
+ | Omit<GaugeCardWidgetConfig, 'id' | 'group_id' | 'order'>
38
+ | Omit<ChartDashboardWidgetConfig, 'id' | 'group_id' | 'order'>
39
+ | Omit<PivotTableWidgetConfig, 'id' | 'group_id' | 'order'>;
40
+
41
+ type ConfigureWidgetRequest = {
42
+ slug: string;
43
+ widgetId: string;
44
+ config: ConfigurableWidgetConfig;
45
+ };
46
+
47
+ type EndpointRequestSchema = Parameters<IHttpServer['endpoint']>[0]['request_schema'];
48
+
20
49
  type WidgetEndpointsContext = {
21
50
  canEditDashboard: (adminUser: AdminUser) => boolean;
22
51
  getDashboardRecord: (slug: string) => Promise<DashboardRecord | null>;
@@ -25,6 +54,10 @@ type WidgetEndpointsContext = {
25
54
  dashboard: DashboardRecord,
26
55
  config: DashboardConfig,
27
56
  ) => Promise<PersistedDashboardResponse>;
57
+ updateDashboardConfig: (
58
+ slug: string,
59
+ mutateConfig: (config: DashboardConfig, dashboard: DashboardRecord) => DashboardConfig | null | Promise<DashboardConfig | null>,
60
+ ) => Promise<PersistedDashboardResponse | null>;
28
61
  getWidgetData: (
29
62
  widget: DashboardWidgetConfig,
30
63
  options?: {
@@ -34,6 +67,86 @@ type WidgetEndpointsContext = {
34
67
  ) => Promise<unknown>;
35
68
  };
36
69
 
70
+ async function replaceWidgetConfig(
71
+ ctx: WidgetEndpointsContext,
72
+ slug: string,
73
+ widgetId: string,
74
+ widgetConfig: ConfigurableWidgetConfig,
75
+ ) {
76
+ let mutationError: string | null = null;
77
+ const updatedDashboard = await ctx.updateDashboardConfig(slug, (config) => {
78
+ const widget = config.widgets.find((item) => item.id === widgetId);
79
+
80
+ if (!widget) {
81
+ mutationError = 'Dashboard widget not found';
82
+ return null;
83
+ }
84
+
85
+ const nextWidget: DashboardWidgetConfig = {
86
+ ...widgetConfig,
87
+ id: widget.id,
88
+ group_id: widget.group_id,
89
+ order: widget.order,
90
+ } as DashboardWidgetConfig;
91
+
92
+ return {
93
+ ...config,
94
+ widgets: config.widgets.map((item) => item.id === widgetId
95
+ ? nextWidget
96
+ : item),
97
+ };
98
+ });
99
+
100
+ return {
101
+ updatedDashboard,
102
+ mutationError,
103
+ };
104
+ }
105
+
106
+ function registerConfigureWidgetEndpoint(
107
+ server: IHttpServer,
108
+ ctx: WidgetEndpointsContext,
109
+ options: {
110
+ path: string;
111
+ description: string;
112
+ requestSchema: EndpointRequestSchema;
113
+ },
114
+ ) {
115
+ server.endpoint({
116
+ method: 'POST',
117
+ path: options.path,
118
+ description: options.description,
119
+ request_schema: options.requestSchema,
120
+ response_schema: DashboardApiResponseSchema,
121
+ handler: async ({ body, adminUser, response }) => {
122
+ if (!ctx.canEditDashboard(adminUser)) {
123
+ response.setStatus(403);
124
+ return { error: 'Dashboard edit is not allowed' };
125
+ }
126
+
127
+ const request = body as ConfigureWidgetRequest;
128
+ const { updatedDashboard, mutationError } = await replaceWidgetConfig(
129
+ ctx,
130
+ request.slug,
131
+ request.widgetId,
132
+ request.config,
133
+ );
134
+
135
+ if (!updatedDashboard) {
136
+ response.setStatus(404);
137
+ return { error: 'Dashboard not found' };
138
+ }
139
+
140
+ if (mutationError) {
141
+ response.setStatus(404);
142
+ return { error: mutationError };
143
+ }
144
+
145
+ return updatedDashboard;
146
+ },
147
+ });
148
+ }
149
+
37
150
  export function registerWidgetEndpoints(
38
151
  server: IHttpServer,
39
152
  ctx: WidgetEndpointsContext,
@@ -50,35 +163,42 @@ export function registerWidgetEndpoints(
50
163
  return { error: 'Dashboard edit is not allowed' };
51
164
  }
52
165
 
53
- const dashboard = await ctx.getDashboardRecord(body.slug);
166
+ let mutationError: string | null = null;
167
+ const updatedDashboard = await ctx.updateDashboardConfig(body.slug, (config) => {
168
+ const group = config.groups.find((item) => item.id === body.groupId);
169
+
170
+ if (!group) {
171
+ mutationError = 'Dashboard group not found';
172
+ return null;
173
+ }
174
+
175
+ const nextOrder = config.widgets.filter((item) => item.group_id === body.groupId).length + 1;
176
+ const widget: DashboardWidgetConfig = {
177
+ id: `widget_${randomUUID()}`,
178
+ group_id: body.groupId,
179
+ label: 'New widget',
180
+ size: 'small',
181
+ order: nextOrder,
182
+ target: 'empty',
183
+ };
54
184
 
55
- if (!dashboard) {
185
+ return {
186
+ ...config,
187
+ widgets: [...config.widgets, widget],
188
+ };
189
+ });
190
+
191
+ if (!updatedDashboard) {
56
192
  response.setStatus(404);
57
193
  return { error: 'Dashboard not found' };
58
194
  }
59
195
 
60
- const config = ctx.parseStoredDashboardConfig(dashboard.config);
61
- const group = config.groups.find((item) => item.id === body.groupId);
62
-
63
- if (!group) {
196
+ if (mutationError) {
64
197
  response.setStatus(404);
65
- return { error: 'Dashboard group not found' };
198
+ return { error: mutationError };
66
199
  }
67
200
 
68
- const nextOrder = config.widgets.filter((item) => item.group_id === body.groupId).length + 1;
69
- const widget: DashboardWidgetConfig = {
70
- id: `widget_${randomUUID()}`,
71
- group_id: body.groupId,
72
- label: 'New widget',
73
- size: 'small',
74
- order: nextOrder,
75
- target: 'empty',
76
- };
77
-
78
- return ctx.persistDashboardConfig(dashboard, {
79
- ...config,
80
- widgets: [...config.widgets, widget],
81
- });
201
+ return updatedDashboard;
82
202
  },
83
203
  });
84
204
 
@@ -94,49 +214,50 @@ export function registerWidgetEndpoints(
94
214
  return { error: 'Dashboard edit is not allowed' };
95
215
  }
96
216
 
97
- const dashboard = await ctx.getDashboardRecord(body.slug);
217
+ let mutationError: string | null = null;
218
+ const updatedDashboard = await ctx.updateDashboardConfig(body.slug, (config) => {
219
+ const widget = config.widgets.find((item) => item.id === body.widgetId);
98
220
 
99
- if (!dashboard) {
100
- response.setStatus(404);
101
- return { error: 'Dashboard not found' };
102
- }
221
+ if (!widget) {
222
+ mutationError = 'Dashboard widget not found';
223
+ return null;
224
+ }
103
225
 
104
- const config = ctx.parseStoredDashboardConfig(dashboard.config);
105
- const widget = config.widgets.find((item) => item.id === body.widgetId);
226
+ const sortedWidgets = config.widgets
227
+ .filter((item) => item.group_id === widget.group_id)
228
+ .sort((a, b) => a.order - b.order);
229
+ const currentIndex = sortedWidgets.findIndex((item) => item.id === body.widgetId);
230
+ const targetIndex = body.direction === 'up' ? currentIndex - 1 : currentIndex + 1;
106
231
 
107
- if (!widget) {
108
- response.setStatus(404);
109
- return { error: 'Dashboard widget not found' };
110
- }
232
+ if (targetIndex < 0 || targetIndex >= sortedWidgets.length) {
233
+ return null;
234
+ }
111
235
 
112
- const sortedWidgets = config.widgets
113
- .filter((item) => item.group_id === widget.group_id)
114
- .sort((a, b) => a.order - b.order);
115
- const currentIndex = sortedWidgets.findIndex((item) => item.id === body.widgetId);
116
- const targetIndex = body.direction === 'up' ? currentIndex - 1 : currentIndex + 1;
236
+ const reorderedWidgets = [...sortedWidgets];
237
+ const [movedWidget] = reorderedWidgets.splice(currentIndex, 1);
238
+ reorderedWidgets.splice(targetIndex, 0, movedWidget);
239
+ const reorderedWidgetIds = new Map(reorderedWidgets.map((item, index) => [item.id, index + 1]));
117
240
 
118
- if (targetIndex < 0 || targetIndex >= sortedWidgets.length) {
119
241
  return {
120
- id: dashboard.id,
121
- slug: dashboard.slug,
122
- label: dashboard.label,
123
- revision: dashboard.revision,
124
- config: ctx.parseStoredDashboardConfig(dashboard.config),
242
+ ...config,
243
+ widgets: config.widgets.map((item) => ({
244
+ ...item,
245
+ order: reorderedWidgetIds.get(item.id) ?? item.order,
246
+ })),
125
247
  };
248
+ });
249
+
250
+ if (!updatedDashboard) {
251
+ response.setStatus(404);
252
+ return { error: 'Dashboard not found' };
126
253
  }
127
254
 
128
- const reorderedWidgets = [...sortedWidgets];
129
- const [movedWidget] = reorderedWidgets.splice(currentIndex, 1);
130
- reorderedWidgets.splice(targetIndex, 0, movedWidget);
131
- const reorderedWidgetIds = new Map(reorderedWidgets.map((item, index) => [item.id, index + 1]));
255
+ if (mutationError) {
256
+ response.setStatus(404);
257
+ return { error: mutationError };
258
+ }
132
259
 
133
- return ctx.persistDashboardConfig(dashboard, {
134
- ...config,
135
- widgets: config.widgets.map((item) => ({
136
- ...item,
137
- order: reorderedWidgetIds.get(item.id) ?? item.order,
138
- })),
139
- });
260
+ return updatedDashboard;
140
261
  },
141
262
  });
142
263
 
@@ -152,28 +273,36 @@ export function registerWidgetEndpoints(
152
273
  return { error: 'Dashboard edit is not allowed' };
153
274
  }
154
275
 
155
- const dashboard = await ctx.getDashboardRecord(body.slug);
276
+ let mutationError: string | null = null;
277
+ const updatedDashboard = await ctx.updateDashboardConfig(body.slug, (config) => {
278
+ const nextWidgets = config.widgets.filter((item) => item.id !== body.widgetId);
156
279
 
157
- if (!dashboard) {
280
+ if (nextWidgets.length === config.widgets.length) {
281
+ mutationError = 'Dashboard widget not found';
282
+ return null;
283
+ }
284
+
285
+ return {
286
+ ...config,
287
+ widgets: nextWidgets,
288
+ };
289
+ });
290
+
291
+ if (!updatedDashboard) {
158
292
  response.setStatus(404);
159
293
  return { error: 'Dashboard not found' };
160
294
  }
161
295
 
162
- const config = ctx.parseStoredDashboardConfig(dashboard.config);
163
- const nextWidgets = config.widgets.filter((item) => item.id !== body.widgetId);
164
-
165
- if (nextWidgets.length === config.widgets.length) {
296
+ if (mutationError) {
166
297
  response.setStatus(404);
167
- return { error: 'Dashboard widget not found' };
298
+ return { error: mutationError };
168
299
  }
169
300
 
170
- return ctx.persistDashboardConfig(dashboard, {
171
- ...config,
172
- widgets: nextWidgets,
173
- });
301
+ return updatedDashboard;
174
302
  },
175
303
  });
176
304
 
305
+
177
306
  server.endpoint({
178
307
  method: 'POST',
179
308
  path: '/dashboard/set_widget_config',
@@ -186,37 +315,81 @@ export function registerWidgetEndpoints(
186
315
  return { error: 'Dashboard edit is not allowed' };
187
316
  }
188
317
 
189
- const dashboard = await ctx.getDashboardRecord(body.slug);
318
+ const request = body as ConfigureWidgetRequest;
319
+ const { updatedDashboard, mutationError } = await replaceWidgetConfig(ctx, request.slug, request.widgetId, request.config);
190
320
 
191
- if (!dashboard) {
321
+ if (!updatedDashboard) {
192
322
  response.setStatus(404);
193
323
  return { error: 'Dashboard not found' };
194
324
  }
195
325
 
196
- const config = ctx.parseStoredDashboardConfig(dashboard.config);
197
- const widget = config.widgets.find((item) => item.id === body.widgetId);
198
-
199
- if (!widget) {
326
+ if (mutationError) {
200
327
  response.setStatus(404);
201
- return { error: 'Dashboard widget not found' };
328
+ return { error: mutationError };
202
329
  }
203
330
 
204
- const typedWidgetConfig = body.config as EditableDashboardWidgetConfig;
331
+ return updatedDashboard;
332
+ },
333
+ });
205
334
 
206
- const nextWidget: DashboardWidgetConfig = {
207
- ...typedWidgetConfig,
208
- id: widget.id,
209
- group_id: widget.group_id,
210
- order: widget.order,
211
- };
335
+ registerConfigureWidgetEndpoint(server, ctx, {
336
+ path: '/dashboard/configure_table_widget',
337
+ description: 'Configures an existing dashboard widget as a table. Superadmin only.',
338
+ requestSchema: ConfigureTableWidgetRequestSchema,
339
+ });
212
340
 
213
- return ctx.persistDashboardConfig(dashboard, {
214
- ...config,
215
- widgets: config.widgets.map((item) => item.id === body.widgetId
216
- ? nextWidget
217
- : item),
218
- });
219
- },
341
+ registerConfigureWidgetEndpoint(server, ctx, {
342
+ path: '/dashboard/configure_kpi_card_widget',
343
+ description: 'Configures an existing dashboard widget as a KPI card. Superadmin only.',
344
+ requestSchema: ConfigureKpiCardWidgetRequestSchema,
345
+ });
346
+
347
+ registerConfigureWidgetEndpoint(server, ctx, {
348
+ path: '/dashboard/configure_gauge_card_widget',
349
+ description: 'Configures an existing dashboard widget as a gauge card. Superadmin only.',
350
+ requestSchema: ConfigureGaugeCardWidgetRequestSchema,
351
+ });
352
+
353
+ registerConfigureWidgetEndpoint(server, ctx, {
354
+ path: '/dashboard/configure_pivot_table_widget',
355
+ description: 'Configures an existing dashboard widget as a pivot table. Superadmin only.',
356
+ requestSchema: ConfigurePivotTableWidgetRequestSchema,
357
+ });
358
+
359
+ registerConfigureWidgetEndpoint(server, ctx, {
360
+ path: '/dashboard/configure_line_chart_widget',
361
+ description: 'Configures an existing dashboard widget as a line chart. Superadmin only.',
362
+ requestSchema: ConfigureLineChartWidgetRequestSchema,
363
+ });
364
+
365
+ registerConfigureWidgetEndpoint(server, ctx, {
366
+ path: '/dashboard/configure_bar_chart_widget',
367
+ description: 'Configures an existing dashboard widget as a bar chart. Superadmin only.',
368
+ requestSchema: ConfigureBarChartWidgetRequestSchema,
369
+ });
370
+
371
+ registerConfigureWidgetEndpoint(server, ctx, {
372
+ path: '/dashboard/configure_stacked_bar_chart_widget',
373
+ description: 'Configures an existing dashboard widget as a stacked bar chart. Superadmin only.',
374
+ requestSchema: ConfigureStackedBarChartWidgetRequestSchema,
375
+ });
376
+
377
+ registerConfigureWidgetEndpoint(server, ctx, {
378
+ path: '/dashboard/configure_pie_chart_widget',
379
+ description: 'Configures an existing dashboard widget as a pie chart. Superadmin only.',
380
+ requestSchema: ConfigurePieChartWidgetRequestSchema,
381
+ });
382
+
383
+ registerConfigureWidgetEndpoint(server, ctx, {
384
+ path: '/dashboard/configure_histogram_chart_widget',
385
+ description: 'Configures an existing dashboard widget as a histogram chart. Superadmin only.',
386
+ requestSchema: ConfigureHistogramChartWidgetRequestSchema,
387
+ });
388
+
389
+ registerConfigureWidgetEndpoint(server, ctx, {
390
+ path: '/dashboard/configure_funnel_chart_widget',
391
+ description: 'Configures an existing dashboard widget as a funnel chart. Superadmin only.',
392
+ requestSchema: ConfigureFunnelChartWidgetRequestSchema,
220
393
  });
221
394
 
222
395
  server.endpoint({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/dashboard",
3
- "version": "1.4.2",
3
+ "version": "1.6.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
package/schema/api.ts CHANGED
@@ -1,9 +1,20 @@
1
1
  import { toJSONSchema, z } from 'zod'
2
- import { EditableDashboardWidgetConfigSchema, StoredWidgetConfigSchema } from './widget.js'
3
-
4
- function toAdminForthJsonSchema(schema: z.ZodType) {
5
- return toJSONSchema(schema, { target: 'draft-7' })
6
- }
2
+ import {
3
+ BarChartSchema,
4
+ FunnelChartSchema,
5
+ FunnelQueryConfigSchema,
6
+ GaugeCardViewConfigSchema,
7
+ HistogramChartSchema,
8
+ KpiCardViewConfigSchema,
9
+ LineChartSchema,
10
+ PieChartSchema,
11
+ PivotTableViewConfigSchema,
12
+ QueryConfigSchema,
13
+ StackedBarChartSchema,
14
+ TableViewConfigSchema,
15
+ WidgetEditableBaseSchema,
16
+ WidgetConfigSchema,
17
+ } from './widget.js'
7
18
 
8
19
  export const DashboardErrorResponseZodSchema = z.object({
9
20
  error: z.string(),
@@ -22,7 +33,7 @@ export const DashboardGroupZodSchema = z.object({
22
33
  export const DashboardConfigZodSchema = z.object({
23
34
  version: z.number(),
24
35
  groups: z.array(DashboardGroupZodSchema),
25
- widgets: z.array(StoredWidgetConfigSchema),
36
+ widgets: z.array(WidgetConfigSchema),
26
37
  }).strict()
27
38
 
28
39
  export const DashboardResponseZodSchema = z.object({
@@ -40,7 +51,7 @@ export const DashboardApiResponseZodSchema = z.union([
40
51
 
41
52
  export const DashboardWidgetDataResponseZodSchema = z.union([
42
53
  z.object({
43
- widget: StoredWidgetConfigSchema,
54
+ widget: WidgetConfigSchema,
44
55
  data: z.unknown(),
45
56
  }),
46
57
  DashboardErrorResponseZodSchema,
@@ -50,11 +61,6 @@ export const SlugRequestZodSchema = z.object({
50
61
  slug: z.string(),
51
62
  }).strict()
52
63
 
53
- export const SetDashboardConfigRequestZodSchema = z.object({
54
- slug: z.string(),
55
- config: DashboardConfigZodSchema,
56
- }).strict()
57
-
58
64
  export const GroupIdRequestZodSchema = z.object({
59
65
  slug: z.string(),
60
66
  groupId: z.string(),
@@ -96,24 +102,138 @@ export const MoveWidgetRequestZodSchema = z.object({
96
102
  direction: z.enum(['up', 'down']),
97
103
  }).strict()
98
104
 
105
+ const ConfigurableTableWidgetConfigSchema = WidgetEditableBaseSchema.extend({
106
+ target: z.literal('table'),
107
+ table: TableViewConfigSchema.optional(),
108
+ query: QueryConfigSchema,
109
+ })
110
+
111
+ const ConfigurableKpiCardWidgetConfigSchema = WidgetEditableBaseSchema.extend({
112
+ target: z.literal('kpi_card'),
113
+ card: KpiCardViewConfigSchema,
114
+ query: QueryConfigSchema,
115
+ })
116
+
117
+ const ConfigurableGaugeCardWidgetConfigSchema = WidgetEditableBaseSchema.extend({
118
+ target: z.literal('gauge_card'),
119
+ card: GaugeCardViewConfigSchema,
120
+ query: QueryConfigSchema,
121
+ })
122
+
123
+ const ConfigurableLineChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
124
+ target: z.literal('chart'),
125
+ chart: LineChartSchema,
126
+ query: QueryConfigSchema,
127
+ })
128
+
129
+ const ConfigurableBarChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
130
+ target: z.literal('chart'),
131
+ chart: BarChartSchema,
132
+ query: QueryConfigSchema,
133
+ })
134
+
135
+ const ConfigurableStackedBarChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
136
+ target: z.literal('chart'),
137
+ chart: StackedBarChartSchema,
138
+ query: QueryConfigSchema,
139
+ })
140
+
141
+ const ConfigurablePieChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
142
+ target: z.literal('chart'),
143
+ chart: PieChartSchema,
144
+ query: QueryConfigSchema,
145
+ })
146
+
147
+ const ConfigurableHistogramChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
148
+ target: z.literal('chart'),
149
+ chart: HistogramChartSchema,
150
+ query: QueryConfigSchema,
151
+ })
152
+
153
+ const ConfigurableFunnelChartWidgetConfigSchema = WidgetEditableBaseSchema.extend({
154
+ target: z.literal('chart'),
155
+ chart: FunnelChartSchema,
156
+ query: FunnelQueryConfigSchema,
157
+ })
158
+
159
+ const ConfigurablePivotTableWidgetConfigSchema = WidgetEditableBaseSchema.extend({
160
+ target: z.literal('pivot_table'),
161
+ pivot: PivotTableViewConfigSchema,
162
+ query: QueryConfigSchema,
163
+ })
164
+
165
+ const ConfigurableChartWidgetConfigSchema = z.union([
166
+ ConfigurableLineChartWidgetConfigSchema,
167
+ ConfigurableBarChartWidgetConfigSchema,
168
+ ConfigurableStackedBarChartWidgetConfigSchema,
169
+ ConfigurablePieChartWidgetConfigSchema,
170
+ ConfigurableHistogramChartWidgetConfigSchema,
171
+ ConfigurableFunnelChartWidgetConfigSchema,
172
+ ])
173
+
174
+ export const ConfigurableWidgetConfigSchema = z.union([
175
+ ConfigurableTableWidgetConfigSchema,
176
+ ConfigurableKpiCardWidgetConfigSchema,
177
+ ConfigurableGaugeCardWidgetConfigSchema,
178
+ ConfigurableChartWidgetConfigSchema,
179
+ ConfigurablePivotTableWidgetConfigSchema,
180
+ ])
181
+
99
182
  export const SetWidgetConfigRequestZodSchema = z.object({
100
183
  slug: z.string(),
101
184
  widgetId: z.string(),
102
- config: EditableDashboardWidgetConfigSchema,
185
+ config: ConfigurableWidgetConfigSchema,
103
186
  }).strict()
104
187
 
105
- export const DashboardErrorResponseSchema = toAdminForthJsonSchema(DashboardErrorResponseZodSchema)
106
- export const DashboardGroupSchema = toAdminForthJsonSchema(DashboardGroupZodSchema)
107
- export const DashboardConfigSchema = toAdminForthJsonSchema(DashboardConfigZodSchema)
108
- export const DashboardResponseSchema = toAdminForthJsonSchema(DashboardResponseZodSchema)
109
- export const DashboardApiResponseSchema = toAdminForthJsonSchema(DashboardApiResponseZodSchema)
110
- export const DashboardWidgetDataResponseSchema = toAdminForthJsonSchema(DashboardWidgetDataResponseZodSchema)
111
- export const SlugRequestSchema = toAdminForthJsonSchema(SlugRequestZodSchema)
112
- export const SetDashboardConfigRequestSchema = toAdminForthJsonSchema(SetDashboardConfigRequestZodSchema)
113
- export const GroupIdRequestSchema = toAdminForthJsonSchema(GroupIdRequestZodSchema)
114
- export const MoveGroupRequestSchema = toAdminForthJsonSchema(MoveGroupRequestZodSchema)
115
- export const SetGroupConfigRequestSchema = toAdminForthJsonSchema(SetGroupConfigRequestZodSchema)
116
- export const WidgetIdRequestSchema = toAdminForthJsonSchema(WidgetIdRequestZodSchema)
117
- export const WidgetDataRequestSchema = toAdminForthJsonSchema(WidgetDataRequestZodSchema)
118
- export const MoveWidgetRequestSchema = toAdminForthJsonSchema(MoveWidgetRequestZodSchema)
119
- export const SetWidgetConfigRequestSchema = toAdminForthJsonSchema(SetWidgetConfigRequestZodSchema)
188
+ function configureWidgetRequestSchema<T extends z.ZodTypeAny>(configSchema: T) {
189
+ return z.object({
190
+ slug: z.string(),
191
+ widgetId: z.string(),
192
+ config: configSchema,
193
+ }).strict()
194
+ }
195
+
196
+ export const ConfigureTableWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableTableWidgetConfigSchema)
197
+ export const ConfigureKpiCardWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableKpiCardWidgetConfigSchema)
198
+ export const ConfigureGaugeCardWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableGaugeCardWidgetConfigSchema)
199
+ export const ConfigureLineChartWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableLineChartWidgetConfigSchema)
200
+ export const ConfigureBarChartWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableBarChartWidgetConfigSchema)
201
+ export const ConfigureStackedBarChartWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableStackedBarChartWidgetConfigSchema)
202
+ export const ConfigurePieChartWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurablePieChartWidgetConfigSchema)
203
+ export const ConfigureHistogramChartWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableHistogramChartWidgetConfigSchema)
204
+ export const ConfigureFunnelChartWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurableFunnelChartWidgetConfigSchema)
205
+ export const ConfigurePivotTableWidgetRequestZodSchema = configureWidgetRequestSchema(ConfigurablePivotTableWidgetConfigSchema)
206
+
207
+ export const DashboardMutationResponseZodSchema = z.union([
208
+ z.object({
209
+ ok: z.literal(true),
210
+ slug: z.string(),
211
+ widgetId: z.string().optional(),
212
+ groupId: z.string().optional(),
213
+ target: z.string().optional(),
214
+ revision: z.number().optional(),
215
+ }).strict(),
216
+ DashboardErrorResponseZodSchema,
217
+ ])
218
+
219
+ export const DashboardApiResponseSchema = toJSONSchema(DashboardApiResponseZodSchema, { target: 'draft-07' })
220
+ export const DashboardWidgetDataResponseSchema = toJSONSchema(DashboardWidgetDataResponseZodSchema, { target: 'draft-07' })
221
+ export const SlugRequestSchema = toJSONSchema(SlugRequestZodSchema, { target: 'draft-07' })
222
+ export const GroupIdRequestSchema = toJSONSchema(GroupIdRequestZodSchema, { target: 'draft-07' })
223
+ export const MoveGroupRequestSchema = toJSONSchema(MoveGroupRequestZodSchema, { target: 'draft-07' })
224
+ export const SetGroupConfigRequestSchema = toJSONSchema(SetGroupConfigRequestZodSchema, { target: 'draft-07' })
225
+ export const WidgetIdRequestSchema = toJSONSchema(WidgetIdRequestZodSchema, { target: 'draft-07' })
226
+ export const WidgetDataRequestSchema = toJSONSchema(WidgetDataRequestZodSchema, { target: 'draft-07' })
227
+ export const MoveWidgetRequestSchema = toJSONSchema(MoveWidgetRequestZodSchema, { target: 'draft-07' })
228
+ export const DashboardMutationResponseSchema = toJSONSchema(DashboardMutationResponseZodSchema, { target: 'draft-07' })
229
+ export const SetWidgetConfigRequestSchema = toJSONSchema(SetWidgetConfigRequestZodSchema, { target: 'draft-07' })
230
+ export const ConfigureTableWidgetRequestSchema = toJSONSchema(ConfigureTableWidgetRequestZodSchema, { target: 'draft-07' })
231
+ export const ConfigureKpiCardWidgetRequestSchema = toJSONSchema(ConfigureKpiCardWidgetRequestZodSchema, { target: 'draft-07' })
232
+ export const ConfigureGaugeCardWidgetRequestSchema = toJSONSchema(ConfigureGaugeCardWidgetRequestZodSchema, { target: 'draft-07' })
233
+ export const ConfigureLineChartWidgetRequestSchema = toJSONSchema(ConfigureLineChartWidgetRequestZodSchema, { target: 'draft-07' })
234
+ export const ConfigureBarChartWidgetRequestSchema = toJSONSchema(ConfigureBarChartWidgetRequestZodSchema, { target: 'draft-07' })
235
+ export const ConfigureStackedBarChartWidgetRequestSchema = toJSONSchema(ConfigureStackedBarChartWidgetRequestZodSchema, { target: 'draft-07' })
236
+ export const ConfigurePieChartWidgetRequestSchema = toJSONSchema(ConfigurePieChartWidgetRequestZodSchema, { target: 'draft-07' })
237
+ export const ConfigureHistogramChartWidgetRequestSchema = toJSONSchema(ConfigureHistogramChartWidgetRequestZodSchema, { target: 'draft-07' })
238
+ export const ConfigureFunnelChartWidgetRequestSchema = toJSONSchema(ConfigureFunnelChartWidgetRequestZodSchema, { target: 'draft-07' })
239
+ export const ConfigurePivotTableWidgetRequestSchema = toJSONSchema(ConfigurePivotTableWidgetRequestZodSchema, { target: 'draft-07' })