@@ -15,7 +15,8 @@ import {
15
15
Tooltip ,
16
16
ButtonGroup ,
17
17
useTheme ,
18
- SxProps
18
+ SxProps ,
19
+ Button
19
20
} from '@mui/material' ;
20
21
21
22
import { VegaLite } from 'react-vega'
@@ -32,6 +33,7 @@ import AddchartIcon from '@mui/icons-material/Addchart';
32
33
import StarIcon from '@mui/icons-material/Star' ;
33
34
import SouthIcon from '@mui/icons-material/South' ;
34
35
import TableRowsIcon from '@mui/icons-material/TableRowsOutlined' ;
36
+ import AnchorIcon from '@mui/icons-material/Anchor' ;
35
37
import PanoramaFishEyeIcon from '@mui/icons-material/PanoramaFishEye' ;
36
38
import InsightsIcon from '@mui/icons-material/Insights' ;
37
39
@@ -43,7 +45,6 @@ import 'prismjs/components/prism-python' // Language
43
45
import 'prismjs/components/prism-typescript' // Language
44
46
import 'prismjs/themes/prism.css' ; //Example style, you can use another
45
47
46
-
47
48
import { chartAvailabilityCheck , generateChartSkeleton , getDataTable } from './VisualizationView' ;
48
49
import { TriggerCard } from './EncodingShelfCard' ;
49
50
@@ -78,12 +79,11 @@ let SingleThreadView: FC<{
78
79
usedTableIds, // tables that have been used
79
80
sx
80
81
} ) {
81
- let theme = useTheme ( ) ;
82
-
83
82
let tables = useSelector ( ( state : DataFormulatorState ) => state . tables ) ;
84
83
let charts = useSelector ( ( state : DataFormulatorState ) => state . charts ) ;
85
84
let focusedChartId = useSelector ( ( state : DataFormulatorState ) => state . focusedChartId ) ;
86
85
let focusedTableId = useSelector ( ( state : DataFormulatorState ) => state . focusedTableId ) ;
86
+ const theme = useTheme ( ) ;
87
87
88
88
let focusedChart = charts . find ( c => c . id == focusedChartId ) ;
89
89
@@ -95,13 +95,18 @@ let SingleThreadView: FC<{
95
95
96
96
let content : any = ""
97
97
98
+ let originTableIdOfThread = undefined ;
98
99
let tableIdList = [ leafTable . id ]
99
100
let triggerCards : any [ ] = [ ]
100
101
let triggers = getTriggers ( leafTable , tables ) ;
101
102
102
103
if ( leafTable . derive ) {
103
104
let firstNewTableIndex = triggers . findIndex ( tg => ! usedTableIds . includes ( tg . tableId ) ) ;
104
105
firstNewTableIndex = firstNewTableIndex == - 1 ? triggers . length : firstNewTableIndex ;
106
+
107
+ if ( firstNewTableIndex - 1 > 0 ) {
108
+ originTableIdOfThread = triggers [ 0 ] . tableId ;
109
+ }
105
110
triggers = firstNewTableIndex > 0 ? triggers . slice ( firstNewTableIndex - 1 ) : triggers ;
106
111
107
112
tableIdList = [ ...triggers . map ( ( trigger ) => trigger . tableId ) , leafTable . id ] ;
@@ -135,8 +140,42 @@ let SingleThreadView: FC<{
135
140
} ) ;
136
141
}
137
142
138
- // the thread is focused if the focused chart is in this table
139
- let threadIsFocused = focusedChart && tableIdList . includes ( focusedChart . tableRef ) && ! usedTableIds . includes ( focusedChart . tableRef ) ;
143
+
144
+ const findTableIdsBetweenAnchors = ( tableIds : string [ ] , tables : DictTable [ ] , focusedTableId ?: string ) : string [ ] => {
145
+ if ( ! focusedTableId ) return [ ] ;
146
+
147
+ // Find the index of the focused table
148
+ const focusedIndex = tableIds . indexOf ( focusedTableId ) ;
149
+ if ( focusedIndex === - 1 ) return [ ] ;
150
+
151
+ // Find anchored tables or boundaries
152
+ let startIndex = 0 ;
153
+ let endIndex = tableIds . length - 1 ;
154
+
155
+ // Search backward for an anchored table or start
156
+ for ( let i = focusedIndex ; i >= 0 ; i -- ) {
157
+ const table = tables . find ( t => t . id === tableIds [ i ] ) ;
158
+ if ( table ?. anchored ) {
159
+ startIndex = i ;
160
+ break ;
161
+ }
162
+ }
163
+
164
+ // Search forward for an anchored table or end
165
+ for ( let i = focusedIndex ; i < tableIds . length ; i ++ ) {
166
+ const table = tables . find ( t => t . id === tableIds [ i ] ) ;
167
+ if ( table ?. anchored ) {
168
+ endIndex = i ;
169
+ break ;
170
+ }
171
+ }
172
+
173
+ // Return the slice of tableIds between anchors
174
+ return tableIds . slice ( startIndex , endIndex + 1 ) ;
175
+ } ;
176
+
177
+ // Find tableIds between anchored tables that include the focused table
178
+ let tableIdsBetweenAnchors = findTableIdsBetweenAnchors ( originTableIdOfThread ? [ originTableIdOfThread , ...tableIdList ] : tableIdList , tables , focusedTableId ) ;
140
179
141
180
let tableList = tableIdList . map ( ( tableId , i ) => {
142
181
// filter charts relavent to this
@@ -159,17 +198,6 @@ let SingleThreadView: FC<{
159
198
// only charts without dependency can be deleted
160
199
let tableDeleteEnabled = ! tables . some ( t => t . derive ?. trigger . tableId == tableId ) ;
161
200
162
- let colloapsedTableBox = < div style = { { padding : 0 } } >
163
- < Box sx = { { textTransform : 'none' , padding : 0 , minWidth : 0 , color : 'gray' } } >
164
- < Stack direction = "row" sx = { { fontSize : '12px' , fontWeight : tableId == focusedTableId ? 'bold' : 'normal' } } alignItems = "center" gap = { "2px" } >
165
- < TableRowsIcon fontSize = "inherit" sx = { { fontWeight : 'inherit' } } />
166
- < Typography sx = { { fontSize : '12px' , fontWeight : 'inherit' } } >
167
- { tableId }
168
- </ Typography >
169
- </ Stack >
170
- </ Box >
171
- </ div > ;
172
-
173
201
let regularTableBox = < div ref = { relevantCharts . some ( c => c . chartId == focusedChartId ) ? scrollRef : null } style = { { padding : '0px' } } >
174
202
< Card className = { `data-thread-card ${ selectedClassName } ` } variant = "outlined"
175
203
sx = { { width : '100%' , background : 'aliceblue' } }
@@ -187,12 +215,27 @@ let SingleThreadView: FC<{
187
215
}
188
216
} } >
189
217
< Box sx = { { margin : '0px' , display : 'flex' } } >
190
- < Stack direction = "row" sx = { { marginLeft : 1 , marginRight : 'auto' , fontSize : 12 } } alignItems = "center" gap = { "2px" } >
191
- < TableRowsIcon sx = { { color : 'darkgray' , width : '14px' , height : '14px' } } />
218
+ < Stack direction = "row" sx = { { marginLeft : 0.5 , marginRight : 'auto' , fontSize : 12 } } alignItems = "center" gap = { "2px" } >
219
+ < IconButton color = "primary" sx = { {
220
+ minWidth : 0 ,
221
+ padding : 0.25 ,
222
+ '&:hover' : {
223
+ transform : 'scale(1.2)' ,
224
+ transition : 'all 0.2s ease'
225
+ }
226
+ } }
227
+ size = "small"
228
+ disabled = { table ?. derive == undefined }
229
+ onClick = { ( event ) => {
230
+ event . stopPropagation ( ) ;
231
+ dispatch ( dfActions . updateTableAnchored ( { tableId : tableId , anchored : ! table ?. anchored } ) ) ;
232
+ } } >
233
+ { table ?. anchored ? < AnchorIcon sx = { { fontSize : 18 } } /> : < TableRowsIcon sx = { { fontSize : 18 } } /> }
234
+ </ IconButton >
192
235
< Box sx = { { margin : '4px 8px 4px 2px' } } >
193
236
< Typography fontSize = "inherit" sx = { {
194
237
textAlign : 'center' ,
195
- color : 'rgba(0,0,0,0.7)' ,
238
+ color : 'rgba(0,0,0,0.7)' ,
196
239
maxWidth : '100px' ,
197
240
wordWrap : 'break-word' ,
198
241
whiteSpace : 'normal'
@@ -201,7 +244,10 @@ let SingleThreadView: FC<{
201
244
</ Stack >
202
245
< ButtonGroup aria-label = "Basic button group" variant = "text" sx = { { textAlign : 'end' , margin : "auto 2px auto auto" } } >
203
246
{ tableDeleteEnabled && < Tooltip title = "delete table" >
204
- < IconButton aria-label = "share" size = "small" sx = { { padding : '2px' } } >
247
+ < IconButton aria-label = "share" size = "small" sx = { { padding : 0.25 , '&:hover' : {
248
+ transform : 'scale(1.2)' ,
249
+ transition : 'all 0.2s ease'
250
+ } } } >
205
251
< DeleteIcon fontSize = "small" sx = { { fontSize : 18 } } color = 'warning'
206
252
onClick = { ( event ) => {
207
253
event . stopPropagation ( ) ;
@@ -210,7 +256,10 @@ let SingleThreadView: FC<{
210
256
</ IconButton >
211
257
</ Tooltip > }
212
258
< Tooltip title = "create a new chart" >
213
- < IconButton aria-label = "share" size = "small" sx = { { padding : '2px' } } >
259
+ < IconButton aria-label = "share" size = "small" sx = { { padding : 0.25 , '&:hover' : {
260
+ transform : 'scale(1.2)' ,
261
+ transition : 'all 0.2s ease'
262
+ } } } >
214
263
< AddchartIcon fontSize = "small" sx = { { fontSize : 18 } } color = 'primary'
215
264
onClick = { ( event ) => {
216
265
event . stopPropagation ( ) ;
@@ -230,19 +279,18 @@ let SingleThreadView: FC<{
230
279
< Box
231
280
key = { `table-${ tableId } ` }
232
281
sx = { { display : 'flex' , flexDirection : 'row' } } >
233
- < div style = { {
282
+ < Box sx = { {
234
283
minWidth : '1px' , padding : '0px' , width : '8px' , flex : 'none' , display : 'flex' ,
235
- marginLeft : '8px' ,
236
- borderLeft : '1px dashed darkgray' ,
284
+ marginLeft : tableIdsBetweenAnchors . includes ( tableId ) ? '7px' : '8px' ,
285
+ borderLeft : tableIdsBetweenAnchors . includes ( tableId ) ?
286
+ `3px solid ${ theme . palette . primary . light } ` : '1px dashed darkgray' ,
237
287
} } >
238
288
< Box sx = { {
239
289
padding : 0 , width : '1px' , margin : 'auto' ,
240
- //borderLeft: 'thin solid lightgray',
241
- // the following for
242
290
backgroundImage : 'linear-gradient(180deg, darkgray, darkgray 75%, transparent 75%, transparent 100%)' ,
243
291
backgroundSize : '1px 6px, 3px 100%'
244
292
} } > </ Box >
245
- </ div >
293
+ </ Box >
246
294
< Box sx = { { flex : 1 , padding : '8px 0px' , minHeight : '8px' , ...chartElementProps } } >
247
295
{ releventChartElements }
248
296
</ Box >
@@ -271,6 +319,16 @@ let SingleThreadView: FC<{
271
319
</ Divider >
272
320
</ Box >
273
321
< div style = { { padding : '2px 4px 2px 4px' , marginTop : 0 , marginBottom : '8px' , direction : 'ltr' } } >
322
+ { originTableIdOfThread && < Box sx = { { direction : 'ltr' } } >
323
+ < Typography sx = { { ml : 0.25 , fontSize : "10px" , color : 'text.secondary' , textTransform : 'none' } } >
324
+ { `${ originTableIdOfThread } ` }
325
+ </ Typography >
326
+ < Box sx = { {
327
+ height : '14px' ,
328
+ ml : 1 ,
329
+ borderLeft : tableIdsBetweenAnchors . includes ( originTableIdOfThread ) ? `3px solid ${ theme . palette . primary . light } ` : `1px dashed rgba(0, 0, 0, 0.3)`
330
+ } } > </ Box >
331
+ </ Box > }
274
332
{ content }
275
333
</ div >
276
334
</ Box >
0 commit comments