@adminforth/dashboard 1.2.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 (50) hide show
  1. package/README.md +47 -39
  2. package/custom/composables/useElementSize.ts +17 -2
  3. package/custom/model/dashboard.types.ts +327 -234
  4. package/custom/skills/adminforth-dashboard/SKILL.md +6 -2
  5. package/custom/widgets/chart/ChartWidget.vue +23 -55
  6. package/custom/widgets/chart/bar/BarChart.vue +20 -12
  7. package/custom/widgets/chart/chart.types.ts +17 -66
  8. package/custom/widgets/chart/chart.utils.ts +11 -0
  9. package/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
  10. package/custom/widgets/chart/line/LineChart.vue +23 -15
  11. package/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
  12. package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -12
  13. package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
  14. package/custom/widgets/pivot-table/PivotTableWidget.vue +8 -7
  15. package/custom/widgets/table/TableWidget.vue +8 -3
  16. package/dist/custom/composables/useElementSize.js +14 -2
  17. package/dist/custom/composables/useElementSize.ts +17 -2
  18. package/dist/custom/model/dashboard.types.d.ts +178 -61
  19. package/dist/custom/model/dashboard.types.js +67 -92
  20. package/dist/custom/model/dashboard.types.ts +327 -234
  21. package/dist/custom/queries/useDashboardConfig.d.ts +832 -66
  22. package/dist/custom/queries/useWidgetData.d.ts +828 -62
  23. package/dist/custom/skills/adminforth-dashboard/SKILL.md +6 -2
  24. package/dist/custom/widgets/chart/ChartWidget.vue +23 -55
  25. package/dist/custom/widgets/chart/bar/BarChart.vue +20 -12
  26. package/dist/custom/widgets/chart/chart.types.d.ts +13 -22
  27. package/dist/custom/widgets/chart/chart.types.js +2 -25
  28. package/dist/custom/widgets/chart/chart.types.ts +17 -66
  29. package/dist/custom/widgets/chart/chart.utils.d.ts +1 -0
  30. package/dist/custom/widgets/chart/chart.utils.js +7 -0
  31. package/dist/custom/widgets/chart/chart.utils.ts +11 -0
  32. package/dist/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
  33. package/dist/custom/widgets/chart/line/LineChart.vue +23 -15
  34. package/dist/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
  35. package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -12
  36. package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
  37. package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +8 -7
  38. package/dist/custom/widgets/table/TableWidget.vue +8 -3
  39. package/dist/endpoint/widgets.js +5 -2
  40. package/dist/schema/api.d.ts +2680 -736
  41. package/dist/schema/widget.d.ts +1588 -476
  42. package/dist/schema/widget.js +205 -139
  43. package/dist/services/widgetConfigValidator.js +16 -40
  44. package/dist/services/widgetDataService.js +359 -82
  45. package/endpoint/dashboard.ts +1 -1
  46. package/endpoint/widgets.ts +5 -2
  47. package/package.json +1 -1
  48. package/schema/widget.ts +222 -139
  49. package/services/widgetConfigValidator.ts +29 -53
  50. package/services/widgetDataService.ts +484 -100
package/README.md CHANGED
@@ -31,60 +31,68 @@ Each widget has common fields:
31
31
  | `order` | Widget order inside its group. |
32
32
  | `size` | Preset width: `small`, `medium`, `large`, `wide`, or `full`. |
33
33
  | `width`, `height`, `min_width`, `max_width` | Optional explicit layout constraints. |
34
- | `data_source` | Resource or aggregate data source definition. |
34
+ | `query` | Data query definition. |
35
35
 
36
36
  ## Widget Support Matrix
37
37
 
38
38
  | Widget target | Config field | Main settings | Data usage |
39
39
  | --- | --- | --- | --- |
40
- | `table` | `table` | `pagination`, `page_size` | Uses `data_source.type = 'resource'` to display resource rows with backend pagination unless `pagination` is `false`. |
41
- | `chart` | `chart` | `type`, `x_field`, `y_field`, `label_field`, `value_field`, `bucket_field`, `buckets`, `series`, `series_name`, `color`, `colors` | Uses `data_source.type = 'aggregate'` with `group_by`. |
42
- | `kpi_card` | `kpi_card` | `value_field`, `label_field`, `prefix`, `suffix` | Reads aggregate values or the first returned row from `data_source`. |
43
- | `gauge_card` | `gauge_card` | `value_field`, `min`, `max`, `min_field`, `max_field`, `suffix`, `color` | Reads aggregate values or the first returned row from `data_source` and renders progress between static or field-driven bounds. |
44
- | `pivot_table` | `pivot_table` | `row_field`, `column_field`, `value_field`, `aggregation` | Uses grouped aggregate rows from `data_source.type = 'aggregate'`. `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. |
45
45
 
46
46
  Chart widget types:
47
47
 
48
48
  | Chart type | Notes |
49
49
  | --- | --- |
50
- | `line` | Uses `x_field` and `y_field`; optional `series_name` and `color`. |
51
- | `pie` | Uses `label_field` and optional `value_field`; without `value_field`, rows are counted by label. |
52
- | `bar` | Uses `label_field` and `value_field`, or `bucket_field` with `buckets`. |
53
- | `stacked_bar` | Uses `x_field` and `series`; if `series` is omitted, non-x columns become series. |
54
- | `funnel` | Uses `label_field`, `value_field`, and optional `colors`. |
55
- | `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`. |
56
56
 
57
- ## Data Source Shape
57
+ ## Query Shape
58
58
 
59
59
  ```ts
60
- type WidgetDataSource =
61
- | {
62
- type: 'resource'
63
- resource_id: string
64
- columns?: string[]
65
- filters?: unknown
66
- sort?: unknown
67
- }
68
- | {
69
- type: 'aggregate'
70
- resource_id: string
71
- aggregations: Record<string, {
72
- operation: 'sum' | 'count' | 'avg' | 'min' | 'max' | 'median'
73
- field?: string
74
- }>
75
- group_by?:
76
- | { type: 'field'; field: string }
77
- | {
78
- type: 'date_trunc'
79
- field: string
80
- truncation: 'day' | 'week' | 'month' | 'year'
81
- timezone?: string
82
- }
83
- filters?: unknown
84
- }
60
+ type QueryConfig = {
61
+ resource: string
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' }>
70
+ limit?: number
71
+ offset?: number
72
+ }
85
73
  ```
86
74
 
87
- `resource_id` is an AdminForth `resourceId`. The data source is executed through AdminForth resources, so widgets use the same resource contracts as the rest of the application.
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
95
+ ```
88
96
 
89
97
  ## Runtime Structure
90
98
 
@@ -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