@adminforth/dashboard 1.3.0 → 1.4.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/README.md +80 -11
- package/custom/api/dashboardApi.ts +4 -0
- package/custom/model/dashboard.types.ts +16 -8
- package/custom/skills/adminforth-dashboard/SKILL.md +108 -1
- package/custom/widgets/chart/ChartWidget.vue +20 -3
- package/dist/custom/api/dashboardApi.d.ts +1 -0
- package/dist/custom/api/dashboardApi.js +5 -0
- package/dist/custom/api/dashboardApi.ts +4 -0
- package/dist/custom/model/dashboard.types.d.ts +3 -0
- package/dist/custom/model/dashboard.types.js +19 -5
- package/dist/custom/model/dashboard.types.ts +16 -8
- package/dist/custom/queries/useDashboardConfig.d.ts +20 -0
- package/dist/custom/queries/useWidgetData.d.ts +20 -0
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +108 -1
- package/dist/custom/widgets/chart/ChartWidget.vue +20 -3
- package/dist/endpoint/dashboard.d.ts +7 -2
- package/dist/endpoint/dashboard.js +45 -1
- package/dist/endpoint/widgets.d.ts +2 -1
- package/dist/endpoint/widgets.js +1 -0
- package/dist/schema/api.d.ts +109 -16
- package/dist/schema/api.js +5 -0
- package/dist/schema/widget.d.ts +72 -12
- package/dist/schema/widget.js +7 -4
- package/dist/services/widgetDataService.d.ts +2 -1
- package/dist/services/widgetDataService.js +50 -20
- package/endpoint/dashboard.ts +76 -3
- package/endpoint/widgets.ts +6 -2
- package/package.json +1 -1
- package/schema/api.ts +6 -0
- package/schema/widget.ts +7 -4
- package/services/widgetDataService.ts +53 -15
|
@@ -6,6 +6,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
6
6
|
id: string;
|
|
7
7
|
group_id: string;
|
|
8
8
|
label?: string | undefined;
|
|
9
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
9
10
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
10
11
|
width?: number | undefined;
|
|
11
12
|
height?: number | undefined;
|
|
@@ -17,6 +18,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
17
18
|
id: string;
|
|
18
19
|
group_id: string;
|
|
19
20
|
label?: string | undefined;
|
|
21
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
20
22
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
21
23
|
width?: number | undefined;
|
|
22
24
|
height?: number | undefined;
|
|
@@ -89,6 +91,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
89
91
|
id: string;
|
|
90
92
|
group_id: string;
|
|
91
93
|
label?: string | undefined;
|
|
94
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
92
95
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
93
96
|
width?: number | undefined;
|
|
94
97
|
height?: number | undefined;
|
|
@@ -199,11 +202,16 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
199
202
|
};
|
|
200
203
|
filters?: any;
|
|
201
204
|
}[];
|
|
205
|
+
calcs?: {
|
|
206
|
+
calc: string;
|
|
207
|
+
as: string;
|
|
208
|
+
}[] | undefined;
|
|
202
209
|
};
|
|
203
210
|
} | {
|
|
204
211
|
id: string;
|
|
205
212
|
group_id: string;
|
|
206
213
|
label?: string | undefined;
|
|
214
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
207
215
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
208
216
|
width?: number | undefined;
|
|
209
217
|
height?: number | undefined;
|
|
@@ -282,6 +290,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
282
290
|
id: string;
|
|
283
291
|
group_id: string;
|
|
284
292
|
label?: string | undefined;
|
|
293
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
285
294
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
286
295
|
width?: number | undefined;
|
|
287
296
|
height?: number | undefined;
|
|
@@ -366,6 +375,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
366
375
|
id: string;
|
|
367
376
|
group_id: string;
|
|
368
377
|
label?: string | undefined;
|
|
378
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
369
379
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
370
380
|
width?: number | undefined;
|
|
371
381
|
height?: number | undefined;
|
|
@@ -450,6 +460,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
450
460
|
id: string;
|
|
451
461
|
group_id: string;
|
|
452
462
|
label?: string | undefined;
|
|
463
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
453
464
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
454
465
|
width?: number | undefined;
|
|
455
466
|
height?: number | undefined;
|
|
@@ -461,6 +472,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
461
472
|
id: string;
|
|
462
473
|
group_id: string;
|
|
463
474
|
label?: string | undefined;
|
|
475
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
464
476
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
465
477
|
width?: number | undefined;
|
|
466
478
|
height?: number | undefined;
|
|
@@ -533,6 +545,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
533
545
|
id: string;
|
|
534
546
|
group_id: string;
|
|
535
547
|
label?: string | undefined;
|
|
548
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
536
549
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
537
550
|
width?: number | undefined;
|
|
538
551
|
height?: number | undefined;
|
|
@@ -643,11 +656,16 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
643
656
|
};
|
|
644
657
|
filters?: any;
|
|
645
658
|
}[];
|
|
659
|
+
calcs?: {
|
|
660
|
+
calc: string;
|
|
661
|
+
as: string;
|
|
662
|
+
}[] | undefined;
|
|
646
663
|
};
|
|
647
664
|
} | {
|
|
648
665
|
id: string;
|
|
649
666
|
group_id: string;
|
|
650
667
|
label?: string | undefined;
|
|
668
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
651
669
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
652
670
|
width?: number | undefined;
|
|
653
671
|
height?: number | undefined;
|
|
@@ -726,6 +744,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
726
744
|
id: string;
|
|
727
745
|
group_id: string;
|
|
728
746
|
label?: string | undefined;
|
|
747
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
729
748
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
730
749
|
width?: number | undefined;
|
|
731
750
|
height?: number | undefined;
|
|
@@ -810,6 +829,7 @@ export declare function useWidgetData(slug: Ref<string>, widgetId: Ref<string>,
|
|
|
810
829
|
id: string;
|
|
811
830
|
group_id: string;
|
|
812
831
|
label?: string | undefined;
|
|
832
|
+
variables?: import("../model/dashboard.types.js").DashboardVariables | undefined;
|
|
813
833
|
size?: import("../model/dashboard.types.js").DashboardWidgetSize | undefined;
|
|
814
834
|
width?: number | undefined;
|
|
815
835
|
height?: number | undefined;
|
|
@@ -41,6 +41,7 @@ If the user asks how the schema works, how to implement the API, or how to chang
|
|
|
41
41
|
Use these tools whenever available:
|
|
42
42
|
|
|
43
43
|
- `dashboard_get_config`
|
|
44
|
+
- `dashboard_set_dashboard_config`
|
|
44
45
|
- `dashboard_add_dashboard_group`
|
|
45
46
|
- `dashboard_set_dashboard_group_config`
|
|
46
47
|
- `dashboard_move_dashboard_group`
|
|
@@ -58,6 +59,7 @@ If a dashboard tool is known by name but its argument schema is not loaded, call
|
|
|
58
59
|
Do not pass fields between dashboard tools by analogy. Use each tool's schema.
|
|
59
60
|
|
|
60
61
|
- `dashboard_add_dashboard_group` creates a new group. It accepts the dashboard slug only. Never pass `groupId` to this tool.
|
|
62
|
+
- `dashboard_set_dashboard_config` replaces the full dashboard config. Use it when the user explicitly asks to edit the whole dashboard config.
|
|
61
63
|
- `dashboard_add_dashboard_widget` creates a widget inside an existing group. Use it when you already have a `groupId`.
|
|
62
64
|
- `dashboard_set_dashboard_group_config`, `dashboard_move_dashboard_group`, and `dashboard_remove_dashboard_group` operate on an existing group and need `groupId`.
|
|
63
65
|
- `dashboard_set_widget_config`, `dashboard_move_dashboard_widget`, `dashboard_remove_dashboard_widget`, and `dashboard_get_dashboard_widget_data` operate on an existing widget and need `widgetId`.
|
|
@@ -113,6 +115,24 @@ For group requests:
|
|
|
113
115
|
|
|
114
116
|
If slug is missing, use `default`.
|
|
115
117
|
|
|
118
|
+
## Dashboard Config Workflow
|
|
119
|
+
|
|
120
|
+
Use `dashboard_set_dashboard_config` only when the user explicitly asks to edit the whole dashboard root config.
|
|
121
|
+
|
|
122
|
+
For requests like:
|
|
123
|
+
|
|
124
|
+
- "update root dashboard config"
|
|
125
|
+
- "replace the whole dashboard config"
|
|
126
|
+
|
|
127
|
+
do this:
|
|
128
|
+
|
|
129
|
+
1. Call `dashboard_get_config`.
|
|
130
|
+
2. Modify the returned root config, preserving existing `version`, `groups`, and `widgets` unless the user asked to change them.
|
|
131
|
+
3. Call `dashboard_set_dashboard_config` with the full updated config.
|
|
132
|
+
4. Return a short summary of the root-level fields changed.
|
|
133
|
+
|
|
134
|
+
Do not use `dashboard_set_dashboard_config` to store reusable widget variables.
|
|
135
|
+
|
|
116
136
|
## Widget Config Rules
|
|
117
137
|
|
|
118
138
|
Use the current schema keys exactly:
|
|
@@ -124,6 +144,93 @@ Use the current schema keys exactly:
|
|
|
124
144
|
- Use `group_by`, not `groupBy`.
|
|
125
145
|
- Use `order_by`, not `orderBy`.
|
|
126
146
|
- Use `page_size`, not `pageSize`.
|
|
127
|
-
- For
|
|
147
|
+
- For step-based chart queries, use `query.steps` as an ordered array of `{ name, resource, metric, filters }` steps and add `query.calcs` when derived fields are needed.
|
|
128
148
|
- Use `card` for KPI and gauge widget view config.
|
|
129
149
|
- Use `pivot` for pivot table view config.
|
|
150
|
+
- Use `variables` for reusable static maps or constants at widget level.
|
|
151
|
+
- In `query.calcs`, use `lookup($variables.some.map, row_field, default_number)` to read a numeric value from a variable map by the current row/group field.
|
|
152
|
+
|
|
153
|
+
## Variables And Lookup Calcs
|
|
154
|
+
|
|
155
|
+
Widget config can define variables:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
variables:
|
|
159
|
+
token_prices_per_1m:
|
|
160
|
+
input:
|
|
161
|
+
gpt-4.1: 2.00
|
|
162
|
+
gpt-4.1-mini: 0.40
|
|
163
|
+
gpt-4o-mini: 0.15
|
|
164
|
+
output:
|
|
165
|
+
gpt-4.1: 8.00
|
|
166
|
+
gpt-4.1-mini: 1.60
|
|
167
|
+
gpt-4o-mini: 0.60
|
|
168
|
+
cached:
|
|
169
|
+
gpt-4.1: 0.50
|
|
170
|
+
gpt-4.1-mini: 0.10
|
|
171
|
+
gpt-4o-mini: 0.075
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use variables when a calculation needs a static rate table, threshold table, coefficient map, or other reusable constants. In calcs, `lookup($variables.path.to.map, field_name, 0)` returns the value from the map using `field_name` from the current row/group. The third argument is the numeric fallback when the key is missing.
|
|
175
|
+
|
|
176
|
+
Example widget:
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
target: chart
|
|
180
|
+
label: Model costs
|
|
181
|
+
size: large
|
|
182
|
+
variables:
|
|
183
|
+
token_prices_per_1m:
|
|
184
|
+
input:
|
|
185
|
+
gpt-4.1: 2.00
|
|
186
|
+
gpt-4.1-mini: 0.40
|
|
187
|
+
gpt-4o-mini: 0.15
|
|
188
|
+
output:
|
|
189
|
+
gpt-4.1: 8.00
|
|
190
|
+
gpt-4.1-mini: 1.60
|
|
191
|
+
gpt-4o-mini: 0.60
|
|
192
|
+
cached:
|
|
193
|
+
gpt-4.1: 0.50
|
|
194
|
+
gpt-4.1-mini: 0.10
|
|
195
|
+
gpt-4o-mini: 0.075
|
|
196
|
+
|
|
197
|
+
chart:
|
|
198
|
+
type: stacked_bar
|
|
199
|
+
title: LLM costs by model
|
|
200
|
+
x:
|
|
201
|
+
field: model
|
|
202
|
+
label: Model
|
|
203
|
+
y:
|
|
204
|
+
- field: input_cost
|
|
205
|
+
label: Input
|
|
206
|
+
format: currency
|
|
207
|
+
- field: output_cost
|
|
208
|
+
label: Output
|
|
209
|
+
format: currency
|
|
210
|
+
- field: cached_cost
|
|
211
|
+
label: Cached
|
|
212
|
+
format: currency
|
|
213
|
+
|
|
214
|
+
query:
|
|
215
|
+
resource: model_usage
|
|
216
|
+
select:
|
|
217
|
+
- field: model
|
|
218
|
+
- agg: sum
|
|
219
|
+
field: input_tokens
|
|
220
|
+
as: input_tokens
|
|
221
|
+
- agg: sum
|
|
222
|
+
field: output_tokens
|
|
223
|
+
as: output_tokens
|
|
224
|
+
- agg: sum
|
|
225
|
+
field: cached_tokens
|
|
226
|
+
as: cached_tokens
|
|
227
|
+
group_by:
|
|
228
|
+
- model
|
|
229
|
+
calcs:
|
|
230
|
+
- calc: input_tokens / 1000000 * lookup($variables.token_prices_per_1m.input, model, 0)
|
|
231
|
+
as: input_cost
|
|
232
|
+
- calc: output_tokens / 1000000 * lookup($variables.token_prices_per_1m.output, model, 0)
|
|
233
|
+
as: output_cost
|
|
234
|
+
- calc: cached_tokens / 1000000 * lookup($variables.token_prices_per_1m.cached, model, 0)
|
|
235
|
+
as: cached_cost
|
|
236
|
+
```
|
|
@@ -69,10 +69,10 @@
|
|
|
69
69
|
|
|
70
70
|
<StackedBarChart
|
|
71
71
|
v-else-if="chartConfig?.type === 'stacked_bar'"
|
|
72
|
-
:rows="
|
|
72
|
+
:rows="stackedBarRows"
|
|
73
73
|
:x-field="xField"
|
|
74
|
-
:y-field="
|
|
75
|
-
:series-field="
|
|
74
|
+
:y-field="stackedBarYField"
|
|
75
|
+
:series-field="stackedBarSeriesField"
|
|
76
76
|
:colors="chartConfig.colors"
|
|
77
77
|
:height="chartHeight"
|
|
78
78
|
/>
|
|
@@ -155,6 +155,21 @@ const valueField = computed(() => chartConfig.value?.value?.field || columns.val
|
|
|
155
155
|
const pieRows = computed(() => rows.value)
|
|
156
156
|
const pieLabelField = computed(() => labelField.value)
|
|
157
157
|
const pieValueField = computed(() => valueField.value)
|
|
158
|
+
const stackedBarYItems = computed(() => {
|
|
159
|
+
const y = chartConfig.value?.y
|
|
160
|
+
return Array.isArray(y) ? y : []
|
|
161
|
+
})
|
|
162
|
+
const stackedBarRows = computed(() => {
|
|
163
|
+
if (chartConfig.value?.type !== 'stacked_bar' || !stackedBarYItems.value.length) {
|
|
164
|
+
return rows.value
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return rows.value.flatMap((row) => stackedBarYItems.value.map((item) => ({
|
|
168
|
+
[xField.value]: row[xField.value],
|
|
169
|
+
__series: item.label ?? item.field,
|
|
170
|
+
__value: row[item.field],
|
|
171
|
+
})))
|
|
172
|
+
})
|
|
158
173
|
const barRows = computed(() => {
|
|
159
174
|
const bucketField = chartConfig.value?.type === 'histogram'
|
|
160
175
|
? chartConfig.value.x?.field
|
|
@@ -178,6 +193,8 @@ const barRows = computed(() => {
|
|
|
178
193
|
const barLabelField = computed(() => chartConfig.value?.type === 'histogram' && chartConfig.value.buckets ? 'label' : xField.value)
|
|
179
194
|
const barValueField = computed(() => chartConfig.value?.type === 'histogram' && chartConfig.value.buckets ? 'count' : yField.value)
|
|
180
195
|
const seriesField = computed(() => chartConfig.value?.series?.field || columns.value[2] || '')
|
|
196
|
+
const stackedBarYField = computed(() => stackedBarYItems.value.length ? '__value' : yField.value)
|
|
197
|
+
const stackedBarSeriesField = computed(() => stackedBarYItems.value.length ? '__series' : seriesField.value)
|
|
181
198
|
const lineSeriesName = computed(() => {
|
|
182
199
|
const y = chartConfig.value?.y
|
|
183
200
|
return Array.isArray(y) ? y[0]?.label : undefined
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type { IHttpServer } from 'adminforth';
|
|
2
|
-
import type {
|
|
1
|
+
import type { AdminUser, IHttpServer } from 'adminforth';
|
|
2
|
+
import type { DashboardConfig, DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
|
|
3
|
+
import type { DashboardWidgetConfigValidationError } from '../schema/widget.js';
|
|
4
|
+
import type { DashboardRecord, PersistedDashboardResponse } from '../services/dashboardConfigService.js';
|
|
3
5
|
type DashboardEndpointsContext = {
|
|
6
|
+
canEditDashboard: (adminUser: AdminUser) => boolean;
|
|
4
7
|
getDashboardRecord: (slug: string) => Promise<DashboardRecord | null>;
|
|
8
|
+
persistDashboardConfig: (dashboard: DashboardRecord, config: DashboardConfig) => Promise<PersistedDashboardResponse>;
|
|
9
|
+
validateDashboardWidgetApiConfig: (widget: DashboardWidgetConfig) => DashboardWidgetConfigValidationError[];
|
|
5
10
|
};
|
|
6
11
|
export declare function registerDashboardEndpoints(server: IHttpServer, ctx: DashboardEndpointsContext): void;
|
|
7
12
|
export {};
|
|
@@ -7,8 +7,15 @@ 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 {
|
|
10
|
+
import { normalizeDashboardConfig } from '../custom/model/dashboard.types.js';
|
|
11
|
+
import { DashboardApiResponseSchema, DashboardConfigZodSchema, SetDashboardConfigRequestSchema, SlugRequestSchema, } from '../schema/api.js';
|
|
11
12
|
import { buildDashboardResponse } from '../services/dashboardConfigService.js';
|
|
13
|
+
function formatDashboardConfigValidationErrors(error) {
|
|
14
|
+
return error.issues.map((issue) => ({
|
|
15
|
+
field: issue.path.length ? issue.path.map(String).join('.') : 'config',
|
|
16
|
+
message: issue.message,
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
12
19
|
export function registerDashboardEndpoints(server, ctx) {
|
|
13
20
|
server.endpoint({
|
|
14
21
|
method: 'POST',
|
|
@@ -26,4 +33,41 @@ export function registerDashboardEndpoints(server, ctx) {
|
|
|
26
33
|
return buildDashboardResponse(dashboard);
|
|
27
34
|
}),
|
|
28
35
|
});
|
|
36
|
+
server.endpoint({
|
|
37
|
+
method: 'POST',
|
|
38
|
+
path: '/dashboard/set_dashboard_config',
|
|
39
|
+
description: 'Replaces one dashboard configuration, including groups and widgets. Superadmin only.',
|
|
40
|
+
request_schema: SetDashboardConfigRequestSchema,
|
|
41
|
+
response_schema: DashboardApiResponseSchema,
|
|
42
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
43
|
+
if (!ctx.canEditDashboard(adminUser)) {
|
|
44
|
+
response.setStatus(403);
|
|
45
|
+
return { error: 'Dashboard edit is not allowed' };
|
|
46
|
+
}
|
|
47
|
+
const slug = String((body === null || body === void 0 ? void 0 : body.slug) || 'default');
|
|
48
|
+
const dashboard = yield ctx.getDashboardRecord(slug);
|
|
49
|
+
if (!dashboard) {
|
|
50
|
+
response.setStatus(404);
|
|
51
|
+
return { error: 'Dashboard not found' };
|
|
52
|
+
}
|
|
53
|
+
const normalizedConfig = normalizeDashboardConfig(body === null || body === void 0 ? void 0 : body.config);
|
|
54
|
+
const parsedConfig = DashboardConfigZodSchema.safeParse(normalizedConfig);
|
|
55
|
+
if (!parsedConfig.success) {
|
|
56
|
+
response.setStatus(422);
|
|
57
|
+
return {
|
|
58
|
+
error: 'Invalid dashboard config',
|
|
59
|
+
validationErrors: formatDashboardConfigValidationErrors(parsedConfig.error),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const widgetValidationErrors = parsedConfig.data.widgets.flatMap((widget, index) => (ctx.validateDashboardWidgetApiConfig(widget).map((error) => (Object.assign(Object.assign({}, error), { field: `widgets.${index}.${error.field}` })))));
|
|
63
|
+
if (widgetValidationErrors.length) {
|
|
64
|
+
response.setStatus(422);
|
|
65
|
+
return {
|
|
66
|
+
error: 'Invalid dashboard config',
|
|
67
|
+
validationErrors: widgetValidationErrors,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return ctx.persistDashboardConfig(dashboard, parsedConfig.data);
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
29
73
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AdminUser, IHttpServer } from 'adminforth';
|
|
2
|
-
import type { DashboardConfig, DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
|
|
2
|
+
import type { DashboardConfig, DashboardVariables, DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
|
|
3
3
|
import type { DashboardWidgetConfigValidationError } from '../schema/widget.js';
|
|
4
4
|
import type { DashboardRecord, PersistedDashboardResponse } from '../services/dashboardConfigService.js';
|
|
5
5
|
type WidgetEndpointsContext = {
|
|
@@ -14,6 +14,7 @@ type WidgetEndpointsContext = {
|
|
|
14
14
|
page: number;
|
|
15
15
|
pageSize: number;
|
|
16
16
|
};
|
|
17
|
+
variables?: DashboardVariables;
|
|
17
18
|
}) => Promise<unknown>;
|
|
18
19
|
};
|
|
19
20
|
export declare function registerWidgetEndpoints(server: IHttpServer, ctx: WidgetEndpointsContext): void;
|
package/dist/endpoint/widgets.js
CHANGED