@@ -68,7 +68,7 @@ type Props = {
68
68
/** Scale up the grid? [default: 1] */
69
69
scale ?: number
70
70
71
- grids : GridSpec [ ]
71
+ grids : ( null | GridSpec ) [ ]
72
72
}
73
73
74
74
type State = {
@@ -95,9 +95,12 @@ type State = {
95
95
}
96
96
97
97
type GridProps = {
98
+ /** Position of legend w.r.t. the grid UI [default: "below"] */
99
+ legendPosition ?: "right" | "below"
100
+
98
101
scale : Props [ "scale" ]
99
- title : Props [ "grids" ] [ number ] [ "title" ]
100
- states : Props [ "grids" ] [ number ] [ "states" ]
102
+ title : NonNullable < Props [ "grids" ] [ number ] > [ "title" ]
103
+ states : NonNullable < Props [ "grids" ] [ number ] > [ "states" ]
101
104
workers : State [ "workers" ] [ number ]
102
105
}
103
106
@@ -136,6 +139,8 @@ class Grid extends React.PureComponent<GridProps> {
136
139
}
137
140
138
141
private get emptyCell ( ) : TextProps {
142
+ // TODO in light terminal themes, white-dim is a better choice
143
+ // than gray-dim
139
144
return this . cellFor ( { color : "gray" , dimColor : true } )
140
145
}
141
146
@@ -199,16 +204,20 @@ class Grid extends React.PureComponent<GridProps> {
199
204
return (
200
205
< Box flexDirection = "column" >
201
206
{ A . filter ( Boolean ) . map ( ( AA , ridx ) => (
207
+ /* legend row */
202
208
< Box key = { ridx } flexDirection = "row" justifyContent = "space-around" >
203
209
{ AA . filter ( Boolean ) . map ( ( _ , cidx ) => (
210
+ /* legend entry (i.e. legend column) */
204
211
< Box key = { _ . state } { ...outerBoxProps } >
205
212
< Box { ...innerBoxProps } marginLeft = { 1 } >
213
+ { /* legend entry label */ }
206
214
< Box >
207
215
< Text { ..._ . style } bold >
208
216
{ _ . state }
209
217
</ Text >
210
218
</ Box >
211
219
220
+ { /* legend entry value */ }
212
221
< Box { ...valueProps } >
213
222
< Text { ..._ . style } > { C [ ridx ] [ cidx ] /*.toString().padStart(maxLen)*/ } </ Text >
214
223
</ Box >
@@ -250,22 +259,45 @@ class Grid extends React.PureComponent<GridProps> {
250
259
return < Text > { this . props . title } </ Text >
251
260
}
252
261
262
+ private get legendPosition ( ) {
263
+ return this . props . legendPosition
264
+ }
265
+
253
266
public render ( ) {
267
+ const flexDirection = this . legendPosition === "below" ? "column" : "row"
268
+ const alignItems = this . legendPosition === "below" ? "center" : "center"
269
+ const legendBoxProps = this . legendPosition === "below" ? { marginTop : 1 } : { marginLeft : 2 }
270
+
254
271
return (
255
- < Box flexDirection = "column" alignItems = "center" justifyContent = "center" paddingTop = { 1 } paddingBottom = { 1 } >
256
- { this . title ( ) }
257
- { this . grid ( ) }
258
- < Box marginTop = { 1 } > { this . legend ( ) } </ Box >
272
+ < Box
273
+ flexDirection = { flexDirection }
274
+ alignItems = { alignItems }
275
+ justifyContent = "center"
276
+ paddingTop = { 1 }
277
+ paddingBottom = { 1 }
278
+ >
279
+ { /* title and grid */ }
280
+ < Box flexDirection = "column" alignItems = "center" >
281
+ { this . title ( ) }
282
+ { this . grid ( ) }
283
+ </ Box >
284
+
285
+ { /* legend */ }
286
+ < Box { ...legendBoxProps } > { this . legend ( ) } </ Box >
259
287
</ Box >
260
288
)
261
289
}
262
290
}
263
291
264
292
export default class Dashboard extends React . PureComponent < Props , State > {
293
+ private get grids ( ) : GridSpec [ ] {
294
+ return this . props . grids . filter ( ( _ ) => _ !== null ) as GridSpec [ ]
295
+ }
296
+
265
297
public componentDidMount ( ) {
266
298
this . setState ( {
267
299
workers : [ ] ,
268
- watchers : this . props . grids . map ( ( props , gridIdx ) =>
300
+ watchers : this . grids . map ( ( props , gridIdx ) =>
269
301
props . initWatcher ( ( model : UpdatePayload ) => this . onUpdate ( gridIdx , model ) )
270
302
) ,
271
303
agoInterval : setInterval ( ( ) => this . setState ( ( curState ) => ( { iter : ( curState ?. iter || 0 ) + 1 } ) ) , 5 * 1000 ) ,
@@ -388,26 +420,47 @@ export default class Dashboard extends React.PureComponent<Props, State> {
388
420
// eslint-disable-next-line no-control-regex
389
421
rows . push ( < Text key = { line + "-" + n } > { line . replace ( / \x1b \x5B \[ 2 J / g, "" ) } </ Text > )
390
422
}
391
- return < React . Fragment > { rows } </ React . Fragment >
423
+ return (
424
+ < Box marginTop = { 1 } flexDirection = "column" >
425
+ { rows }
426
+ </ Box >
427
+ )
428
+ }
429
+ }
430
+
431
+ private gridRows ( ) {
432
+ const rows : { widx : number ; grid : NonNullable < Props [ "grids" ] [ number ] > } [ ] [ ] = [ ]
433
+ for ( let idx = 0 , ridx = 0 , widx = 0 ; idx < this . props . grids . length ; idx ++ ) {
434
+ const grid = this . props . grids [ idx ]
435
+ if ( grid === null ) {
436
+ ridx ++
437
+ } else {
438
+ if ( ! rows [ ridx ] ) {
439
+ rows [ ridx ] = [ ]
440
+ }
441
+ rows [ ridx ] . push ( { grid, widx : widx ++ } )
442
+ }
392
443
}
444
+ return rows
393
445
}
394
446
395
447
private body ( ) {
396
- return (
397
- < Box justifyContent = "space-around" >
398
- { this . props . grids . map ( ( props , idx ) => (
399
- < Box key = { props . title } marginLeft = { 2 } >
448
+ return this . gridRows ( ) . map ( ( row , ridx ) => (
449
+ < Box key = { ridx } justifyContent = "space-around" >
450
+ { row . map ( ( { grid , widx } ) => (
451
+ < Box key = { grid . title } marginLeft = { 2 } >
400
452
< Grid
401
- key = { props . title }
402
- title = { props . title }
453
+ key = { grid . title }
454
+ title = { grid . title }
403
455
scale = { this . props . scale }
404
- states = { props . states }
405
- workers = { this . state ?. workers [ idx ] || [ ] }
456
+ states = { grid . states }
457
+ workers = { this . state ?. workers [ widx ] || [ ] }
458
+ legendPosition = { row . length === 1 ? "right" : "below" }
406
459
/>
407
460
</ Box >
408
461
) ) }
409
462
</ Box >
410
- )
463
+ ) )
411
464
}
412
465
413
466
public render ( ) {
0 commit comments