@cdc/dashboard 4.26.4 → 4.26.5

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 (91) hide show
  1. package/CONFIG.md +77 -30
  2. package/LICENSE +201 -0
  3. package/dist/cdcdashboard.js +49936 -49166
  4. package/examples/dashboard-conditions-filters-incomplete.json +221 -0
  5. package/examples/dashboard-missing-datasets-multi.json +174 -0
  6. package/examples/dashboard-missing-datasets-single.json +121 -0
  7. package/examples/dashboard-multi-dashboard-version-regression.json +146 -0
  8. package/examples/dashboard-shared-filter-row-delete-cleanup.json +186 -0
  9. package/examples/dashboard-stale-dataset-keys.json +181 -0
  10. package/examples/dashboard-tiered-filter-regression.json +190 -0
  11. package/examples/private/cfa-dashboard.json +651 -0
  12. package/examples/private/data-bite-wrap.json +6936 -0
  13. package/examples/private/multi-dash-fix.json +16963 -0
  14. package/examples/private/versions.json +41612 -0
  15. package/examples/us-map-filter-example.json +1074 -0
  16. package/package.json +9 -9
  17. package/src/CdcDashboard.tsx +6 -2
  18. package/src/CdcDashboardComponent.tsx +178 -87
  19. package/src/DashboardCopyPasteContext.test.tsx +33 -0
  20. package/src/DashboardCopyPasteContext.tsx +48 -0
  21. package/src/_stories/Dashboard.EditorRegression.stories.tsx +72 -0
  22. package/src/_stories/Dashboard.Regression.stories.tsx +196 -0
  23. package/src/_stories/Dashboard.Zoom.stories.tsx +88 -0
  24. package/src/_stories/Dashboard.stories.tsx +294 -0
  25. package/src/_stories/FilteredTextMigrationComparison.stories.tsx +87 -0
  26. package/src/components/Column.test.tsx +176 -0
  27. package/src/components/Column.tsx +214 -13
  28. package/src/components/DashboardConditionModal.test.tsx +420 -0
  29. package/src/components/DashboardConditionModal.tsx +367 -0
  30. package/src/components/DashboardConditionSummary.tsx +59 -0
  31. package/src/components/DashboardEditors.tsx +8 -0
  32. package/src/components/DashboardFilters/DashboardFilters.test.tsx +139 -1
  33. package/src/components/DashboardFilters/DashboardFilters.tsx +192 -174
  34. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.test.tsx +164 -0
  35. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +41 -2
  36. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.test.tsx +180 -3
  37. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +15 -32
  38. package/src/components/DashboardFilters/DashboardFiltersWrapper.test.tsx +142 -0
  39. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +32 -27
  40. package/src/components/DashboardFilters/dashboardfilter.styles.css +42 -27
  41. package/src/components/DataDesignerModal.tsx +2 -1
  42. package/src/components/Grid.tsx +8 -4
  43. package/src/components/Header/Header.tsx +36 -17
  44. package/src/components/Row.test.tsx +228 -0
  45. package/src/components/Row.tsx +93 -18
  46. package/src/components/VisualizationRow.test.tsx +396 -0
  47. package/src/components/VisualizationRow.tsx +110 -35
  48. package/src/components/VisualizationsPanel/VisualizationsPanel.test.tsx +49 -0
  49. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +14 -13
  50. package/src/components/Widget/Widget.test.tsx +218 -0
  51. package/src/components/Widget/Widget.tsx +119 -17
  52. package/src/components/Widget/widget.styles.css +31 -18
  53. package/src/components/dashboard-condition-modal.css +76 -0
  54. package/src/components/dashboard-condition-summary.css +87 -0
  55. package/src/helpers/addValuesToDashboardFilters.ts +3 -5
  56. package/src/helpers/addVisualization.ts +15 -4
  57. package/src/helpers/cloneDashboardWidget.ts +127 -0
  58. package/src/helpers/dashboardColumnWidgets.ts +99 -0
  59. package/src/helpers/dashboardConditionUi.ts +47 -0
  60. package/src/helpers/dashboardConditions.ts +200 -0
  61. package/src/helpers/dashboardFilterTargets.ts +156 -0
  62. package/src/helpers/filterData.ts +4 -9
  63. package/src/helpers/filterVisibility.ts +20 -0
  64. package/src/helpers/formatConfigBeforeSave.ts +2 -2
  65. package/src/helpers/getFilteredData.ts +18 -5
  66. package/src/helpers/getUpdateConfig.ts +43 -12
  67. package/src/helpers/getVizRowColumnLocator.ts +11 -1
  68. package/src/helpers/iconHash.tsx +9 -3
  69. package/src/helpers/mapDataToConfig.ts +31 -29
  70. package/src/helpers/reloadURLHelpers.ts +25 -5
  71. package/src/helpers/removeDashboardFilter.ts +33 -33
  72. package/src/helpers/tests/addVisualization.test.ts +53 -9
  73. package/src/helpers/tests/cloneDashboardWidget.test.ts +136 -0
  74. package/src/helpers/tests/dashboardColumnWidgets.test.ts +99 -0
  75. package/src/helpers/tests/dashboardConditionUi.test.ts +41 -0
  76. package/src/helpers/tests/dashboardConditions.test.ts +428 -0
  77. package/src/helpers/tests/formatConfigBeforeSave.test.ts +51 -0
  78. package/src/helpers/tests/getFilteredData.test.ts +265 -86
  79. package/src/helpers/tests/getUpdateConfig.test.ts +338 -0
  80. package/src/helpers/tests/reloadURLHelpers.test.ts +394 -238
  81. package/src/index.tsx +6 -3
  82. package/src/scss/grid.scss +249 -20
  83. package/src/scss/main.scss +108 -29
  84. package/src/store/dashboard.actions.ts +17 -4
  85. package/src/store/dashboard.reducer.test.ts +538 -0
  86. package/src/store/dashboard.reducer.ts +135 -22
  87. package/src/test/CdcDashboard.test.tsx +148 -0
  88. package/src/test/CdcDashboardComponent.test.tsx +935 -2
  89. package/src/types/ConfigRow.ts +15 -0
  90. package/src/types/DashboardFilters.ts +4 -0
  91. package/src/types/SharedFilter.ts +1 -0
@@ -0,0 +1,221 @@
1
+ {
2
+ "type": "dashboard",
3
+ "version": "4.26.4",
4
+ "dashboard": {
5
+ "theme": "theme-blue",
6
+ "title": "Dashboard Conditions: Incomplete Filters",
7
+ "titleStyle": "small",
8
+ "description": "<p>This example demonstrates the <code>filtersIncomplete</code>, <code>hasData</code>, and <code>hasNoData</code> dashboard condition operators with one shared filter.</p>",
9
+ "sharedFilters": [
10
+ {
11
+ "key": "County",
12
+ "label": "County",
13
+ "type": "datafilter",
14
+ "filterStyle": "dropdown",
15
+ "columnName": "county",
16
+ "showDropdown": true,
17
+ "resetLabel": "- Select a county -",
18
+ "active": "- Select a county -",
19
+ "values": ["Adams County", "Baker County", "Clark County"],
20
+ "orderedValues": ["Adams County", "Baker County", "Clark County"],
21
+ "usedBy": [
22
+ "condition-filters-incomplete",
23
+ "condition-county-has-data",
24
+ "condition-county-has-no-data",
25
+ "condition-row-has-data",
26
+ "condition-row-has-no-data"
27
+ ]
28
+ }
29
+ ]
30
+ },
31
+ "rows": [
32
+ {
33
+ "columns": [
34
+ {
35
+ "width": 12,
36
+ "widget": "dashboard-filters"
37
+ }
38
+ ],
39
+ "expandCollapseAllButtons": false
40
+ },
41
+ {
42
+ "columns": [
43
+ {
44
+ "width": 12,
45
+ "conditionalWidgets": [
46
+ {
47
+ "widget": "state-filters-incomplete",
48
+ "dashboardCondition": {
49
+ "id": "condition-filters-incomplete",
50
+ "operator": "filtersIncomplete"
51
+ }
52
+ },
53
+ {
54
+ "widget": "state-has-data",
55
+ "dashboardCondition": {
56
+ "id": "condition-county-has-data",
57
+ "datasetKey": "condition-demo-data",
58
+ "operator": "hasData"
59
+ }
60
+ },
61
+ {
62
+ "widget": "state-has-no-data",
63
+ "dashboardCondition": {
64
+ "id": "condition-county-has-no-data",
65
+ "datasetKey": "condition-demo-data",
66
+ "operator": "hasNoData"
67
+ }
68
+ }
69
+ ]
70
+ }
71
+ ],
72
+ "expandCollapseAllButtons": false
73
+ },
74
+ {
75
+ "dashboardCondition": {
76
+ "id": "condition-row-has-data",
77
+ "datasetKey": "condition-demo-data",
78
+ "operator": "hasData"
79
+ },
80
+ "columns": [
81
+ {
82
+ "width": 6,
83
+ "widget": "details-has-data-left"
84
+ },
85
+ {
86
+ "width": 6,
87
+ "widget": "details-has-data-right"
88
+ }
89
+ ],
90
+ "expandCollapseAllButtons": false
91
+ },
92
+ {
93
+ "dashboardCondition": {
94
+ "id": "condition-row-has-no-data",
95
+ "datasetKey": "condition-demo-data",
96
+ "operator": "hasNoData"
97
+ },
98
+ "columns": [
99
+ {
100
+ "width": 12,
101
+ "widget": "details-has-no-data"
102
+ }
103
+ ],
104
+ "expandCollapseAllButtons": false
105
+ }
106
+ ],
107
+ "visualizations": {
108
+ "dashboard-filters": {
109
+ "uid": "dashboard-filters",
110
+ "type": "dashboardFilters",
111
+ "visualizationType": "dashboardFilters",
112
+ "sharedFilterIndexes": [0],
113
+ "filterBehavior": "Filter Change",
114
+ "autoLoad": true
115
+ },
116
+ "state-filters-incomplete": {
117
+ "uid": "state-filters-incomplete",
118
+ "type": "markup-include",
119
+ "visualizationType": "markup-include",
120
+ "theme": "theme-blue",
121
+ "contentEditor": {
122
+ "inlineHTML": "<h2>Filters are incomplete</h2><p>This component is visible because its dashboard condition uses <code>operator: filtersIncomplete</code>.</p><p>The County filter is applicable to this condition id and is currently at its reset state. The hard-coded dashboard message is intentionally bypassed because this dashboard authored its own incomplete-filter state.</p>",
123
+ "showHeader": true,
124
+ "srcUrl": "",
125
+ "title": "Filters Incomplete State",
126
+ "useInlineHTML": true
127
+ }
128
+ },
129
+ "state-has-data": {
130
+ "uid": "state-has-data",
131
+ "type": "markup-include",
132
+ "visualizationType": "markup-include",
133
+ "theme": "theme-blue",
134
+ "contentEditor": {
135
+ "inlineHTML": "<h2>Filtered data exists</h2><p>This component is visible because the selected County has at least one matching row in <code>condition-demo-data</code>.</p><p>The neighboring incomplete-filter and no-data components are hidden because their conditions do not match.</p>",
136
+ "showHeader": true,
137
+ "srcUrl": "",
138
+ "title": "Has Data State",
139
+ "useInlineHTML": true
140
+ }
141
+ },
142
+ "state-has-no-data": {
143
+ "uid": "state-has-no-data",
144
+ "type": "markup-include",
145
+ "visualizationType": "markup-include",
146
+ "theme": "theme-blue",
147
+ "contentEditor": {
148
+ "inlineHTML": "<h2>No matching data</h2><p>This component is visible because the selected County has no matching rows in <code>condition-demo-data</code>.</p><p>This is different from the reset state: the filter is complete, the condition dataset is loaded, and <code>hasNoData</code> can safely render an authored no-results message.</p>",
149
+ "showHeader": true,
150
+ "srcUrl": "",
151
+ "title": "Has No Data State",
152
+ "useInlineHTML": true
153
+ }
154
+ },
155
+ "details-has-data-left": {
156
+ "uid": "details-has-data-left",
157
+ "type": "markup-include",
158
+ "visualizationType": "markup-include",
159
+ "theme": "theme-blue",
160
+ "contentEditor": {
161
+ "inlineHTML": "<h3>Row-level hasData condition</h3><p>This whole row appears only when <code>condition-row-has-data</code> passes.</p><p>It demonstrates that row-level conditions and component-level conditional widgets can use the same shared filter targeting model.</p>",
162
+ "showHeader": true,
163
+ "srcUrl": "",
164
+ "title": "Row Has Data Detail",
165
+ "useInlineHTML": true
166
+ }
167
+ },
168
+ "details-has-data-right": {
169
+ "uid": "details-has-data-right",
170
+ "type": "markup-include",
171
+ "visualizationType": "markup-include",
172
+ "theme": "theme-blue",
173
+ "contentEditor": {
174
+ "inlineHTML": "<h3>Why this row hides</h3><p>When the County filter is reset, this data-backed condition is unresolved and the row hides.</p><p>When Clark County is selected, the condition resolves with an empty filtered dataset, so <code>hasData</code> is false and this row hides.</p>",
175
+ "showHeader": true,
176
+ "srcUrl": "",
177
+ "title": "Has Data Hide Explanation",
178
+ "useInlineHTML": true
179
+ }
180
+ },
181
+ "details-has-no-data": {
182
+ "uid": "details-has-no-data",
183
+ "type": "markup-include",
184
+ "visualizationType": "markup-include",
185
+ "theme": "theme-blue",
186
+ "contentEditor": {
187
+ "inlineHTML": "<h3>Row-level hasNoData condition</h3><p>This row appears only when the County filter is complete and the filtered condition dataset is empty.</p><p>It stays hidden during reset because reset filters leave data-backed operators unresolved rather than pretending there is no data.</p>",
188
+ "showHeader": true,
189
+ "srcUrl": "",
190
+ "title": "Row Has No Data Detail",
191
+ "useInlineHTML": true
192
+ }
193
+ }
194
+ },
195
+ "datasets": {
196
+ "condition-demo-data": {
197
+ "data": [
198
+ {
199
+ "county": "Adams County",
200
+ "status": "Has data",
201
+ "value": 42
202
+ },
203
+ {
204
+ "county": "Baker County",
205
+ "status": "Has data",
206
+ "value": 27
207
+ }
208
+ ],
209
+ "dataFileName": "condition-demo-data.json",
210
+ "dataFileSourceType": "file",
211
+ "dataFileFormat": "JSON",
212
+ "preview": true
213
+ }
214
+ },
215
+ "table": {
216
+ "label": "Data Table",
217
+ "show": false,
218
+ "showDownloadUrl": false,
219
+ "showVertical": true
220
+ }
221
+ }
@@ -0,0 +1,174 @@
1
+ {
2
+ "type": "dashboard",
3
+ "version": "4.26.5",
4
+ "activeDashboard": 0,
5
+ "dashboard": {
6
+ "theme": "theme-blue",
7
+ "title": "Tab 1: Missing datasets"
8
+ },
9
+ "rows": [
10
+ {
11
+ "columns": [
12
+ {
13
+ "width": 12,
14
+ "widget": "multi-missing-markup"
15
+ }
16
+ ]
17
+ },
18
+ {
19
+ "columns": [
20
+ {
21
+ "width": 12,
22
+ "widget": "multi-missing-chart"
23
+ }
24
+ ]
25
+ }
26
+ ],
27
+ "visualizations": {
28
+ "multi-missing-markup": {
29
+ "uid": "multi-missing-markup",
30
+ "type": "markup-include",
31
+ "visualizationType": "markup-include",
32
+ "theme": "theme-blue",
33
+ "contentEditor": {
34
+ "title": "Tab 1",
35
+ "showHeader": true,
36
+ "srcUrl": "",
37
+ "useInlineHTML": true,
38
+ "inlineHTML": "<p>This tab has no datasets object entries for its chart.</p>"
39
+ }
40
+ },
41
+ "multi-missing-chart": {
42
+ "uid": "multi-missing-chart",
43
+ "type": "chart",
44
+ "visualizationType": "Bar",
45
+ "title": "Missing dataset key",
46
+ "dataKey": "missing-multi-dataset",
47
+ "xAxis": {
48
+ "dataKey": "Category"
49
+ },
50
+ "series": [
51
+ {
52
+ "dataKey": "Value"
53
+ }
54
+ ],
55
+ "theme": "theme-blue"
56
+ }
57
+ },
58
+ "datasets": {},
59
+ "multiDashboards": [
60
+ {
61
+ "label": "Missing Dataset",
62
+ "type": "dashboard",
63
+ "version": "4.26.5",
64
+ "dashboard": {
65
+ "theme": "theme-blue",
66
+ "title": "Tab 1: Missing datasets",
67
+ "description": "<p>This sub-dashboard has no datasets object entries at all.</p>"
68
+ },
69
+ "rows": [
70
+ {
71
+ "columns": [
72
+ {
73
+ "width": 12,
74
+ "widget": "multi-missing-markup"
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ "columns": [
80
+ {
81
+ "width": 12,
82
+ "widget": "multi-missing-chart"
83
+ }
84
+ ]
85
+ }
86
+ ],
87
+ "visualizations": {
88
+ "multi-missing-markup": {
89
+ "uid": "multi-missing-markup",
90
+ "type": "markup-include",
91
+ "visualizationType": "markup-include",
92
+ "theme": "theme-blue",
93
+ "contentEditor": {
94
+ "title": "Tab 1",
95
+ "showHeader": true,
96
+ "srcUrl": "",
97
+ "useInlineHTML": true,
98
+ "inlineHTML": "<p>This tab has no datasets object entries for its chart.</p>"
99
+ }
100
+ },
101
+ "multi-missing-chart": {
102
+ "uid": "multi-missing-chart",
103
+ "type": "chart",
104
+ "visualizationType": "Bar",
105
+ "title": "Missing dataset key",
106
+ "dataKey": "missing-multi-dataset",
107
+ "xAxis": {
108
+ "dataKey": "Category"
109
+ },
110
+ "series": [
111
+ {
112
+ "dataKey": "Value"
113
+ }
114
+ ],
115
+ "theme": "theme-blue"
116
+ }
117
+ },
118
+ "datasets": {}
119
+ },
120
+ {
121
+ "label": "Empty Dataset",
122
+ "type": "dashboard",
123
+ "version": "4.26.5",
124
+ "dashboard": {
125
+ "theme": "theme-blue",
126
+ "title": "Tab 2: Empty datasets",
127
+ "description": "<p>This sub-dashboard has a datasets object, but the dataset is empty.</p>"
128
+ },
129
+ "rows": [
130
+ {
131
+ "columns": [
132
+ {
133
+ "width": 12,
134
+ "widget": "multi-empty-chart"
135
+ }
136
+ ]
137
+ }
138
+ ],
139
+ "visualizations": {
140
+ "multi-empty-chart": {
141
+ "uid": "multi-empty-chart",
142
+ "type": "chart",
143
+ "visualizationType": "Bar",
144
+ "title": "Empty dataset key",
145
+ "dataKey": "empty-multi-dataset",
146
+ "xAxis": {
147
+ "dataKey": "Category"
148
+ },
149
+ "series": [
150
+ {
151
+ "dataKey": "Value"
152
+ }
153
+ ],
154
+ "theme": "theme-blue"
155
+ }
156
+ },
157
+ "datasets": {
158
+ "empty-multi-dataset": {
159
+ "data": [],
160
+ "preview": true,
161
+ "dataFileName": "empty-multi-dataset.json",
162
+ "dataFileSourceType": "file",
163
+ "dataFileFormat": "JSON"
164
+ }
165
+ }
166
+ }
167
+ ],
168
+ "table": {
169
+ "label": "Data Table",
170
+ "show": false,
171
+ "showDownloadUrl": false,
172
+ "showVertical": true
173
+ }
174
+ }
@@ -0,0 +1,121 @@
1
+ {
2
+ "type": "dashboard",
3
+ "version": "4.26.5",
4
+ "dashboard": {
5
+ "theme": "theme-blue",
6
+ "title": "Regression: Missing Datasets (Single Dashboard)",
7
+ "description": "<p>This fixture intentionally mixes a missing dataset key and an empty dataset so dashboard loading can skip dataset preparation safely.</p>"
8
+ },
9
+ "rows": [
10
+ {
11
+ "columns": [
12
+ {
13
+ "width": 12,
14
+ "widget": "intro-single-missing"
15
+ }
16
+ ]
17
+ },
18
+ {
19
+ "columns": [
20
+ {
21
+ "width": 6,
22
+ "widget": "chart-missing-dataset"
23
+ },
24
+ {
25
+ "width": 6,
26
+ "widget": "chart-empty-dataset"
27
+ }
28
+ ]
29
+ },
30
+ {
31
+ "dataKey": "missing-row-dataset",
32
+ "dataDescription": {
33
+ "horizontal": false,
34
+ "series": false
35
+ },
36
+ "columns": [
37
+ {
38
+ "width": 12,
39
+ "widget": "chart-row-missing-dataset"
40
+ }
41
+ ]
42
+ }
43
+ ],
44
+ "visualizations": {
45
+ "intro-single-missing": {
46
+ "uid": "intro-single-missing",
47
+ "type": "markup-include",
48
+ "visualizationType": "markup-include",
49
+ "theme": "theme-blue",
50
+ "contentEditor": {
51
+ "title": "Fixture notes",
52
+ "showHeader": true,
53
+ "srcUrl": "",
54
+ "useInlineHTML": true,
55
+ "inlineHTML": "<p><strong>Expected:</strong> the dashboard loads without crashing even though one viz points at a missing dataset, one viz points at an empty dataset, and one row points at a missing dataset.</p>"
56
+ }
57
+ },
58
+ "chart-missing-dataset": {
59
+ "uid": "chart-missing-dataset",
60
+ "type": "chart",
61
+ "visualizationType": "Bar",
62
+ "title": "Missing dataset",
63
+ "dataKey": "missing-dataset",
64
+ "xAxis": {
65
+ "dataKey": "Category"
66
+ },
67
+ "series": [
68
+ {
69
+ "dataKey": "Value"
70
+ }
71
+ ],
72
+ "theme": "theme-blue"
73
+ },
74
+ "chart-empty-dataset": {
75
+ "uid": "chart-empty-dataset",
76
+ "type": "chart",
77
+ "visualizationType": "Bar",
78
+ "title": "Empty dataset",
79
+ "dataKey": "empty-dataset",
80
+ "xAxis": {
81
+ "dataKey": "Category"
82
+ },
83
+ "series": [
84
+ {
85
+ "dataKey": "Value"
86
+ }
87
+ ],
88
+ "theme": "theme-blue"
89
+ },
90
+ "chart-row-missing-dataset": {
91
+ "uid": "chart-row-missing-dataset",
92
+ "type": "chart",
93
+ "visualizationType": "Bar",
94
+ "title": "Row with missing dataset",
95
+ "xAxis": {
96
+ "dataKey": "Category"
97
+ },
98
+ "series": [
99
+ {
100
+ "dataKey": "Value"
101
+ }
102
+ ],
103
+ "theme": "theme-blue"
104
+ }
105
+ },
106
+ "datasets": {
107
+ "empty-dataset": {
108
+ "data": [],
109
+ "preview": true,
110
+ "dataFileName": "empty-dataset.json",
111
+ "dataFileSourceType": "file",
112
+ "dataFileFormat": "JSON"
113
+ }
114
+ },
115
+ "table": {
116
+ "label": "Data Table",
117
+ "show": false,
118
+ "showDownloadUrl": false,
119
+ "showVertical": true
120
+ }
121
+ }
@@ -0,0 +1,146 @@
1
+ {
2
+ "type": "dashboard",
3
+ "version": "4.25.0",
4
+ "activeDashboard": 0,
5
+ "dashboard": {
6
+ "theme": "theme-blue",
7
+ "title": "Sub-dashboard keeps its own version"
8
+ },
9
+ "rows": [
10
+ {
11
+ "columns": [
12
+ {
13
+ "width": 12,
14
+ "widget": "versioned-subdash-markup"
15
+ }
16
+ ]
17
+ }
18
+ ],
19
+ "visualizations": {
20
+ "versioned-subdash-markup": {
21
+ "uid": "versioned-subdash-markup",
22
+ "type": "markup-include",
23
+ "visualizationType": "markup-include",
24
+ "theme": "theme-blue",
25
+ "contentEditor": {
26
+ "title": "Versioned sub-dashboard",
27
+ "showHeader": true,
28
+ "srcUrl": "",
29
+ "useInlineHTML": true,
30
+ "inlineHTML": "<p>This top-level copy mirrors the first sub-dashboard so the multi-dashboard loader can open tab 1 immediately.</p>"
31
+ }
32
+ }
33
+ },
34
+ "datasets": {},
35
+ "multiDashboards": [
36
+ {
37
+ "label": "Explicit Version",
38
+ "type": "dashboard",
39
+ "version": "4.26.2",
40
+ "dashboard": {
41
+ "theme": "theme-blue",
42
+ "title": "Sub-dashboard keeps its own version",
43
+ "description": "<p>This tab already has its own version. It should not fall back to the parent version.</p>"
44
+ },
45
+ "rows": [
46
+ {
47
+ "columns": [
48
+ {
49
+ "width": 12,
50
+ "widget": "versioned-subdash-markup"
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ "columns": [
56
+ {
57
+ "width": 12,
58
+ "widget": "versioned-subdash-chart"
59
+ }
60
+ ]
61
+ }
62
+ ],
63
+ "visualizations": {
64
+ "versioned-subdash-markup": {
65
+ "uid": "versioned-subdash-markup",
66
+ "type": "markup-include",
67
+ "visualizationType": "markup-include",
68
+ "theme": "theme-blue",
69
+ "contentEditor": {
70
+ "title": "Explicit version",
71
+ "showHeader": true,
72
+ "srcUrl": "",
73
+ "useInlineHTML": true,
74
+ "inlineHTML": "<p>Because this sub-dashboard is already at <code>4.26.2</code>, older migrations should not rerun on each load.</p>"
75
+ }
76
+ },
77
+ "versioned-subdash-chart": {
78
+ "uid": "versioned-subdash-chart",
79
+ "type": "chart",
80
+ "visualizationType": "Bar",
81
+ "title": "Brush should remain if version is respected",
82
+ "xAxis": {
83
+ "dataKey": "Category"
84
+ },
85
+ "series": [
86
+ {
87
+ "dataKey": "Value"
88
+ }
89
+ ],
90
+ "brush": {
91
+ "enabled": true
92
+ },
93
+ "data": [
94
+ {
95
+ "Category": "A",
96
+ "Value": 1
97
+ },
98
+ {
99
+ "Category": "B",
100
+ "Value": 2
101
+ }
102
+ ],
103
+ "theme": "theme-blue"
104
+ }
105
+ },
106
+ "datasets": {}
107
+ },
108
+ {
109
+ "label": "Fallback Version",
110
+ "type": "dashboard",
111
+ "dashboard": {
112
+ "theme": "theme-blue",
113
+ "title": "Sub-dashboard receives fallback version",
114
+ "description": "<p>This tab intentionally omits its own version. It should inherit the parent version during worker processing and then retain a stamped version so migrations do not rerun on every reload.</p>"
115
+ },
116
+ "rows": [
117
+ {
118
+ "columns": [
119
+ {
120
+ "width": 12,
121
+ "widget": "fallback-subdash-markup"
122
+ }
123
+ ]
124
+ }
125
+ ],
126
+ "visualizations": {
127
+ "fallback-subdash-markup": {
128
+ "uid": "fallback-subdash-markup",
129
+ "type": "markup-include",
130
+ "visualizationType": "markup-include",
131
+ "contentEditor": {
132
+ "title": "Fallback version tab"
133
+ },
134
+ "theme": "theme-blue"
135
+ }
136
+ },
137
+ "datasets": {}
138
+ }
139
+ ],
140
+ "table": {
141
+ "label": "Data Table",
142
+ "show": false,
143
+ "showDownloadUrl": false,
144
+ "showVertical": true
145
+ }
146
+ }