@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.
- package/custom/api/dashboardApi.ts +137 -5
- package/custom/model/dashboard.types.ts +32 -22
- package/custom/runtime/DashboardRuntime.vue +2 -3
- package/custom/skills/adminforth-dashboard/SKILL.md +165 -179
- package/custom/widgets/KpiCardWidget.vue +172 -9
- package/custom/widgets/chart/ChartWidget.vue +5 -5
- package/custom/widgets/registry.ts +4 -4
- package/dist/custom/api/dashboardApi.d.ts +46 -2
- package/dist/custom/api/dashboardApi.js +90 -5
- package/dist/custom/api/dashboardApi.ts +137 -5
- package/dist/custom/model/dashboard.types.d.ts +30 -14
- package/dist/custom/model/dashboard.types.js +2 -2
- package/dist/custom/model/dashboard.types.ts +32 -22
- package/dist/custom/queries/useDashboardConfig.d.ts +106 -104
- package/dist/custom/queries/useWidgetData.d.ts +106 -104
- package/dist/custom/runtime/DashboardRuntime.vue +2 -3
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +165 -179
- package/dist/custom/widgets/KpiCardWidget.vue +172 -9
- package/dist/custom/widgets/chart/ChartWidget.vue +5 -5
- package/dist/custom/widgets/registry.js +4 -4
- package/dist/custom/widgets/registry.ts +4 -4
- package/dist/endpoint/dashboard.d.ts +2 -4
- package/dist/endpoint/dashboard.js +1 -21
- package/dist/endpoint/groups.d.ts +1 -0
- package/dist/endpoint/groups.js +61 -48
- package/dist/endpoint/widgets.d.ts +1 -0
- package/dist/endpoint/widgets.js +167 -64
- package/dist/schema/api.d.ts +11710 -2785
- package/dist/schema/api.js +118 -26
- package/dist/schema/widget.d.ts +425 -1980
- package/dist/schema/widget.js +13 -374
- package/dist/schema/widgets/charts.d.ts +1689 -0
- package/dist/schema/widgets/charts.js +92 -0
- package/dist/schema/widgets/common.d.ts +275 -0
- package/dist/schema/widgets/common.js +171 -0
- package/dist/schema/widgets/gauge-card.d.ts +172 -0
- package/dist/schema/widgets/gauge-card.js +28 -0
- package/dist/schema/widgets/kpi-card.d.ts +212 -0
- package/dist/schema/widgets/kpi-card.js +43 -0
- package/dist/schema/widgets/pivot-table.d.ts +196 -0
- package/dist/schema/widgets/pivot-table.js +17 -0
- package/dist/schema/widgets/table.d.ts +130 -0
- package/dist/schema/widgets/table.js +12 -0
- package/dist/services/dashboardConfigService.d.ts +4 -0
- package/dist/services/dashboardConfigService.js +46 -0
- package/dist/services/widgetDataService.js +96 -2
- package/endpoint/dashboard.ts +2 -33
- package/endpoint/groups.ts +91 -72
- package/endpoint/widgets.ts +260 -87
- package/package.json +1 -1
- package/schema/api.ts +148 -28
- package/schema/widget.ts +43 -425
- package/schema/widgets/charts.ts +113 -0
- package/schema/widgets/common.ts +194 -0
- package/schema/widgets/gauge-card.ts +34 -0
- package/schema/widgets/kpi-card.ts +49 -0
- package/schema/widgets/pivot-table.ts +24 -0
- package/schema/widgets/table.ts +18 -0
- package/services/dashboardConfigService.ts +73 -0
- package/services/widgetDataService.ts +129 -3
package/endpoint/widgets.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
198
|
+
return { error: mutationError };
|
|
66
199
|
}
|
|
67
200
|
|
|
68
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
221
|
+
if (!widget) {
|
|
222
|
+
mutationError = 'Dashboard widget not found';
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
103
225
|
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
232
|
+
if (targetIndex < 0 || targetIndex >= sortedWidgets.length) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
111
235
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
.
|
|
115
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
255
|
+
if (mutationError) {
|
|
256
|
+
response.setStatus(404);
|
|
257
|
+
return { error: mutationError };
|
|
258
|
+
}
|
|
132
259
|
|
|
133
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
298
|
+
return { error: mutationError };
|
|
168
299
|
}
|
|
169
300
|
|
|
170
|
-
return
|
|
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
|
|
318
|
+
const request = body as ConfigureWidgetRequest;
|
|
319
|
+
const { updatedDashboard, mutationError } = await replaceWidgetConfig(ctx, request.slug, request.widgetId, request.config);
|
|
190
320
|
|
|
191
|
-
if (!
|
|
321
|
+
if (!updatedDashboard) {
|
|
192
322
|
response.setStatus(404);
|
|
193
323
|
return { error: 'Dashboard not found' };
|
|
194
324
|
}
|
|
195
325
|
|
|
196
|
-
|
|
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:
|
|
328
|
+
return { error: mutationError };
|
|
202
329
|
}
|
|
203
330
|
|
|
204
|
-
|
|
331
|
+
return updatedDashboard;
|
|
332
|
+
},
|
|
333
|
+
});
|
|
205
334
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
package/schema/api.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { toJSONSchema, z } from 'zod'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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(
|
|
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:
|
|
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:
|
|
185
|
+
config: ConfigurableWidgetConfigSchema,
|
|
103
186
|
}).strict()
|
|
104
187
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
export const
|
|
114
|
-
export const
|
|
115
|
-
export const
|
|
116
|
-
export const
|
|
117
|
-
export const
|
|
118
|
-
export const
|
|
119
|
-
export const
|
|
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' })
|