|
1 | 1 | // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. |
2 | 2 |
|
3 | | -import type { Dashboard } from '@objectstack/spec/ui'; |
| 3 | +import type { ChartConfig, ChartType, Dashboard } from '@objectstack/spec/ui'; |
4 | 4 |
|
5 | 5 | const taskDs = 'showcase_task_metrics'; |
6 | 6 | const projectDs = 'showcase_project_metrics'; |
7 | 7 |
|
| 8 | +/** Axis fields name the dataset's dimension/measure — query rows are keyed by |
| 9 | + * measure NAME post-cutover, never the base column (issue #1721). */ |
| 10 | +const cfg = (type: ChartType, dimension: string, measure: string): ChartConfig => ({ |
| 11 | + type, |
| 12 | + xAxis: { field: dimension, showGridLines: true, logarithmic: false }, |
| 13 | + yAxis: [{ field: measure, showGridLines: true, logarithmic: false }], |
| 14 | + showLegend: true, |
| 15 | + showDataLabels: false, |
| 16 | +}); |
| 17 | + |
8 | 18 | /** |
9 | 19 | * Chart Gallery — one widget per chart family the dashboard renderer can draw |
10 | 20 | * DISTINCTLY, so the showcase honestly reflects what the platform implements. |
@@ -34,26 +44,26 @@ export const ChartGalleryDashboard: Dashboard = { |
34 | 44 | { id: 'kpi_total_spent', type: 'metric', title: 'Total Spent', dataset: projectDs, values: ['spent_sum'], layout: { x: 8, y: 0, w: 4, h: 2 } }, |
35 | 45 |
|
36 | 46 | // ── Comparison ───────────────────────────────────────────────────────── |
37 | | - { id: 'bar_by_status', type: 'bar', title: 'Tasks by Status', dataset: taskDs, dimensions: ['status'], values: ['task_count'], layout: { x: 0, y: 2, w: 4, h: 4 } }, |
38 | | - { id: 'column_by_priority', type: 'column', title: 'Tasks by Priority', dataset: taskDs, dimensions: ['priority'], values: ['task_count'], layout: { x: 4, y: 2, w: 4, h: 4 } }, |
39 | | - { id: 'hbar_hours', type: 'horizontal-bar', title: 'Hours by Status', dataset: taskDs, dimensions: ['status'], values: ['est_hours'], layout: { x: 8, y: 2, w: 4, h: 4 } }, |
| 47 | + { id: 'bar_by_status', type: 'bar', title: 'Tasks by Status', dataset: taskDs, dimensions: ['status'], values: ['task_count'], chartConfig: cfg('bar', 'status', 'task_count'), layout: { x: 0, y: 2, w: 4, h: 4 } }, |
| 48 | + { id: 'column_by_priority', type: 'column', title: 'Tasks by Priority', dataset: taskDs, dimensions: ['priority'], values: ['task_count'], chartConfig: cfg('column', 'priority', 'task_count'), layout: { x: 4, y: 2, w: 4, h: 4 } }, |
| 49 | + { id: 'hbar_hours', type: 'horizontal-bar', title: 'Hours by Status', dataset: taskDs, dimensions: ['status'], values: ['est_hours'], chartConfig: cfg('horizontal-bar', 'status', 'est_hours'), layout: { x: 8, y: 2, w: 4, h: 4 } }, |
40 | 50 |
|
41 | 51 | // ── Trend (month-bucketed via the dataset's created_at granularity) ────── |
42 | | - { id: 'line_created', type: 'line', title: 'Tasks Created (monthly)', dataset: taskDs, dimensions: ['created_at'], values: ['task_count'], layout: { x: 0, y: 6, w: 6, h: 4 } }, |
43 | | - { id: 'area_created', type: 'area', title: 'Tasks Created (area)', dataset: taskDs, dimensions: ['created_at'], values: ['task_count'], layout: { x: 6, y: 6, w: 6, h: 4 } }, |
| 52 | + { id: 'line_created', type: 'line', title: 'Tasks Created (monthly)', dataset: taskDs, dimensions: ['created_at'], values: ['task_count'], chartConfig: cfg('line', 'created_at', 'task_count'), layout: { x: 0, y: 6, w: 6, h: 4 } }, |
| 53 | + { id: 'area_created', type: 'area', title: 'Tasks Created (area)', dataset: taskDs, dimensions: ['created_at'], values: ['task_count'], chartConfig: cfg('area', 'created_at', 'task_count'), layout: { x: 6, y: 6, w: 6, h: 4 } }, |
44 | 54 |
|
45 | 55 | // ── Distribution ───────────────────────────────────────────────────────── |
46 | | - { id: 'pie_status', type: 'pie', title: 'Status Split', dataset: taskDs, dimensions: ['status'], values: ['task_count'], layout: { x: 0, y: 10, w: 4, h: 4 } }, |
47 | | - { id: 'donut_priority', type: 'donut', title: 'Priority Split', dataset: taskDs, dimensions: ['priority'], values: ['task_count'], layout: { x: 4, y: 10, w: 4, h: 4 } }, |
48 | | - { id: 'funnel_status', type: 'funnel', title: 'Status Funnel', dataset: taskDs, dimensions: ['status'], values: ['task_count'], layout: { x: 8, y: 10, w: 4, h: 4 } }, |
| 56 | + { id: 'pie_status', type: 'pie', title: 'Status Split', dataset: taskDs, dimensions: ['status'], values: ['task_count'], chartConfig: cfg('pie', 'status', 'task_count'), layout: { x: 0, y: 10, w: 4, h: 4 } }, |
| 57 | + { id: 'donut_priority', type: 'donut', title: 'Priority Split', dataset: taskDs, dimensions: ['priority'], values: ['task_count'], chartConfig: cfg('donut', 'priority', 'task_count'), layout: { x: 4, y: 10, w: 4, h: 4 } }, |
| 58 | + { id: 'funnel_status', type: 'funnel', title: 'Status Funnel', dataset: taskDs, dimensions: ['status'], values: ['task_count'], chartConfig: cfg('funnel', 'status', 'task_count'), layout: { x: 8, y: 10, w: 4, h: 4 } }, |
49 | 59 |
|
50 | 60 | // ── Relationship + Advanced ────────────────────────────────────────────── |
51 | | - { id: 'scatter_estimate', type: 'scatter', title: 'Estimate vs Progress', dataset: taskDs, dimensions: ['progress'], values: ['avg_estimate'], layout: { x: 0, y: 14, w: 6, h: 4 } }, |
52 | | - { id: 'radar_priority', type: 'radar', title: 'Priority Radar', dataset: taskDs, dimensions: ['priority'], values: ['task_count'], layout: { x: 6, y: 14, w: 6, h: 4 } }, |
| 61 | + { id: 'scatter_estimate', type: 'scatter', title: 'Estimate vs Progress', dataset: taskDs, dimensions: ['progress'], values: ['avg_estimate'], chartConfig: cfg('scatter', 'progress', 'avg_estimate'), layout: { x: 0, y: 14, w: 6, h: 4 } }, |
| 62 | + { id: 'radar_priority', type: 'radar', title: 'Priority Radar', dataset: taskDs, dimensions: ['priority'], values: ['task_count'], chartConfig: cfg('radar', 'priority', 'task_count'), layout: { x: 6, y: 14, w: 6, h: 4 } }, |
53 | 63 |
|
54 | 64 | // ── Composition ────────────────────────────────────────────────────────── |
55 | | - { id: 'treemap_hours', type: 'treemap', title: 'Hours Treemap', dataset: taskDs, dimensions: ['status'], values: ['est_hours'], layout: { x: 0, y: 18, w: 6, h: 4 } }, |
56 | | - { id: 'sankey_flow', type: 'sankey', title: 'Status Flow (Sankey)', dataset: taskDs, dimensions: ['status'], values: ['task_count'], layout: { x: 6, y: 18, w: 6, h: 4 } }, |
| 65 | + { id: 'treemap_hours', type: 'treemap', title: 'Hours Treemap', dataset: taskDs, dimensions: ['status'], values: ['est_hours'], chartConfig: cfg('treemap', 'status', 'est_hours'), layout: { x: 0, y: 18, w: 6, h: 4 } }, |
| 66 | + { id: 'sankey_flow', type: 'sankey', title: 'Status Flow (Sankey)', dataset: taskDs, dimensions: ['status'], values: ['task_count'], chartConfig: cfg('sankey', 'status', 'task_count'), layout: { x: 6, y: 18, w: 6, h: 4 } }, |
57 | 67 |
|
58 | 68 | // ── Tabular (real grouped tables, multiple measures) ───────────────────── |
59 | 69 | { id: 'table_projects', type: 'table', title: 'Projects by Account', dataset: projectDs, dimensions: ['account'], values: ['project_count', 'budget_sum', 'spent_sum'], layout: { x: 0, y: 22, w: 6, h: 4 } }, |
|
0 commit comments