@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.
Files changed (39) hide show
  1. package/README.md +11 -28
  2. package/custom/model/dashboard.types.ts +236 -42
  3. package/custom/runtime/DashboardRuntime.vue +2 -1
  4. package/custom/runtime/WidgetRenderer.vue +2 -1
  5. package/custom/skills/adminforth-dashboard/SKILL.md +4 -4
  6. package/custom/widgets/chart/ChartWidget.vue +45 -12
  7. package/custom/widgets/chart/chart.types.ts +83 -0
  8. package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -38
  9. package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
  10. package/custom/widgets/pivot-table/PivotTableWidget.vue +8 -10
  11. package/custom/widgets/table/TableWidget.vue +1 -1
  12. package/dist/custom/model/dashboard.types.d.ts +25 -1
  13. package/dist/custom/model/dashboard.types.js +133 -42
  14. package/dist/custom/model/dashboard.types.ts +236 -42
  15. package/dist/custom/queries/useDashboardConfig.d.ts +0 -2
  16. package/dist/custom/queries/useWidgetData.d.ts +0 -2
  17. package/dist/custom/runtime/DashboardRuntime.vue +2 -1
  18. package/dist/custom/runtime/WidgetRenderer.vue +2 -1
  19. package/dist/custom/skills/adminforth-dashboard/SKILL.md +4 -4
  20. package/dist/custom/widgets/chart/ChartWidget.vue +45 -12
  21. package/dist/custom/widgets/chart/chart.types.d.ts +15 -0
  22. package/dist/custom/widgets/chart/chart.types.js +46 -0
  23. package/dist/custom/widgets/chart/chart.types.ts +83 -0
  24. package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -38
  25. package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
  26. package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +8 -10
  27. package/dist/custom/widgets/table/TableWidget.vue +1 -1
  28. package/dist/endpoint/widgets.js +20 -3
  29. package/dist/schema/api.d.ts +0 -240
  30. package/dist/schema/widget.d.ts +0 -132
  31. package/dist/schema/widget.js +30 -16
  32. package/dist/services/widgetConfigValidator.js +9 -49
  33. package/dist/services/widgetDataService.d.ts +0 -9
  34. package/dist/services/widgetDataService.js +12 -30
  35. package/endpoint/widgets.ts +26 -3
  36. package/package.json +1 -1
  37. package/schema/widget.ts +34 -17
  38. package/services/widgetConfigValidator.ts +10 -57
  39. 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
- if (!widget.chart) {
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: 'dataSource.resourceId',
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: 'dataSource.groupBy',
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
- if (!widget.query) {
53
- errors.push({
54
- field: 'query',
55
- message: 'Chart widget must have query or aggregate dataSource config',
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 legacyQuery = getLegacyQueryConfig(widget.query);
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, legacyQuery, options);
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 ?? legacyQuery?.order);
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 queryLimit = legacyQuery?.limit;
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 ?? legacyQuery?.select ?? Object.keys(rows[0] ?? {});
85
- const total = pagination ? Math.min(await resource.count(filters), queryLimit ?? Infinity) : 0;
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 getLegacyQueryConfig(query: unknown): DashboardWidgetQueryConfig | undefined {
139
- if (!isRecord(query) || typeof query.resource !== 'string') {
140
- return undefined;
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
- if (!legacyQuery) {
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 {