@adminforth/dashboard 1.1.0 → 1.2.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 +11 -28
- package/custom/model/dashboard.types.ts +236 -42
- package/custom/runtime/DashboardRuntime.vue +2 -1
- package/custom/runtime/WidgetRenderer.vue +2 -1
- package/custom/skills/adminforth-dashboard/SKILL.md +4 -4
- package/custom/widgets/chart/ChartWidget.vue +45 -12
- package/custom/widgets/chart/chart.types.ts +83 -0
- package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -38
- package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
- package/custom/widgets/pivot-table/PivotTableWidget.vue +8 -10
- package/custom/widgets/table/TableWidget.vue +1 -1
- package/dist/custom/model/dashboard.types.d.ts +25 -1
- package/dist/custom/model/dashboard.types.js +133 -42
- package/dist/custom/model/dashboard.types.ts +236 -42
- package/dist/custom/queries/useDashboardConfig.d.ts +0 -2
- package/dist/custom/queries/useWidgetData.d.ts +0 -2
- package/dist/custom/runtime/DashboardRuntime.vue +2 -1
- package/dist/custom/runtime/WidgetRenderer.vue +2 -1
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +4 -4
- package/dist/custom/widgets/chart/ChartWidget.vue +45 -12
- package/dist/custom/widgets/chart/chart.types.d.ts +15 -0
- package/dist/custom/widgets/chart/chart.types.js +46 -0
- package/dist/custom/widgets/chart/chart.types.ts +83 -0
- package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -38
- package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
- package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +8 -10
- package/dist/custom/widgets/table/TableWidget.vue +1 -1
- package/dist/endpoint/widgets.js +20 -3
- package/dist/schema/api.d.ts +0 -240
- package/dist/schema/widget.d.ts +0 -132
- package/dist/schema/widget.js +30 -16
- package/dist/services/widgetConfigValidator.js +9 -49
- package/dist/services/widgetDataService.d.ts +0 -9
- package/dist/services/widgetDataService.js +12 -30
- package/endpoint/widgets.ts +26 -3
- package/package.json +1 -1
- package/schema/widget.ts +34 -17
- package/services/widgetConfigValidator.ts +10 -57
- package/services/widgetDataService.ts +10 -45
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IAdminForth } from 'adminforth';
|
|
2
2
|
import type { DashboardWidgetConfig } from '../custom/model/dashboard.types.js';
|
|
3
|
+
import { normalizeChartWidgetConfig } from '../custom/widgets/chart/chart.types.js';
|
|
3
4
|
import type { DashboardWidgetConfigValidationError } from '../schema/widget.js';
|
|
4
|
-
import type { DashboardWidgetQueryConfig } from './widgetDataService.js';
|
|
5
5
|
|
|
6
6
|
export type WidgetConfigValidatorService = {
|
|
7
7
|
validateDashboardWidgetApiConfig: (
|
|
@@ -19,7 +19,9 @@ export function validateDashboardWidgetApiConfig(
|
|
|
19
19
|
|
|
20
20
|
const errors: DashboardWidgetConfigValidationError[] = [];
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const chart = normalizeChartWidgetConfig(widget.chart);
|
|
23
|
+
|
|
24
|
+
if (!chart) {
|
|
23
25
|
errors.push({
|
|
24
26
|
field: 'chart',
|
|
25
27
|
message: 'Chart widget must have chart config',
|
|
@@ -34,14 +36,14 @@ export function validateDashboardWidgetApiConfig(
|
|
|
34
36
|
|
|
35
37
|
if (!resource) {
|
|
36
38
|
errors.push({
|
|
37
|
-
field: '
|
|
39
|
+
field: 'data_source.resource_id',
|
|
38
40
|
message: `Resource "${aggregateDataSource.resourceId}" is not registered`,
|
|
39
41
|
});
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
if (!aggregateDataSource.groupBy) {
|
|
43
45
|
errors.push({
|
|
44
|
-
field: '
|
|
46
|
+
field: 'data_source.group_by',
|
|
45
47
|
message: 'Chart aggregate dataSource must define groupBy',
|
|
46
48
|
});
|
|
47
49
|
}
|
|
@@ -49,59 +51,10 @@ export function validateDashboardWidgetApiConfig(
|
|
|
49
51
|
return errors;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
});
|
|
57
|
-
return errors;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const query = widget.query as DashboardWidgetQueryConfig;
|
|
61
|
-
const chart = widget.chart;
|
|
62
|
-
|
|
63
|
-
const resource = adminforth.config.resources.find((item) => item.resourceId === query.resource);
|
|
64
|
-
|
|
65
|
-
if (!resource) {
|
|
66
|
-
errors.push({
|
|
67
|
-
field: 'query.resource',
|
|
68
|
-
message: `Resource "${query.resource}" is not registered`,
|
|
69
|
-
});
|
|
70
|
-
return errors;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!query.select) {
|
|
74
|
-
return errors;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const resourceFields = resource.columns.map((column) => column.name);
|
|
78
|
-
|
|
79
|
-
for (const field of query.select) {
|
|
80
|
-
if (!resourceFields.includes(field)) {
|
|
81
|
-
errors.push({
|
|
82
|
-
field: 'query.select',
|
|
83
|
-
message: `Field "${field}" is not in resource "${query.resource}"`,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const chartFields = [
|
|
89
|
-
chart.x_field,
|
|
90
|
-
chart.y_field,
|
|
91
|
-
chart.label_field,
|
|
92
|
-
chart.value_field,
|
|
93
|
-
chart.bucket_field,
|
|
94
|
-
...(chart.series?.map((series: { field: string }) => series.field) ?? []),
|
|
95
|
-
].filter((field): field is string => typeof field === 'string');
|
|
96
|
-
|
|
97
|
-
for (const field of chartFields) {
|
|
98
|
-
if (!query.select.includes(field)) {
|
|
99
|
-
errors.push({
|
|
100
|
-
field: 'query.select',
|
|
101
|
-
message: `Query select must include chart field "${field}"`,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
54
|
+
errors.push({
|
|
55
|
+
field: 'data_source',
|
|
56
|
+
message: 'Chart widget must have aggregate dataSource config',
|
|
57
|
+
});
|
|
105
58
|
|
|
106
59
|
return errors;
|
|
107
60
|
}
|
|
@@ -13,16 +13,6 @@ import type {
|
|
|
13
13
|
WidgetDataSource,
|
|
14
14
|
} from '../custom/model/dashboard.types.js';
|
|
15
15
|
|
|
16
|
-
export type DashboardWidgetQueryConfig = {
|
|
17
|
-
resource: string;
|
|
18
|
-
select?: string[];
|
|
19
|
-
order?: {
|
|
20
|
-
field: string;
|
|
21
|
-
direction: 'asc' | 'desc';
|
|
22
|
-
};
|
|
23
|
-
limit?: number;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
16
|
export type DashboardWidgetDataOptions = {
|
|
27
17
|
pagination?: {
|
|
28
18
|
page: number;
|
|
@@ -44,8 +34,7 @@ export async function getWidgetData(
|
|
|
44
34
|
widget: DashboardWidgetConfig,
|
|
45
35
|
options: DashboardWidgetDataOptions = {},
|
|
46
36
|
): Promise<DashboardWidgetData | null> {
|
|
47
|
-
const
|
|
48
|
-
const dataSource = getWidgetDataSource(widget, legacyQuery);
|
|
37
|
+
const dataSource = getWidgetDataSource(widget.dataSource);
|
|
49
38
|
|
|
50
39
|
if (!dataSource) {
|
|
51
40
|
return null;
|
|
@@ -55,24 +44,20 @@ export async function getWidgetData(
|
|
|
55
44
|
return getAggregateWidgetData(adminforth, dataSource);
|
|
56
45
|
}
|
|
57
46
|
|
|
58
|
-
return getResourceWidgetData(adminforth, dataSource,
|
|
47
|
+
return getResourceWidgetData(adminforth, dataSource, options);
|
|
59
48
|
}
|
|
60
49
|
|
|
61
50
|
async function getResourceWidgetData(
|
|
62
51
|
adminforth: IAdminForth,
|
|
63
52
|
dataSource: Extract<WidgetDataSource, { type: 'resource' }>,
|
|
64
|
-
legacyQuery: DashboardWidgetQueryConfig | undefined,
|
|
65
53
|
options: DashboardWidgetDataOptions,
|
|
66
54
|
): Promise<DashboardWidgetData> {
|
|
67
55
|
const resource = adminforth.resource(dataSource.resourceId);
|
|
68
56
|
const filters = normalizeFilters(dataSource.filters);
|
|
69
|
-
const sort = normalizeSort(dataSource.sort
|
|
57
|
+
const sort = normalizeSort(dataSource.sort);
|
|
70
58
|
const pagination = options.pagination;
|
|
71
59
|
const offset = pagination ? (pagination.page - 1) * pagination.pageSize : 0;
|
|
72
|
-
const
|
|
73
|
-
const limit = pagination
|
|
74
|
-
? Math.max(Math.min(pagination.pageSize, (queryLimit ?? Infinity) - offset), 0)
|
|
75
|
-
: queryLimit;
|
|
60
|
+
const limit = pagination ? pagination.pageSize : undefined;
|
|
76
61
|
|
|
77
62
|
const rows = await resource.list(
|
|
78
63
|
filters,
|
|
@@ -81,8 +66,8 @@ async function getResourceWidgetData(
|
|
|
81
66
|
sort,
|
|
82
67
|
);
|
|
83
68
|
|
|
84
|
-
const columns = dataSource.columns ??
|
|
85
|
-
const total = pagination ?
|
|
69
|
+
const columns = dataSource.columns ?? Object.keys(rows[0] ?? {});
|
|
70
|
+
const total = pagination ? await resource.count(filters) : 0;
|
|
86
71
|
|
|
87
72
|
return {
|
|
88
73
|
columns,
|
|
@@ -135,32 +120,12 @@ async function getAggregateWidgetData(
|
|
|
135
120
|
};
|
|
136
121
|
}
|
|
137
122
|
|
|
138
|
-
function
|
|
139
|
-
if (
|
|
140
|
-
return
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return query as DashboardWidgetQueryConfig;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function getWidgetDataSource(
|
|
147
|
-
widget: DashboardWidgetConfig,
|
|
148
|
-
legacyQuery: DashboardWidgetQueryConfig | undefined,
|
|
149
|
-
): WidgetDataSource | undefined {
|
|
150
|
-
if (isWidgetDataSource(widget.dataSource)) {
|
|
151
|
-
return widget.dataSource;
|
|
123
|
+
function getWidgetDataSource(dataSource: unknown): WidgetDataSource | undefined {
|
|
124
|
+
if (isWidgetDataSource(dataSource)) {
|
|
125
|
+
return dataSource;
|
|
152
126
|
}
|
|
153
127
|
|
|
154
|
-
|
|
155
|
-
return undefined;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
type: 'resource',
|
|
160
|
-
resourceId: legacyQuery.resource,
|
|
161
|
-
columns: legacyQuery.select,
|
|
162
|
-
sort: legacyQuery.order,
|
|
163
|
-
};
|
|
128
|
+
return undefined;
|
|
164
129
|
}
|
|
165
130
|
|
|
166
131
|
function isWidgetDataSource(value: unknown): value is WidgetDataSource {
|