@adminforth/dashboard 1.4.2 → 1.5.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 +0 -4
- package/custom/skills/adminforth-dashboard/SKILL.md +111 -181
- package/dist/custom/api/dashboardApi.d.ts +0 -1
- package/dist/custom/api/dashboardApi.js +0 -5
- package/dist/custom/api/dashboardApi.ts +0 -4
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +111 -181
- 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 +80 -62
- package/dist/schema/api.d.ts +0 -867
- package/dist/schema/api.js +0 -5
- package/dist/services/dashboardConfigService.d.ts +4 -0
- package/dist/services/dashboardConfigService.js +46 -0
- package/endpoint/dashboard.ts +2 -33
- package/endpoint/groups.ts +91 -72
- package/endpoint/widgets.ts +114 -88
- package/package.json +1 -1
- package/schema/api.ts +0 -6
- package/services/dashboardConfigService.ts +73 -0
|
@@ -140,10 +140,6 @@ export const dashboardApi = {
|
|
|
140
140
|
return callDashboardApi('/adminapi/v1/dashboard/get-config', { slug })
|
|
141
141
|
},
|
|
142
142
|
|
|
143
|
-
async setDashboardConfig(slug: string, config: unknown): Promise<DashboardResponse> {
|
|
144
|
-
return callDashboardApi('/adminapi/v1/dashboard/set_dashboard_config', { slug, config })
|
|
145
|
-
},
|
|
146
|
-
|
|
147
143
|
async addDashboardGroup(slug: string): Promise<DashboardResponse> {
|
|
148
144
|
return callDashboardApi('/adminapi/v1/dashboard/add_dashboard_group', { slug })
|
|
149
145
|
},
|
|
@@ -5,232 +5,162 @@ description: Use when the user wants to view, create, update, move, remove, vali
|
|
|
5
5
|
|
|
6
6
|
# AdminForth Dashboard Plugin
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Use this skill for dashboard group/widget mutations and dashboard data loading.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Core rule
|
|
11
11
|
|
|
12
|
-
If
|
|
12
|
+
If dashboard tools are callable, use tools. Do not answer mutation requests by only printing config.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## Entity boundaries
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Dashboard root, groups, and widgets are different entities.
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
- Group tools use groupId and only change group config.
|
|
19
|
+
- Widget tools use widgetId and change target/query/card/chart/table/pivot.
|
|
20
|
+
- Never call dashboard_set_dashboard_group_config to configure a widget.
|
|
21
|
+
- Never call dashboard_add_dashboard_group to configure a widget.
|
|
22
|
+
- If widget target, label, query, chart, card, table, pivot, variables, formulas, filters, or display fields must change, use dashboard_set_widget_config.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
## Tool routing
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
- Read dashboard: dashboard_get_config
|
|
27
|
+
- Add group: dashboard_add_dashboard_group
|
|
28
|
+
- Rename group: dashboard_set_dashboard_group_config
|
|
29
|
+
- Add widget slot: dashboard_add_dashboard_widget
|
|
30
|
+
- Configure widget: dashboard_set_widget_config
|
|
31
|
+
- Move/remove widget/group: matching move/remove tool
|
|
32
|
+
- Load widget data: dashboard_get_dashboard_widget_data
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
If a known dashboard tool schema is missing, call fetch_tool_schema for that exact tool.
|
|
35
|
+
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.
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
- "change/update/edit this widget" → update widget config.
|
|
31
|
-
- "move this widget/group" → call the move tool.
|
|
32
|
-
- "remove/delete this widget/group" → call the remove tool.
|
|
33
|
-
- "show/load dashboard" → call the dashboard config tool.
|
|
34
|
-
- "load/check widget data" → call the widget data tool.
|
|
35
|
-
- "validate this widget config" → call validation logic/tool if available.
|
|
37
|
+
## Group creation guard
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
Before creating a group, call dashboard_get_config and check existing groups.
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
- If a requested group label already exists, reuse that groupId.
|
|
42
|
+
- If no matching group exists, call dashboard_add_dashboard_group at most once for that requested group.
|
|
43
|
+
- After dashboard_add_dashboard_group succeeds, extract the new groupId from the returned dashboard response.
|
|
44
|
+
- If the group needs a label, call dashboard_set_dashboard_group_config once with that groupId.
|
|
45
|
+
- After that, the next mutation must be dashboard_add_dashboard_widget or dashboard_set_widget_config, not another dashboard_add_dashboard_group.
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
Never call dashboard_add_dashboard_group repeatedly for the same user request. If you are about to create a second group for the same label/section, stop and report:
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
- `dashboard_set_dashboard_config`
|
|
45
|
-
- `dashboard_add_dashboard_group`
|
|
46
|
-
- `dashboard_set_dashboard_group_config`
|
|
47
|
-
- `dashboard_move_dashboard_group`
|
|
48
|
-
- `dashboard_remove_dashboard_group`
|
|
49
|
-
- `dashboard_add_dashboard_widget`
|
|
50
|
-
- `dashboard_move_dashboard_widget`
|
|
51
|
-
- `dashboard_remove_dashboard_widget`
|
|
52
|
-
- `dashboard_set_widget_config`
|
|
53
|
-
- `dashboard_get_dashboard_widget_data`
|
|
49
|
+
Repeated dashboard_add_dashboard_group; expected using the existing/new groupId.
|
|
54
50
|
|
|
55
|
-
|
|
51
|
+
## Create-and-configure workflow
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
For any request to create KPI/chart/table/pivot/gauge widgets:
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
1. dashboard_get_config
|
|
56
|
+
2. select existing group by label, or create one group once
|
|
57
|
+
3. if needed, rename group once
|
|
58
|
+
4. for each widget:
|
|
59
|
+
- dashboard_add_dashboard_widget
|
|
60
|
+
- immediately dashboard_set_widget_config for the returned widgetId
|
|
61
|
+
- confirm target is not empty
|
|
62
|
+
5. dashboard_get_config
|
|
63
|
+
6. validate all requested widgets are configured
|
|
64
|
+
7. return short summary
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- `dashboard_add_dashboard_widget` creates a widget inside an existing group. Use it when you already have a `groupId`.
|
|
64
|
-
- `dashboard_set_dashboard_group_config`, `dashboard_move_dashboard_group`, and `dashboard_remove_dashboard_group` operate on an existing group and need `groupId`.
|
|
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`.
|
|
66
|
-
- If a tool call fails with "input did not match expected schema", call `fetch_tool_schema` for that exact tool, remove unsupported arguments, and retry the correct tool.
|
|
66
|
+
Do not batch-create empty widgets and postpone configuration.
|
|
67
|
+
Do not build a full dashboard JSON object for this workflow.
|
|
67
68
|
|
|
68
|
-
##
|
|
69
|
+
## Empty widget rule
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
dashboard_add_dashboard_widget creates only:
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
- "write a widget showing top 5 orders"
|
|
75
|
-
- "make a widget for revenue by product"
|
|
73
|
+
label: New widget
|
|
74
|
+
target: empty
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
This is incomplete for KPI/chart/table/pivot/gauge/spend/revenue/usage widgets.
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
2. Select the requested group. If the group is not specified, use the first existing group.
|
|
81
|
-
3. If there are no groups, call `dashboard_add_dashboard_group`.
|
|
82
|
-
4. Call `dashboard_add_dashboard_widget` with the selected group id.
|
|
83
|
-
5. Call `dashboard_set_widget_config` with the returned widget id and schema-valid config.
|
|
84
|
-
6. Return a short summary with dashboard slug, group id, widget id, target, label, resource, selected fields, order, and limit.
|
|
78
|
+
## No-op loop guard
|
|
85
79
|
|
|
86
|
-
|
|
80
|
+
If the same mutation tool is about to be called with the same payload twice, stop and reassess.
|
|
81
|
+
If dashboard_add_dashboard_group repeats for the same requested group, stop and reuse the groupId from dashboard_get_config.
|
|
82
|
+
If dashboard_set_dashboard_group_config repeats while new widgets are target: empty, use dashboard_set_widget_config instead.
|
|
83
|
+
After 2 repeated no-op mutations, stop with an explicit error.
|
|
87
84
|
|
|
88
|
-
##
|
|
85
|
+
## State machine
|
|
89
86
|
|
|
90
|
-
For
|
|
87
|
+
For create group + widgets tasks, follow this exact state order:
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
dashboard_get_config
|
|
90
|
+
-> maybe dashboard_add_dashboard_group
|
|
91
|
+
-> maybe dashboard_set_dashboard_group_config
|
|
92
|
+
-> dashboard_add_dashboard_widget
|
|
93
|
+
-> dashboard_set_widget_config
|
|
94
|
+
-> repeat only the two widget steps for more widgets
|
|
95
|
+
-> dashboard_get_config
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
Allowed repeats:
|
|
98
|
+
- dashboard_add_dashboard_widget may repeat once per requested widget.
|
|
99
|
+
- dashboard_set_widget_config may repeat once per requested widget.
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
4. Call `dashboard_set_widget_config`.
|
|
103
|
-
5. Return a short summary of what changed.
|
|
101
|
+
Forbidden repeats:
|
|
102
|
+
- dashboard_add_dashboard_group for the same requested group.
|
|
103
|
+
- dashboard_set_dashboard_group_config with the same label/groupId.
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
Forbidden substitutions:
|
|
106
|
+
- dashboard_set_dashboard_group_config instead of set widget config.
|
|
107
|
+
- dashboard_add_dashboard_group instead of add widget.
|
|
106
108
|
|
|
107
|
-
##
|
|
109
|
+
## Widget config keys
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
Use current keys:
|
|
112
|
+
target, label, query, resource, group_by, order_by, page_size, variables.
|
|
113
|
+
Use card for kpi_card/gauge_card.
|
|
114
|
+
Use chart for chart.
|
|
115
|
+
Use table for table.
|
|
116
|
+
Use pivot for pivot_table.
|
|
110
117
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
- Remove group → `dashboard_remove_dashboard_group`
|
|
118
|
+
Use target, not type.
|
|
119
|
+
Use query, not dataSource.
|
|
120
|
+
Use resource, not resourceId.
|
|
115
121
|
|
|
116
|
-
|
|
122
|
+
## Query shape rules
|
|
117
123
|
|
|
118
|
-
|
|
124
|
+
Use query.steps only for funnel charts. Do not use query.steps for kpi_card, gauge_card, table, pivot_table, or normal bar/line/stacked/pie charts.
|
|
119
125
|
|
|
120
|
-
|
|
126
|
+
For kpi_card and normal charts, use:
|
|
127
|
+
- query.resource
|
|
128
|
+
- query.select
|
|
129
|
+
- optional query.filters
|
|
130
|
+
- optional query.group_by
|
|
131
|
+
- optional query.period
|
|
132
|
+
- optional query.order_by
|
|
133
|
+
- optional query.calcs
|
|
121
134
|
|
|
122
|
-
|
|
135
|
+
Calculations run after selected fields and aggregates are loaded into a row. Therefore:
|
|
136
|
+
- aggregate real resource fields first
|
|
137
|
+
- then calculate derived fields from those aggregate aliases
|
|
138
|
+
- do not aggregate a calc alias such as cost unless cost is an actual resource field
|
|
123
139
|
|
|
124
|
-
|
|
125
|
-
- "replace the whole dashboard config"
|
|
140
|
+
For spend/cost widgets, prefer this pattern:
|
|
126
141
|
|
|
127
|
-
|
|
142
|
+
select raw token totals:
|
|
143
|
+
- sum uncached_input_tokens as uncached_input_tokens
|
|
144
|
+
- sum cached_input_tokens as cached_input_tokens
|
|
145
|
+
- sum output_tokens as output_tokens
|
|
128
146
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
3. Call `dashboard_set_dashboard_config` with the full updated config.
|
|
132
|
-
4. Return a short summary of the root-level fields changed.
|
|
147
|
+
then query.calcs:
|
|
148
|
+
- calculate total_spend from those aliases and lookup variables
|
|
133
149
|
|
|
134
|
-
|
|
150
|
+
For today vs yesterday KPI, use multiple aggregate select items with filters and distinct aliases, then calcs. Do not use query.steps.
|
|
135
151
|
|
|
136
|
-
##
|
|
152
|
+
## Calc variables
|
|
137
153
|
|
|
138
|
-
Use
|
|
154
|
+
Use variables for static maps/rates.
|
|
155
|
+
Use lookup($variables.some.map, row_field, default_number) in query.calcs.
|
|
139
156
|
|
|
140
|
-
|
|
141
|
-
- Use `label`, not `title`.
|
|
142
|
-
- Use `query`, not `dataSource`.
|
|
143
|
-
- Use `resource`, not `resourceId`.
|
|
144
|
-
- Use `group_by`, not `groupBy`.
|
|
145
|
-
- Use `order_by`, not `orderBy`.
|
|
146
|
-
- Use `page_size`, not `pageSize`.
|
|
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.
|
|
148
|
-
- Use `card` for KPI and gauge widget view config.
|
|
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.
|
|
157
|
+
Minimal example:
|
|
152
158
|
|
|
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
159
|
variables:
|
|
183
|
-
|
|
184
|
-
|
|
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
|
|
160
|
+
prices:
|
|
161
|
+
gpt-5.4: 2.5
|
|
213
162
|
|
|
214
163
|
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
164
|
calcs:
|
|
230
|
-
- calc:
|
|
231
|
-
as:
|
|
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
|
-
```
|
|
165
|
+
- calc: tokens / 1000000 * lookup($variables.prices, model, 0)
|
|
166
|
+
as: cost
|
|
@@ -22,7 +22,6 @@ export declare class DashboardApiError extends Error {
|
|
|
22
22
|
}
|
|
23
23
|
export declare const dashboardApi: {
|
|
24
24
|
getDashboardConfig(slug: string): Promise<DashboardResponse>;
|
|
25
|
-
setDashboardConfig(slug: string, config: unknown): Promise<DashboardResponse>;
|
|
26
25
|
addDashboardGroup(slug: string): Promise<DashboardResponse>;
|
|
27
26
|
moveDashboardGroup(slug: string, groupId: string, direction: DashboardGroupMoveDirection): Promise<DashboardResponse>;
|
|
28
27
|
removeDashboardGroup(slug: string, groupId: string): Promise<DashboardResponse>;
|
|
@@ -99,11 +99,6 @@ export const dashboardApi = {
|
|
|
99
99
|
return callDashboardApi('/adminapi/v1/dashboard/get-config', { slug });
|
|
100
100
|
});
|
|
101
101
|
},
|
|
102
|
-
setDashboardConfig(slug, config) {
|
|
103
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
return callDashboardApi('/adminapi/v1/dashboard/set_dashboard_config', { slug, config });
|
|
105
|
-
});
|
|
106
|
-
},
|
|
107
102
|
addDashboardGroup(slug) {
|
|
108
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
109
104
|
return callDashboardApi('/adminapi/v1/dashboard/add_dashboard_group', { slug });
|
|
@@ -140,10 +140,6 @@ export const dashboardApi = {
|
|
|
140
140
|
return callDashboardApi('/adminapi/v1/dashboard/get-config', { slug })
|
|
141
141
|
},
|
|
142
142
|
|
|
143
|
-
async setDashboardConfig(slug: string, config: unknown): Promise<DashboardResponse> {
|
|
144
|
-
return callDashboardApi('/adminapi/v1/dashboard/set_dashboard_config', { slug, config })
|
|
145
|
-
},
|
|
146
|
-
|
|
147
143
|
async addDashboardGroup(slug: string): Promise<DashboardResponse> {
|
|
148
144
|
return callDashboardApi('/adminapi/v1/dashboard/add_dashboard_group', { slug })
|
|
149
145
|
},
|