18
18
* under the License.
19
19
*/
20
20
21
- import { t } from '@superset-ui/core' ;
21
+ import { t , validateNonEmpty } from '@superset-ui/core' ;
22
22
import { SharedControlConfig } from '../types' ;
23
23
import { dndAdhocMetricControl } from './dndControls' ;
24
+ import { defineSavedMetrics } from '../utils' ;
24
25
25
26
/**
26
27
* Matrixify control definitions
27
28
* Controls for transforming charts into matrix/grid layouts
28
29
*/
29
30
31
+ // Utility function to check if matrixify controls should be visible
32
+ const isMatrixifyVisible = (
33
+ controls : any ,
34
+ axis : 'rows' | 'columns' ,
35
+ mode ?: 'metrics' | 'dimensions' ,
36
+ selectionMode ?: 'members' | 'topn' ,
37
+ ) => {
38
+ const layoutControl = `matrixify_enable_${ axis === 'rows' ? 'vertical' : 'horizontal' } _layout` ;
39
+ const modeControl = `matrixify_mode_${ axis } ` ;
40
+ const selectionModeControl = `matrixify_dimension_selection_mode_${ axis } ` ;
41
+
42
+ const isLayoutEnabled = controls ?. [ layoutControl ] ?. value === true ;
43
+
44
+ if ( ! isLayoutEnabled ) return false ;
45
+
46
+ if ( mode ) {
47
+ const isModeMatch = controls ?. [ modeControl ] ?. value === mode ;
48
+ if ( ! isModeMatch ) return false ;
49
+
50
+ if ( selectionMode && mode === 'dimensions' ) {
51
+ return controls ?. [ selectionModeControl ] ?. value === selectionMode ;
52
+ }
53
+ }
54
+
55
+ return true ;
56
+ } ;
57
+
30
58
// Initialize the controls object that will be populated dynamically
31
59
const matrixifyControls : Record < string , SharedControlConfig < any > > = { } ;
32
60
33
61
// Dynamically add axis-specific controls (rows and columns)
34
- [ 'columns' , 'rows' ] . forEach ( axisParam => {
35
- const axis = axisParam ; // Capture the value in a local variable
62
+ ( [ 'columns' , 'rows' ] as const ) . forEach ( axisParam => {
63
+ const axis : 'rows' | 'columns' = axisParam ;
36
64
37
65
matrixifyControls [ `matrixify_mode_${ axis } ` ] = {
38
66
type : 'RadioButtonControl' ,
@@ -43,17 +71,18 @@ const matrixifyControls: Record<string, SharedControlConfig<any>> = {};
43
71
[ 'dimensions' , t ( 'Dimension members' ) ] ,
44
72
] ,
45
73
renderTrigger : true ,
74
+ tabOverride : 'matrixify' ,
75
+ visibility : ( { controls } ) => isMatrixifyVisible ( controls , axis ) ,
46
76
} ;
47
77
48
78
matrixifyControls [ `matrixify_${ axis } ` ] = {
49
79
...dndAdhocMetricControl ,
50
80
label : t ( `Metrics` ) ,
51
81
multi : true ,
52
- validators : [ ] , // Not required
53
- // description: t(`Select metrics for ${axis}`),
82
+ validators : [ ] , // No validation - rely on visibility
54
83
renderTrigger : true ,
55
- visibility : ( { controls } ) =>
56
- controls ?. [ `matrixify_mode_ ${ axis } ` ] ?. value === 'metrics' ,
84
+ tabOverride : 'matrixify' ,
85
+ visibility : ( { controls } ) => isMatrixifyVisible ( controls , axis , 'metrics' ) ,
57
86
} ;
58
87
59
88
// Combined dimension and values control
@@ -62,8 +91,9 @@ const matrixifyControls: Record<string, SharedControlConfig<any>> = {};
62
91
label : t ( `Dimension selection` ) ,
63
92
description : t ( `Select dimension and values` ) ,
64
93
default : { dimension : '' , values : [ ] } ,
65
- validators : [ ] , // Not required
94
+ validators : [ ] , // No validation - rely on visibility
66
95
renderTrigger : true ,
96
+ tabOverride : 'matrixify' ,
67
97
shouldMapStateToProps : ( prevState , state ) => {
68
98
// Recalculate when any relevant form_data field changes
69
99
const fieldsToCheck = [
@@ -82,24 +112,40 @@ const matrixifyControls: Record<string, SharedControlConfig<any>> = {};
82
112
const getValue = ( key : string , defaultValue ?: any ) =>
83
113
form_data ?. [ key ] ?? controls ?. [ key ] ?. value ?? defaultValue ;
84
114
115
+ const selectionMode = getValue (
116
+ `matrixify_dimension_selection_mode_${ axis } ` ,
117
+ 'members' ,
118
+ ) ;
119
+
120
+ const isVisible = isMatrixifyVisible ( controls , axis , 'dimensions' ) ;
121
+
122
+ // Validate dimension is selected when visible
123
+ const dimensionValidator = ( value : any ) => {
124
+ if ( ! value ?. dimension ) {
125
+ return t ( 'Dimension is required' ) ;
126
+ }
127
+ return false ;
128
+ } ;
129
+
130
+ // Additional validation for topN mode
131
+ const validators = isVisible
132
+ ? [ dimensionValidator , validateNonEmpty ]
133
+ : [ ] ;
134
+
85
135
return {
86
136
datasource,
87
- selectionMode : getValue (
88
- `matrixify_dimension_selection_mode_${ axis } ` ,
89
- 'members' ,
90
- ) ,
137
+ selectionMode,
91
138
topNMetric : getValue ( `matrixify_topn_metric_${ axis } ` ) ,
92
139
topNValue : getValue ( `matrixify_topn_value_${ axis } ` ) ,
93
140
topNOrder : getValue ( `matrixify_topn_order_${ axis } ` ) ,
94
141
formData : form_data ,
142
+ validators,
95
143
} ;
96
144
} ,
97
145
visibility : ( { controls } ) =>
98
- controls ?. [ `matrixify_mode_ ${ axis } ` ] ?. value === 'dimensions' ,
146
+ isMatrixifyVisible ( controls , axis , 'dimensions' ) ,
99
147
} ;
100
148
101
- // Dimension picker for TopN mode (just dimension, no values)
102
- // NOTE: This is now handled by matrixify_dimension control, so hiding it
103
149
matrixifyControls [ `matrixify_topn_dimension_${ axis } ` ] = {
104
150
type : 'SelectControl' ,
105
151
label : t ( 'Dimension' ) ,
@@ -127,33 +173,67 @@ const matrixifyControls: Record<string, SharedControlConfig<any>> = {};
127
173
[ 'topn' , t ( 'Top n' ) ] ,
128
174
] ,
129
175
renderTrigger : true ,
176
+ tabOverride : 'matrixify' ,
130
177
visibility : ( { controls } ) =>
131
- controls ?. [ `matrixify_mode_ ${ axis } ` ] ?. value === 'dimensions' ,
178
+ isMatrixifyVisible ( controls , axis , 'dimensions' ) ,
132
179
} ;
133
180
134
181
// TopN controls
135
182
matrixifyControls [ `matrixify_topn_value_${ axis } ` ] = {
136
- type : 'TextControl ' ,
183
+ type : 'NumberControl ' ,
137
184
label : t ( `Number of top values` ) ,
138
185
description : t ( `How many top values to select` ) ,
139
186
default : 10 ,
140
187
isInt : true ,
188
+ validators : [ ] ,
189
+ renderTrigger : true ,
190
+ tabOverride : 'matrixify' ,
141
191
visibility : ( { controls } ) =>
142
- controls ?. [ `matrixify_mode_${ axis } ` ] ?. value === 'dimensions' &&
143
- controls ?. [ `matrixify_dimension_selection_mode_${ axis } ` ] ?. value ===
192
+ isMatrixifyVisible ( controls , axis , 'dimensions' , 'topn' ) ,
193
+ mapStateToProps : ( { controls } ) => {
194
+ const isVisible = isMatrixifyVisible (
195
+ controls ,
196
+ axis ,
197
+ 'dimensions' ,
144
198
'topn' ,
199
+ ) ;
200
+
201
+ return {
202
+ validators : isVisible ? [ validateNonEmpty ] : [ ] ,
203
+ } ;
204
+ } ,
145
205
} ;
146
206
147
207
matrixifyControls [ `matrixify_topn_metric_${ axis } ` ] = {
148
208
...dndAdhocMetricControl ,
149
209
label : t ( `Metric for ordering` ) ,
150
210
multi : false ,
151
- validators : [ ] , // Not required
211
+ validators : [ ] ,
152
212
description : t ( `Metric to use for ordering Top N values` ) ,
213
+ tabOverride : 'matrixify' ,
153
214
visibility : ( { controls } ) =>
154
- controls ?. [ `matrixify_mode_${ axis } ` ] ?. value === 'dimensions' &&
155
- controls ?. [ `matrixify_dimension_selection_mode_${ axis } ` ] ?. value ===
215
+ isMatrixifyVisible ( controls , axis , 'dimensions' , 'topn' ) ,
216
+ mapStateToProps : ( state , controlState ) => {
217
+ const { controls, datasource } = state ;
218
+ const isVisible = isMatrixifyVisible (
219
+ controls ,
220
+ axis ,
221
+ 'dimensions' ,
156
222
'topn' ,
223
+ ) ;
224
+
225
+ const originalProps =
226
+ dndAdhocMetricControl . mapStateToProps ?.( state , controlState ) || { } ;
227
+
228
+ return {
229
+ ...originalProps ,
230
+ columns : datasource ?. columns || [ ] ,
231
+ savedMetrics : defineSavedMetrics ( datasource ) ,
232
+ datasource,
233
+ datasourceType : datasource ?. type ,
234
+ validators : isVisible ? [ validateNonEmpty ] : [ ] ,
235
+ } ;
236
+ } ,
157
237
} ;
158
238
159
239
matrixifyControls [ `matrixify_topn_order_${ axis } ` ] = {
@@ -164,10 +244,10 @@ const matrixifyControls: Record<string, SharedControlConfig<any>> = {};
164
244
[ 'asc' , t ( 'Ascending' ) ] ,
165
245
[ 'desc' , t ( 'Descending' ) ] ,
166
246
] ,
247
+ renderTrigger : true ,
248
+ tabOverride : 'matrixify' ,
167
249
visibility : ( { controls } ) =>
168
- controls ?. [ `matrixify_mode_${ axis } ` ] ?. value === 'dimensions' &&
169
- controls ?. [ `matrixify_dimension_selection_mode_${ axis } ` ] ?. value ===
170
- 'topn' ,
250
+ isMatrixifyVisible ( controls , axis , 'dimensions' , 'topn' ) ,
171
251
} ;
172
252
} ) ;
173
253
@@ -213,15 +293,22 @@ matrixifyControls.matrixify_charts_per_row = {
213
293
! controls ?. matrixify_fit_columns_dynamically ?. value ,
214
294
} ;
215
295
216
- // Main enable control
217
- matrixifyControls . matrixify_enabled = {
296
+ matrixifyControls . matrixify_enable_vertical_layout = {
218
297
type : 'CheckboxControl' ,
219
- label : t ( 'Enable matrixify' ) ,
220
- description : t (
221
- 'Transform this chart into a matrix/grid of charts based on dimensions or metrics' ,
222
- ) ,
298
+ label : t ( 'Enable vertical layout (rows)' ) ,
299
+ description : t ( 'Create matrix rows by stacking charts vertically' ) ,
300
+ default : false ,
301
+ renderTrigger : true ,
302
+ tabOverride : 'matrixify' ,
303
+ } ;
304
+
305
+ matrixifyControls . matrixify_enable_horizontal_layout = {
306
+ type : 'CheckboxControl' ,
307
+ label : t ( 'Enable horizontal layout (columns)' ) ,
308
+ description : t ( 'Create matrix columns by placing charts side-by-side' ) ,
223
309
default : false ,
224
310
renderTrigger : true ,
311
+ tabOverride : 'matrixify' ,
225
312
} ;
226
313
227
314
// Cell title control for Matrixify
@@ -234,8 +321,8 @@ matrixifyControls.matrixify_cell_title_template = {
234
321
default : '' ,
235
322
renderTrigger : true ,
236
323
visibility : ( { controls } ) =>
237
- ( controls ?. matrixify_mode_rows ?. value ||
238
- controls ?. matrixify_mode_columns ?. value ) !== undefined ,
324
+ controls ?. matrixify_enable_vertical_layout ?. value === true ||
325
+ controls ?. matrixify_enable_horizontal_layout ?. value === true ,
239
326
} ;
240
327
241
328
// Matrix display controls
@@ -245,9 +332,9 @@ matrixifyControls.matrixify_show_row_labels = {
245
332
description : t ( 'Display labels for each row on the left side of the matrix' ) ,
246
333
default : true ,
247
334
renderTrigger : true ,
335
+ tabOverride : 'matrixify' ,
248
336
visibility : ( { controls } ) =>
249
- ( controls ?. matrixify_mode_rows ?. value ||
250
- controls ?. matrixify_mode_columns ?. value ) !== undefined ,
337
+ controls ?. matrixify_enable_vertical_layout ?. value === true ,
251
338
} ;
252
339
253
340
matrixifyControls . matrixify_show_column_headers = {
@@ -256,9 +343,9 @@ matrixifyControls.matrixify_show_column_headers = {
256
343
description : t ( 'Display headers for each column at the top of the matrix' ) ,
257
344
default : true ,
258
345
renderTrigger : true ,
346
+ tabOverride : 'matrixify' ,
259
347
visibility : ( { controls } ) =>
260
- ( controls ?. matrixify_mode_rows ?. value ||
261
- controls ?. matrixify_mode_columns ?. value ) !== undefined ,
348
+ controls ?. matrixify_enable_horizontal_layout ?. value === true ,
262
349
} ;
263
350
264
351
export { matrixifyControls } ;
0 commit comments