@adminforth/dashboard 1.1.0 → 1.3.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 (55) hide show
  1. package/README.md +43 -52
  2. package/custom/composables/useElementSize.ts +17 -2
  3. package/custom/model/dashboard.types.ts +385 -98
  4. package/custom/runtime/DashboardRuntime.vue +2 -1
  5. package/custom/runtime/WidgetRenderer.vue +2 -1
  6. package/custom/skills/adminforth-dashboard/SKILL.md +8 -4
  7. package/custom/widgets/chart/ChartWidget.vue +36 -35
  8. package/custom/widgets/chart/bar/BarChart.vue +20 -12
  9. package/custom/widgets/chart/chart.types.ts +42 -8
  10. package/custom/widgets/chart/chart.utils.ts +11 -0
  11. package/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
  12. package/custom/widgets/chart/line/LineChart.vue +23 -15
  13. package/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
  14. package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -43
  15. package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -10
  16. package/custom/widgets/pivot-table/PivotTableWidget.vue +10 -11
  17. package/custom/widgets/table/TableWidget.vue +9 -4
  18. package/dist/custom/composables/useElementSize.js +14 -2
  19. package/dist/custom/composables/useElementSize.ts +17 -2
  20. package/dist/custom/model/dashboard.types.d.ts +179 -38
  21. package/dist/custom/model/dashboard.types.js +108 -42
  22. package/dist/custom/model/dashboard.types.ts +385 -98
  23. package/dist/custom/queries/useDashboardConfig.d.ts +832 -68
  24. package/dist/custom/queries/useWidgetData.d.ts +828 -64
  25. package/dist/custom/runtime/DashboardRuntime.vue +2 -1
  26. package/dist/custom/runtime/WidgetRenderer.vue +2 -1
  27. package/dist/custom/skills/adminforth-dashboard/SKILL.md +8 -4
  28. package/dist/custom/widgets/chart/ChartWidget.vue +36 -35
  29. package/dist/custom/widgets/chart/bar/BarChart.vue +20 -12
  30. package/dist/custom/widgets/chart/chart.types.d.ts +14 -8
  31. package/dist/custom/widgets/chart/chart.types.js +23 -0
  32. package/dist/custom/widgets/chart/chart.types.ts +42 -8
  33. package/dist/custom/widgets/chart/chart.utils.d.ts +1 -0
  34. package/dist/custom/widgets/chart/chart.utils.js +7 -0
  35. package/dist/custom/widgets/chart/chart.utils.ts +11 -0
  36. package/dist/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
  37. package/dist/custom/widgets/chart/line/LineChart.vue +23 -15
  38. package/dist/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
  39. package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -43
  40. package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -10
  41. package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +10 -11
  42. package/dist/custom/widgets/table/TableWidget.vue +9 -4
  43. package/dist/endpoint/widgets.js +23 -3
  44. package/dist/schema/api.d.ts +2637 -933
  45. package/dist/schema/widget.d.ts +1562 -582
  46. package/dist/schema/widget.js +207 -127
  47. package/dist/services/widgetConfigValidator.js +16 -80
  48. package/dist/services/widgetDataService.d.ts +0 -9
  49. package/dist/services/widgetDataService.js +356 -97
  50. package/endpoint/dashboard.ts +1 -1
  51. package/endpoint/widgets.ts +29 -3
  52. package/package.json +1 -1
  53. package/schema/widget.ts +221 -121
  54. package/services/widgetConfigValidator.ts +29 -100
  55. package/services/widgetDataService.ts +478 -129
package/README.md CHANGED
@@ -30,79 +30,70 @@ Each widget has common fields:
30
30
  | `target` | Widget type: `table`, `chart`, `kpi_card`, `pivot_table`, or `gauge_card`. |
31
31
  | `order` | Widget order inside its group. |
32
32
  | `size` | Preset width: `small`, `medium`, `large`, `wide`, or `full`. |
33
- | `width`, `height`, `minWidth`, `maxWidth` | Optional explicit layout constraints. |
34
- | `dataSource` | Optional resource or aggregate data source definition. |
35
- | `query` | Optional AdminForth resource query used to load widget data. |
33
+ | `width`, `height`, `min_width`, `max_width` | Optional explicit layout constraints. |
34
+ | `query` | Data query definition. |
36
35
 
37
36
  ## Widget Support Matrix
38
37
 
39
38
  | Widget target | Config field | Main settings | Data usage |
40
39
  | --- | --- | --- | --- |
41
- | `table` | `table` | `columns`, `pagination`, `pageSize` | Uses `dataSource.type = 'resource'` or legacy `query` to display resource rows with backend pagination unless `pagination` is `false`. |
42
- | `chart` | `chart` | `type`, `x_field`, `y_field`, `label_field`, `value_field`, `bucket_field`, `buckets`, `series`, `series_name`, `color`, `colors` | Supports legacy `query` or `dataSource.type = 'aggregate'` with `groupBy`. |
43
- | `kpi_card` | `kpi_card` | `value_field`, `label_field`, `prefix`, `suffix` | Reads the first row or aggregate values and formats one numeric value. |
44
- | `gauge_card` | `gauge_card` | `value_field`, `min`, `max`, `min_field`, `max_field`, `suffix`, `color` | Reads the first row or aggregate values and renders progress between static or field-driven bounds. |
45
- | `pivot_table` | `pivot_table` | `row_field`, `column_field`, `value_field`, `aggregation` | Supports legacy row-based queries and grouped aggregate rows. `aggregation` supports `count` and `sum`. |
40
+ | `table` | `table` | `pagination`, `page_size`, `columns` | Uses `query` to display raw or aggregate rows. |
41
+ | `chart` | `chart` | `type`, `x`, `y`, `label`, `value`, `series`, `buckets`, `color`, `colors` | Uses `query`; funnel charts use `query.steps`. |
42
+ | `kpi_card` | `card` | `value`, `subtitle`, `comparison`, `sparkline` | Reads the first returned query row. |
43
+ | `gauge_card` | `card` | `value`, `target`, `progress`, `color` | Reads the first returned query row. |
44
+ | `pivot_table` | `pivot` | `rows`, `columns`, `values` | Uses query rows to build a pivot table. |
46
45
 
47
46
  Chart widget types:
48
47
 
49
48
  | Chart type | Notes |
50
49
  | --- | --- |
51
- | `line` | Uses `x_field` and `y_field`; optional `series_name` and `color`. |
52
- | `pie` | Uses `label_field` and optional `value_field`; without `value_field`, rows are counted by label. |
53
- | `bar` | Uses `label_field` and `value_field`, or `bucket_field` with `buckets`. |
54
- | `stacked_bar` | Uses `x_field` and `series`; if `series` is omitted, non-x columns become series. |
55
- | `funnel` | Uses `label_field`, `value_field`, and optional `colors`. |
56
- | `histogram` | Uses the same bucket settings as `bar`. |
50
+ | `line` | Uses `x` and `y`; `y` may contain multiple fields in config. |
51
+ | `pie` | Uses `label` and `value`. |
52
+ | `bar` | Uses `x` and `y`. |
53
+ | `stacked_bar` | Uses `x`, `y`, and `series`. |
54
+ | `funnel` | Uses `query.steps` and optional `label`, `value`, `colors`. |
55
+ | `histogram` | Uses `x`, `y`, and optional `buckets`. |
57
56
 
58
57
  ## Query Shape
59
58
 
60
59
  ```ts
61
- type DashboardWidgetQuery = {
60
+ type QueryConfig = {
62
61
  resource: string
63
- select?: string[]
64
- order?: {
65
- field: string
66
- direction: 'asc' | 'desc'
67
- }
62
+ select?: Array<
63
+ | { field: string; as?: string; grain?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' }
64
+ | { agg: 'sum' | 'count' | 'count_distinct' | 'avg' | 'min' | 'max' | 'median'; field?: string; as: string; filters?: unknown }
65
+ | { calc: string; as: string }
66
+ >
67
+ filters?: unknown
68
+ group_by?: Array<string | { field: string; as?: string; grain?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'; timezone?: string }>
69
+ order_by?: Array<{ field: string; direction?: 'asc' | 'desc' }>
68
70
  limit?: number
71
+ offset?: number
69
72
  }
70
73
  ```
71
74
 
72
- `resource` is an AdminForth `resourceId`. The query is executed through AdminForth resources, so widgets use the same resource contracts as the rest of the application.
73
-
74
- ## Data Source Shape
75
-
76
- ```ts
77
- type WidgetDataSource =
78
- | {
79
- type: 'resource'
80
- resourceId: string
81
- columns?: string[]
82
- filters?: unknown
83
- sort?: unknown
84
- }
85
- | {
86
- type: 'aggregate'
87
- resourceId: string
88
- aggregations: Record<string, {
89
- operation: 'sum' | 'count' | 'avg' | 'min' | 'max' | 'median'
90
- field?: string
91
- }>
92
- groupBy?:
93
- | { type: 'field'; field: string }
94
- | {
95
- type: 'date_trunc'
96
- field: string
97
- truncation: 'day' | 'week' | 'month' | 'year'
98
- timezone?: string
99
- }
100
- filters?: unknown
101
- }
75
+ Funnel charts use a steps query:
76
+
77
+ ```yaml
78
+ target: chart
79
+ chart:
80
+ type: funnel
81
+ title: Sales funnel
82
+ query:
83
+ steps:
84
+ - name: Leads
85
+ resource: leads
86
+ metric:
87
+ agg: count
88
+ as: value
89
+ - name: Customers
90
+ resource: orders
91
+ metric:
92
+ agg: count_distinct
93
+ field: customer_id
94
+ as: value
102
95
  ```
103
96
 
104
- `query` remains supported for backwards compatibility. When both are present, widgets prefer `dataSource`.
105
-
106
97
  ## Runtime Structure
107
98
 
108
99
  ```text
@@ -13,6 +13,7 @@ export function useElementSize<T extends HTMLElement>(): ElementSizeState<T> {
13
13
  const height = ref(0)
14
14
 
15
15
  let observer: ResizeObserver | undefined
16
+ let frameId: number | undefined
16
17
 
17
18
  onMounted(() => {
18
19
  observer = new ResizeObserver(([entry]) => {
@@ -20,8 +21,18 @@ export function useElementSize<T extends HTMLElement>(): ElementSizeState<T> {
20
21
  return
21
22
  }
22
23
 
23
- width.value = Math.floor(entry.contentRect.width)
24
- height.value = Math.floor(entry.contentRect.height)
24
+ const nextWidth = Math.floor(entry.contentRect.width)
25
+ const nextHeight = Math.floor(entry.contentRect.height)
26
+
27
+ if (frameId !== undefined) {
28
+ cancelAnimationFrame(frameId)
29
+ }
30
+
31
+ frameId = requestAnimationFrame(() => {
32
+ frameId = undefined
33
+ width.value = nextWidth
34
+ height.value = nextHeight
35
+ })
25
36
  })
26
37
 
27
38
  if (el.value) {
@@ -30,6 +41,10 @@ export function useElementSize<T extends HTMLElement>(): ElementSizeState<T> {
30
41
  })
31
42
 
32
43
  onBeforeUnmount(() => {
44
+ if (frameId !== undefined) {
45
+ cancelAnimationFrame(frameId)
46
+ }
47
+
33
48
  observer?.disconnect()
34
49
  })
35
50