@adminforth/dashboard 1.9.0 → 1.11.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 +73 -36
- package/custom/runtime/DashboardRuntime.vue +26 -22
- package/custom/skills/adminforth-dashboard/SKILL.md +305 -10
- package/dist/custom/api/dashboardApi.d.ts +24 -18
- package/dist/custom/api/dashboardApi.js +42 -18
- package/dist/custom/api/dashboardApi.ts +73 -36
- package/dist/custom/runtime/DashboardRuntime.vue +26 -22
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +305 -10
- package/dist/endpoint/dashboard.d.ts +1 -0
- package/dist/endpoint/dashboard.js +15 -1
- package/dist/endpoint/groups.js +22 -20
- package/dist/endpoint/widgets.js +28 -26
- package/dist/schema/api.d.ts +151 -1869
- package/dist/schema/api.js +12 -12
- package/dist/services/calc-evaluator.d.ts +2 -1
- package/dist/services/calc-evaluator.js +29 -3
- package/dist/services/dashboardConfigService.d.ts +2 -0
- package/dist/services/dashboardConfigService.js +6 -0
- package/dist/services/widgetDataService.js +2 -2
- package/endpoint/dashboard.ts +17 -0
- package/endpoint/groups.ts +22 -20
- package/endpoint/widgets.ts +28 -26
- package/package.json +1 -1
- package/schema/api.ts +13 -12
- package/services/calc-evaluator.ts +41 -3
- package/services/dashboardConfigService.ts +9 -0
- package/services/widgetDataService.ts +2 -2
|
@@ -22,26 +22,320 @@ Dashboard root, groups, and widgets are different entities.
|
|
|
22
22
|
|
|
23
23
|
## Tool routing
|
|
24
24
|
|
|
25
|
+
- Get dashboard slugs: dashboard_get_slugs
|
|
25
26
|
- Read dashboard: dashboard_get_config
|
|
26
27
|
- Add group: dashboard_add_dashboard_group
|
|
27
28
|
- Rename group: dashboard_set_dashboard_group_config
|
|
28
29
|
- Add widget slot: dashboard_add_dashboard_widget
|
|
29
|
-
- Configure
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
30
|
+
- Configure widget:
|
|
31
|
+
- table: dashboard_configure_table_widget
|
|
32
|
+
- kpi_card: dashboard_configure_kpi_card_widget
|
|
33
|
+
- gauge_card: dashboard_configure_gauge_card_widget
|
|
34
|
+
- pivot_table: dashboard_configure_pivot_table_widget
|
|
35
|
+
- line_chart: dashboard_configure_line_chart_widget
|
|
36
|
+
- bar_chart: dashboard_configure_bar_chart_widget
|
|
37
|
+
- stacked_bar_chart: dashboard_configure_stacked_bar_chart_widget
|
|
38
|
+
- pie_chart: dashboard_configure_pie_chart_widget
|
|
39
|
+
- histogram_chart: dashboard_configure_histogram_chart_widget
|
|
40
|
+
- funnel_chart: dashboard_configure_funnel_chart_widget
|
|
39
41
|
- Move/remove widget/group: matching move/remove tool
|
|
40
42
|
- Load widget data: dashboard_get_dashboard_widget_data
|
|
41
43
|
|
|
42
44
|
If a known dashboard tool schema is missing, call fetch_tool_schema for that exact tool.
|
|
43
45
|
If fetch_tool_schema returns but the intended tool is still not callable, stop and report a tool-routing error. Do not substitute another mutation tool.
|
|
44
46
|
|
|
47
|
+
## Configure schema examples
|
|
48
|
+
|
|
49
|
+
These examples show the expected shape only. Do not copy them one-to-one: adapt resource names, fields, aggregations, labels, filters, formats, and calculations to the actual dashboard request and available resource columns.
|
|
50
|
+
|
|
51
|
+
Important:
|
|
52
|
+
- `config.target` is the widget target, never a resource path.
|
|
53
|
+
- Never use values like `/resource/llm_usage` in `config.target`.
|
|
54
|
+
- Put the data resource in `config.query.resource`, for example `query.resource: "llm_usage"`.
|
|
55
|
+
- For chart widgets, `config.target` is always `chart`; the concrete chart kind is `config.chart.type`.
|
|
56
|
+
- `query.calcs[].calc` is an expression over already selected fields/aliases, not raw SQL. Do not use SQL syntax such as `CASE WHEN`.
|
|
57
|
+
|
|
58
|
+
Example `dashboard_configure_table_widget` config:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
target: table
|
|
62
|
+
label: Recent usage
|
|
63
|
+
size: wide
|
|
64
|
+
table:
|
|
65
|
+
columns:
|
|
66
|
+
- field: used_at
|
|
67
|
+
label: Date
|
|
68
|
+
- field: model
|
|
69
|
+
label: Model
|
|
70
|
+
- field: total_tokens
|
|
71
|
+
label: Tokens
|
|
72
|
+
format: integer
|
|
73
|
+
pagination: true
|
|
74
|
+
page_size: 20
|
|
75
|
+
query:
|
|
76
|
+
resource: llm_usage
|
|
77
|
+
select:
|
|
78
|
+
- field: used_at
|
|
79
|
+
- field: model
|
|
80
|
+
- field: total_tokens
|
|
81
|
+
order_by:
|
|
82
|
+
- field: used_at
|
|
83
|
+
direction: desc
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Example `dashboard_configure_kpi_card_widget` config:
|
|
87
|
+
|
|
88
|
+
```yaml
|
|
89
|
+
target: kpi_card
|
|
90
|
+
label: Total spend
|
|
91
|
+
size: medium
|
|
92
|
+
card:
|
|
93
|
+
title: Total spend
|
|
94
|
+
value:
|
|
95
|
+
field: spend
|
|
96
|
+
format: currency
|
|
97
|
+
query:
|
|
98
|
+
resource: llm_usage
|
|
99
|
+
select:
|
|
100
|
+
- agg: sum
|
|
101
|
+
field: cost
|
|
102
|
+
as: spend
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Example `dashboard_configure_gauge_card_widget` config:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
target: gauge_card
|
|
109
|
+
label: Budget usage
|
|
110
|
+
size: medium
|
|
111
|
+
card:
|
|
112
|
+
title: Budget usage
|
|
113
|
+
value:
|
|
114
|
+
field: spend
|
|
115
|
+
format: currency
|
|
116
|
+
progress:
|
|
117
|
+
value_field: spend
|
|
118
|
+
target_value: 1000
|
|
119
|
+
format: percent
|
|
120
|
+
query:
|
|
121
|
+
resource: llm_usage
|
|
122
|
+
select:
|
|
123
|
+
- agg: sum
|
|
124
|
+
field: cost
|
|
125
|
+
as: spend
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Example `dashboard_configure_pivot_table_widget` config:
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
target: pivot_table
|
|
132
|
+
label: Spend by model and purpose
|
|
133
|
+
size: wide
|
|
134
|
+
pivot:
|
|
135
|
+
rows:
|
|
136
|
+
- field: model
|
|
137
|
+
label: Model
|
|
138
|
+
columns:
|
|
139
|
+
- field: purpose
|
|
140
|
+
label: Purpose
|
|
141
|
+
values:
|
|
142
|
+
- field: spend
|
|
143
|
+
label: Spend
|
|
144
|
+
format: currency
|
|
145
|
+
aggregation: sum
|
|
146
|
+
query:
|
|
147
|
+
resource: llm_usage
|
|
148
|
+
select:
|
|
149
|
+
- field: model
|
|
150
|
+
- field: purpose
|
|
151
|
+
- agg: sum
|
|
152
|
+
field: cost
|
|
153
|
+
as: spend
|
|
154
|
+
group_by:
|
|
155
|
+
- model
|
|
156
|
+
- purpose
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Example `dashboard_configure_line_chart_widget` config:
|
|
160
|
+
|
|
161
|
+
```yaml
|
|
162
|
+
target: chart
|
|
163
|
+
label: Daily spend
|
|
164
|
+
size: wide
|
|
165
|
+
chart:
|
|
166
|
+
type: line
|
|
167
|
+
x:
|
|
168
|
+
field: day
|
|
169
|
+
label: Day
|
|
170
|
+
y:
|
|
171
|
+
- field: spend
|
|
172
|
+
label: Spend
|
|
173
|
+
format: currency
|
|
174
|
+
query:
|
|
175
|
+
resource: llm_usage
|
|
176
|
+
select:
|
|
177
|
+
- field: used_at
|
|
178
|
+
grain: day
|
|
179
|
+
as: day
|
|
180
|
+
- agg: sum
|
|
181
|
+
field: cost
|
|
182
|
+
as: spend
|
|
183
|
+
group_by:
|
|
184
|
+
- field: used_at
|
|
185
|
+
grain: day
|
|
186
|
+
as: day
|
|
187
|
+
order_by:
|
|
188
|
+
- field: day
|
|
189
|
+
direction: asc
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Example `dashboard_configure_bar_chart_widget` config:
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
target: chart
|
|
196
|
+
label: Spend by model
|
|
197
|
+
size: wide
|
|
198
|
+
chart:
|
|
199
|
+
type: bar
|
|
200
|
+
x:
|
|
201
|
+
field: model
|
|
202
|
+
label: Model
|
|
203
|
+
y:
|
|
204
|
+
field: spend
|
|
205
|
+
label: Spend
|
|
206
|
+
format: currency
|
|
207
|
+
query:
|
|
208
|
+
resource: llm_usage
|
|
209
|
+
select:
|
|
210
|
+
- field: model
|
|
211
|
+
- agg: sum
|
|
212
|
+
field: cost
|
|
213
|
+
as: spend
|
|
214
|
+
group_by:
|
|
215
|
+
- model
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Example `dashboard_configure_stacked_bar_chart_widget` config:
|
|
219
|
+
|
|
220
|
+
```yaml
|
|
221
|
+
target: chart
|
|
222
|
+
label: Daily spend by purpose
|
|
223
|
+
size: wide
|
|
224
|
+
chart:
|
|
225
|
+
type: stacked_bar
|
|
226
|
+
x:
|
|
227
|
+
field: day
|
|
228
|
+
label: Day
|
|
229
|
+
y:
|
|
230
|
+
field: spend
|
|
231
|
+
label: Spend
|
|
232
|
+
format: currency
|
|
233
|
+
series:
|
|
234
|
+
field: purpose
|
|
235
|
+
label: Purpose
|
|
236
|
+
query:
|
|
237
|
+
resource: llm_usage
|
|
238
|
+
select:
|
|
239
|
+
- field: used_at
|
|
240
|
+
grain: day
|
|
241
|
+
as: day
|
|
242
|
+
- field: purpose
|
|
243
|
+
- agg: sum
|
|
244
|
+
field: cost
|
|
245
|
+
as: spend
|
|
246
|
+
group_by:
|
|
247
|
+
- field: used_at
|
|
248
|
+
grain: day
|
|
249
|
+
as: day
|
|
250
|
+
- purpose
|
|
251
|
+
order_by:
|
|
252
|
+
- field: day
|
|
253
|
+
direction: asc
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Example `dashboard_configure_pie_chart_widget` config:
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
target: chart
|
|
260
|
+
label: Spend share by model
|
|
261
|
+
size: medium
|
|
262
|
+
chart:
|
|
263
|
+
type: pie
|
|
264
|
+
label:
|
|
265
|
+
field: model
|
|
266
|
+
label: Model
|
|
267
|
+
value:
|
|
268
|
+
field: spend
|
|
269
|
+
label: Spend
|
|
270
|
+
format: currency
|
|
271
|
+
query:
|
|
272
|
+
resource: llm_usage
|
|
273
|
+
select:
|
|
274
|
+
- field: model
|
|
275
|
+
- agg: sum
|
|
276
|
+
field: cost
|
|
277
|
+
as: spend
|
|
278
|
+
group_by:
|
|
279
|
+
- model
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Example `dashboard_configure_histogram_chart_widget` config:
|
|
283
|
+
|
|
284
|
+
```yaml
|
|
285
|
+
target: chart
|
|
286
|
+
label: Request size distribution
|
|
287
|
+
size: wide
|
|
288
|
+
chart:
|
|
289
|
+
type: histogram
|
|
290
|
+
x:
|
|
291
|
+
field: total_tokens
|
|
292
|
+
label: Tokens
|
|
293
|
+
y:
|
|
294
|
+
field: requests
|
|
295
|
+
label: Requests
|
|
296
|
+
query:
|
|
297
|
+
resource: llm_usage
|
|
298
|
+
select:
|
|
299
|
+
- field: total_tokens
|
|
300
|
+
- agg: count
|
|
301
|
+
as: requests
|
|
302
|
+
bucket:
|
|
303
|
+
field: total_tokens
|
|
304
|
+
buckets:
|
|
305
|
+
- label: Small
|
|
306
|
+
max: 1000
|
|
307
|
+
- label: Medium
|
|
308
|
+
min: 1000
|
|
309
|
+
max: 10000
|
|
310
|
+
- label: Large
|
|
311
|
+
min: 10000
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Example `dashboard_configure_funnel_chart_widget` config:
|
|
315
|
+
|
|
316
|
+
```yaml
|
|
317
|
+
target: chart
|
|
318
|
+
label: Request funnel
|
|
319
|
+
size: wide
|
|
320
|
+
chart:
|
|
321
|
+
type: funnel
|
|
322
|
+
label:
|
|
323
|
+
field: stage
|
|
324
|
+
label: Stage
|
|
325
|
+
value:
|
|
326
|
+
field: count
|
|
327
|
+
label: Count
|
|
328
|
+
query:
|
|
329
|
+
resource: llm_usage
|
|
330
|
+
select:
|
|
331
|
+
- field: stage
|
|
332
|
+
- agg: count
|
|
333
|
+
as: count
|
|
334
|
+
group_by:
|
|
335
|
+
- stage
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
|
|
45
339
|
## Group creation guard
|
|
46
340
|
|
|
47
341
|
Before creating a group, call dashboard_get_config and check existing groups.
|
|
@@ -148,6 +442,7 @@ Use target, not type.
|
|
|
148
442
|
For charts, use target: chart and chart.type for the concrete chart kind.
|
|
149
443
|
Use query, not dataSource.
|
|
150
444
|
Use resource, not resourceId.
|
|
445
|
+
Never use AdminForth routes such as /resource/llm_usage as resource or target values.
|
|
151
446
|
|
|
152
447
|
## Query shape rules
|
|
153
448
|
|
|
@@ -3,6 +3,7 @@ import type { DashboardConfig } from '../custom/model/dashboard.types.js';
|
|
|
3
3
|
import type { DashboardRecord } from '../services/dashboardConfigService.js';
|
|
4
4
|
type DashboardEndpointsContext = {
|
|
5
5
|
getDashboardRecord: (slug: string) => Promise<DashboardRecord | null>;
|
|
6
|
+
getAllDashboardRecords: () => Promise<DashboardRecord[]>;
|
|
6
7
|
parseStoredDashboardConfig: (config: unknown) => DashboardConfig;
|
|
7
8
|
};
|
|
8
9
|
export declare function registerDashboardEndpoints(server: IHttpServer, ctx: DashboardEndpointsContext): void;
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { DashboardApiResponseSchema, SlugRequestSchema, } from '../schema/api.js';
|
|
10
|
+
import { DashboardApiResponseSchema, GetSlugsResponseSchema, SlugRequestSchema, } from '../schema/api.js';
|
|
11
11
|
export function registerDashboardEndpoints(server, ctx) {
|
|
12
12
|
server.endpoint({
|
|
13
13
|
method: 'POST',
|
|
@@ -30,4 +30,18 @@ export function registerDashboardEndpoints(server, ctx) {
|
|
|
30
30
|
};
|
|
31
31
|
}),
|
|
32
32
|
});
|
|
33
|
+
server.endpoint({
|
|
34
|
+
method: 'GET',
|
|
35
|
+
path: '/dashboard/get-slugs',
|
|
36
|
+
description: 'Returns a list of all dashboard slugs and labels for listing purposes.',
|
|
37
|
+
request_schema: undefined,
|
|
38
|
+
response_schema: GetSlugsResponseSchema,
|
|
39
|
+
handler: () => __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
const dashboards = yield ctx.getAllDashboardRecords();
|
|
41
|
+
return dashboards.map((dashboard) => ({
|
|
42
|
+
slug: dashboard.slug,
|
|
43
|
+
label: dashboard.label,
|
|
44
|
+
}));
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
33
47
|
}
|
package/dist/endpoint/groups.js
CHANGED
|
@@ -8,19 +8,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { randomUUID } from 'crypto';
|
|
11
|
-
import {
|
|
11
|
+
import { DashboardMutationResponseSchema, GroupIdRequestSchema, MoveGroupRequestSchema, SetGroupConfigRequestSchema, SlugRequestSchema, } from '../schema/api.js';
|
|
12
12
|
export function registerGroupEndpoints(server, ctx) {
|
|
13
13
|
server.endpoint({
|
|
14
14
|
method: 'POST',
|
|
15
15
|
path: '/dashboard/add_dashboard_group',
|
|
16
16
|
description: 'Adds a new group to a dashboard configuration. Superadmin only.',
|
|
17
17
|
request_schema: SlugRequestSchema,
|
|
18
|
-
response_schema:
|
|
18
|
+
response_schema: DashboardMutationResponseSchema,
|
|
19
19
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
20
20
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
21
21
|
response.setStatus(403);
|
|
22
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
22
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
23
23
|
}
|
|
24
|
+
let groupId = null;
|
|
24
25
|
const updatedDashboard = yield ctx.updateDashboardConfig(body.slug, (config) => {
|
|
25
26
|
const nextOrder = config.groups.length + 1;
|
|
26
27
|
const group = {
|
|
@@ -28,13 +29,14 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
28
29
|
label: 'New group',
|
|
29
30
|
order: nextOrder,
|
|
30
31
|
};
|
|
32
|
+
groupId = group.id;
|
|
31
33
|
return Object.assign(Object.assign({}, config), { groups: [...config.groups, group] });
|
|
32
34
|
});
|
|
33
35
|
if (!updatedDashboard) {
|
|
34
36
|
response.setStatus(404);
|
|
35
|
-
return { error: 'Dashboard not found' };
|
|
37
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
36
38
|
}
|
|
37
|
-
return
|
|
39
|
+
return { ok: true, groupId };
|
|
38
40
|
}),
|
|
39
41
|
});
|
|
40
42
|
server.endpoint({
|
|
@@ -42,11 +44,11 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
42
44
|
path: '/dashboard/set_dashboard_group_config',
|
|
43
45
|
description: 'Replaces editable JSON configuration for a dashboard group while preserving group id and order. Superadmin only.',
|
|
44
46
|
request_schema: SetGroupConfigRequestSchema,
|
|
45
|
-
response_schema:
|
|
47
|
+
response_schema: DashboardMutationResponseSchema,
|
|
46
48
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
47
49
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
48
50
|
response.setStatus(403);
|
|
49
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
51
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
50
52
|
}
|
|
51
53
|
const groupId = body.groupId;
|
|
52
54
|
let mutationError = null;
|
|
@@ -63,13 +65,13 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
63
65
|
});
|
|
64
66
|
if (!updatedDashboard) {
|
|
65
67
|
response.setStatus(404);
|
|
66
|
-
return { error: 'Dashboard not found' };
|
|
68
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
67
69
|
}
|
|
68
70
|
if (mutationError) {
|
|
69
71
|
response.setStatus(404);
|
|
70
|
-
return { error: mutationError };
|
|
72
|
+
return { ok: false, error: mutationError };
|
|
71
73
|
}
|
|
72
|
-
return
|
|
74
|
+
return { ok: true };
|
|
73
75
|
}),
|
|
74
76
|
});
|
|
75
77
|
server.endpoint({
|
|
@@ -77,11 +79,11 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
77
79
|
path: '/dashboard/move_dashboard_group',
|
|
78
80
|
description: 'Moves a dashboard group up or down in its dashboard. Superadmin only.',
|
|
79
81
|
request_schema: MoveGroupRequestSchema,
|
|
80
|
-
response_schema:
|
|
82
|
+
response_schema: DashboardMutationResponseSchema,
|
|
81
83
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
82
84
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
83
85
|
response.setStatus(403);
|
|
84
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
86
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
85
87
|
}
|
|
86
88
|
let mutationError = null;
|
|
87
89
|
const updatedDashboard = yield ctx.updateDashboardConfig(body.slug, (config) => {
|
|
@@ -102,13 +104,13 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
102
104
|
});
|
|
103
105
|
if (!updatedDashboard) {
|
|
104
106
|
response.setStatus(404);
|
|
105
|
-
return { error: 'Dashboard not found' };
|
|
107
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
106
108
|
}
|
|
107
109
|
if (mutationError) {
|
|
108
110
|
response.setStatus(404);
|
|
109
|
-
return { error: mutationError };
|
|
111
|
+
return { ok: false, error: mutationError };
|
|
110
112
|
}
|
|
111
|
-
return
|
|
113
|
+
return { ok: true };
|
|
112
114
|
}),
|
|
113
115
|
});
|
|
114
116
|
server.endpoint({
|
|
@@ -116,11 +118,11 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
116
118
|
path: '/dashboard/remove_dashboard_group',
|
|
117
119
|
description: 'Removes a dashboard group and all widgets inside it. Superadmin only.',
|
|
118
120
|
request_schema: GroupIdRequestSchema,
|
|
119
|
-
response_schema:
|
|
121
|
+
response_schema: DashboardMutationResponseSchema,
|
|
120
122
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
121
123
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
122
124
|
response.setStatus(403);
|
|
123
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
125
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
124
126
|
}
|
|
125
127
|
const groupId = body.groupId;
|
|
126
128
|
let mutationError = null;
|
|
@@ -134,13 +136,13 @@ export function registerGroupEndpoints(server, ctx) {
|
|
|
134
136
|
});
|
|
135
137
|
if (!updatedDashboard) {
|
|
136
138
|
response.setStatus(404);
|
|
137
|
-
return { error: 'Dashboard not found' };
|
|
139
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
138
140
|
}
|
|
139
141
|
if (mutationError) {
|
|
140
142
|
response.setStatus(404);
|
|
141
|
-
return { error: mutationError };
|
|
143
|
+
return { ok: false, error: mutationError };
|
|
142
144
|
}
|
|
143
|
-
return
|
|
145
|
+
return { ok: true };
|
|
144
146
|
}),
|
|
145
147
|
});
|
|
146
148
|
}
|
package/dist/endpoint/widgets.js
CHANGED
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { randomUUID } from 'crypto';
|
|
11
|
-
import { ConfigureBarChartWidgetRequestSchema, ConfigureFunnelChartWidgetRequestSchema, ConfigureGaugeCardWidgetRequestSchema, ConfigureHistogramChartWidgetRequestSchema, ConfigureKpiCardWidgetRequestSchema, ConfigureLineChartWidgetRequestSchema, ConfigurePieChartWidgetRequestSchema, ConfigurePivotTableWidgetRequestSchema, ConfigureStackedBarChartWidgetRequestSchema, ConfigureTableWidgetRequestSchema,
|
|
11
|
+
import { ConfigureBarChartWidgetRequestSchema, ConfigureFunnelChartWidgetRequestSchema, ConfigureGaugeCardWidgetRequestSchema, ConfigureHistogramChartWidgetRequestSchema, ConfigureKpiCardWidgetRequestSchema, ConfigureLineChartWidgetRequestSchema, ConfigurePieChartWidgetRequestSchema, ConfigurePivotTableWidgetRequestSchema, ConfigureStackedBarChartWidgetRequestSchema, ConfigureTableWidgetRequestSchema, DashboardMutationResponseSchema, DashboardWidgetDataResponseSchema, GroupIdRequestSchema, MoveWidgetRequestSchema, SetWidgetConfigRequestSchema, WidgetDataRequestSchema, WidgetIdRequestSchema, } from '../schema/api.js';
|
|
12
12
|
function replaceWidgetConfig(ctx, slug, widgetId, widgetConfig) {
|
|
13
13
|
return __awaiter(this, void 0, void 0, function* () {
|
|
14
14
|
let mutationError = null;
|
|
@@ -35,23 +35,23 @@ function registerConfigureWidgetEndpoint(server, ctx, options) {
|
|
|
35
35
|
path: options.path,
|
|
36
36
|
description: options.description,
|
|
37
37
|
request_schema: options.requestSchema,
|
|
38
|
-
response_schema:
|
|
38
|
+
response_schema: DashboardMutationResponseSchema,
|
|
39
39
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
40
40
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
41
41
|
response.setStatus(403);
|
|
42
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
42
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
43
43
|
}
|
|
44
44
|
const request = body;
|
|
45
45
|
const { updatedDashboard, mutationError } = yield replaceWidgetConfig(ctx, request.slug, request.widgetId, request.config);
|
|
46
46
|
if (!updatedDashboard) {
|
|
47
47
|
response.setStatus(404);
|
|
48
|
-
return { error: 'Dashboard not found' };
|
|
48
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
49
49
|
}
|
|
50
50
|
if (mutationError) {
|
|
51
51
|
response.setStatus(404);
|
|
52
|
-
return { error: mutationError };
|
|
52
|
+
return { ok: false, error: mutationError };
|
|
53
53
|
}
|
|
54
|
-
return
|
|
54
|
+
return { ok: true };
|
|
55
55
|
}),
|
|
56
56
|
});
|
|
57
57
|
}
|
|
@@ -61,13 +61,14 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
61
61
|
path: '/dashboard/add_dashboard_widget',
|
|
62
62
|
description: 'Adds a new empty widget to a dashboard group. Superadmin only.',
|
|
63
63
|
request_schema: GroupIdRequestSchema,
|
|
64
|
-
response_schema:
|
|
64
|
+
response_schema: DashboardMutationResponseSchema,
|
|
65
65
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
66
66
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
67
67
|
response.setStatus(403);
|
|
68
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
68
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
69
69
|
}
|
|
70
70
|
let mutationError = null;
|
|
71
|
+
let widgetId = null;
|
|
71
72
|
const updatedDashboard = yield ctx.updateDashboardConfig(body.slug, (config) => {
|
|
72
73
|
const group = config.groups.find((item) => item.id === body.groupId);
|
|
73
74
|
if (!group) {
|
|
@@ -83,17 +84,18 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
83
84
|
order: nextOrder,
|
|
84
85
|
target: 'empty',
|
|
85
86
|
};
|
|
87
|
+
widgetId = widget.id;
|
|
86
88
|
return Object.assign(Object.assign({}, config), { widgets: [...config.widgets, widget] });
|
|
87
89
|
});
|
|
88
90
|
if (!updatedDashboard) {
|
|
89
91
|
response.setStatus(404);
|
|
90
|
-
return { error: 'Dashboard not found' };
|
|
92
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
91
93
|
}
|
|
92
94
|
if (mutationError) {
|
|
93
95
|
response.setStatus(404);
|
|
94
|
-
return { error: mutationError };
|
|
96
|
+
return { ok: false, error: mutationError };
|
|
95
97
|
}
|
|
96
|
-
return
|
|
98
|
+
return { ok: true, widgetId };
|
|
97
99
|
}),
|
|
98
100
|
});
|
|
99
101
|
server.endpoint({
|
|
@@ -101,11 +103,11 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
101
103
|
path: '/dashboard/move_dashboard_widget',
|
|
102
104
|
description: 'Moves a dashboard widget up or down inside its group. Superadmin only.',
|
|
103
105
|
request_schema: MoveWidgetRequestSchema,
|
|
104
|
-
response_schema:
|
|
106
|
+
response_schema: DashboardMutationResponseSchema,
|
|
105
107
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
106
108
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
107
109
|
response.setStatus(403);
|
|
108
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
110
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
109
111
|
}
|
|
110
112
|
let mutationError = null;
|
|
111
113
|
const updatedDashboard = yield ctx.updateDashboardConfig(body.slug, (config) => {
|
|
@@ -133,13 +135,13 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
133
135
|
});
|
|
134
136
|
if (!updatedDashboard) {
|
|
135
137
|
response.setStatus(404);
|
|
136
|
-
return { error: 'Dashboard not found' };
|
|
138
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
137
139
|
}
|
|
138
140
|
if (mutationError) {
|
|
139
141
|
response.setStatus(404);
|
|
140
|
-
return { error: mutationError };
|
|
142
|
+
return { ok: false, error: mutationError };
|
|
141
143
|
}
|
|
142
|
-
return
|
|
144
|
+
return { ok: true };
|
|
143
145
|
}),
|
|
144
146
|
});
|
|
145
147
|
server.endpoint({
|
|
@@ -147,11 +149,11 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
147
149
|
path: '/dashboard/remove_dashboard_widget',
|
|
148
150
|
description: 'Removes one dashboard widget by id. Superadmin only.',
|
|
149
151
|
request_schema: WidgetIdRequestSchema,
|
|
150
|
-
response_schema:
|
|
152
|
+
response_schema: DashboardMutationResponseSchema,
|
|
151
153
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
152
154
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
153
155
|
response.setStatus(403);
|
|
154
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
156
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
155
157
|
}
|
|
156
158
|
let mutationError = null;
|
|
157
159
|
const updatedDashboard = yield ctx.updateDashboardConfig(body.slug, (config) => {
|
|
@@ -164,13 +166,13 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
164
166
|
});
|
|
165
167
|
if (!updatedDashboard) {
|
|
166
168
|
response.setStatus(404);
|
|
167
|
-
return { error: 'Dashboard not found' };
|
|
169
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
168
170
|
}
|
|
169
171
|
if (mutationError) {
|
|
170
172
|
response.setStatus(404);
|
|
171
|
-
return { error: mutationError };
|
|
173
|
+
return { ok: false, error: mutationError };
|
|
172
174
|
}
|
|
173
|
-
return
|
|
175
|
+
return { ok: true };
|
|
174
176
|
}),
|
|
175
177
|
});
|
|
176
178
|
server.endpoint({
|
|
@@ -178,23 +180,23 @@ export function registerWidgetEndpoints(server, ctx) {
|
|
|
178
180
|
path: '/dashboard/set_widget_config',
|
|
179
181
|
description: 'Replaces editable JSON configuration for a dashboard widget while preserving widget id, group id, and order. Superadmin only.',
|
|
180
182
|
request_schema: SetWidgetConfigRequestSchema,
|
|
181
|
-
response_schema:
|
|
183
|
+
response_schema: DashboardMutationResponseSchema,
|
|
182
184
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
183
185
|
if (!ctx.canEditDashboard(adminUser)) {
|
|
184
186
|
response.setStatus(403);
|
|
185
|
-
return { error: 'Dashboard edit is not allowed' };
|
|
187
|
+
return { ok: false, error: 'Dashboard edit is not allowed' };
|
|
186
188
|
}
|
|
187
189
|
const request = body;
|
|
188
190
|
const { updatedDashboard, mutationError } = yield replaceWidgetConfig(ctx, request.slug, request.widgetId, request.config);
|
|
189
191
|
if (!updatedDashboard) {
|
|
190
192
|
response.setStatus(404);
|
|
191
|
-
return { error: 'Dashboard not found' };
|
|
193
|
+
return { ok: false, error: 'Dashboard not found' };
|
|
192
194
|
}
|
|
193
195
|
if (mutationError) {
|
|
194
196
|
response.setStatus(404);
|
|
195
|
-
return { error: mutationError };
|
|
197
|
+
return { ok: false, error: mutationError };
|
|
196
198
|
}
|
|
197
|
-
return
|
|
199
|
+
return { ok: true };
|
|
198
200
|
}),
|
|
199
201
|
});
|
|
200
202
|
registerConfigureWidgetEndpoint(server, ctx, {
|