1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
4
- import { createAsyncThunk , createSlice , PayloadAction } from '@reduxjs/toolkit'
4
+ import { createAsyncThunk , createSlice , PayloadAction , createSelector } from '@reduxjs/toolkit'
5
5
import { Channel , Chart , ChartTemplate , EncodingItem , EncodingMap , FieldItem , Trigger } from '../components/ComponentType'
6
6
import { enableMapSet } from 'immer' ;
7
7
import { DictTable } from "../components/ComponentType" ;
@@ -16,14 +16,15 @@ import { handleSSEMessage } from './SSEActions';
16
16
17
17
enableMapSet ( ) ;
18
18
19
- export const generateFreshChart = ( tableRef : string , chartType ?: string ) : Chart => {
19
+ export const generateFreshChart = ( tableRef : string , chartType ?: string , source : "user" | "trigger" = "user" ) : Chart => {
20
20
let realChartType = chartType || "?"
21
21
return {
22
22
id : `chart-${ Date . now ( ) - Math . floor ( Math . random ( ) * 10000 ) } ` ,
23
23
chartType : realChartType ,
24
24
encodingMap : Object . assign ( { } , ...getChartChannels ( realChartType ) . map ( ( channel ) => ( { [ channel ] : { channel : channel , bin : false } } ) ) ) ,
25
25
tableRef : tableRef ,
26
- saved : false
26
+ saved : false ,
27
+ source : source ,
27
28
}
28
29
}
29
30
@@ -69,7 +70,6 @@ export interface DataFormulatorState {
69
70
70
71
focusedTableId : string | undefined ;
71
72
focusedChartId : string | undefined ;
72
- activeThreadChartId : string | undefined ; // specifying which chartThread is actively viewed
73
73
74
74
chartSynthesisInProgress : string [ ] ;
75
75
@@ -111,7 +111,6 @@ const initialState: DataFormulatorState = {
111
111
112
112
focusedTableId : undefined ,
113
113
focusedChartId : undefined ,
114
- activeThreadChartId : undefined ,
115
114
116
115
chartSynthesisInProgress : [ ] ,
117
116
@@ -128,27 +127,20 @@ const initialState: DataFormulatorState = {
128
127
}
129
128
130
129
let getUnrefedDerivedTableIds = ( state : DataFormulatorState ) => {
131
-
132
130
// find tables directly referred by charts
133
- let chartRefedTables = state . charts . map ( chart => getDataTable ( chart , state . tables , state . charts , state . conceptShelfItems ) ) ;
134
-
135
- // find tables referred via triggers
136
- let triggerRefedTableIds = chartRefedTables . filter ( t => t . derive != undefined ) . map ( t => t . derive ?. trigger as Trigger ) ;
131
+ let allCharts = dfSelectors . getAllCharts ( state ) ;
132
+ let chartRefedTables = allCharts . map ( chart => getDataTable ( chart , state . tables , allCharts , state . conceptShelfItems ) ) . map ( t => t . id ) ;
137
133
138
- let allRefedTableIds = [ ...chartRefedTables . map ( t => t . id ) , ...triggerRefedTableIds ] ;
139
-
140
- return state . tables . filter ( table => table . derive && ! allRefedTableIds . includes ( table . id ) ) . map ( t => t . id ) ;
134
+ return state . tables . filter ( table => table . derive && ! chartRefedTables . includes ( table . id ) ) . map ( t => t . id ) ;
141
135
}
142
136
143
137
let deleteChartsRoutine = ( state : DataFormulatorState , chartIds : string [ ] ) => {
144
138
let charts = state . charts . filter ( c => ! chartIds . includes ( c . id ) ) ;
145
139
let focusedChartId = state . focusedChartId ;
146
- let activeThreadChartId = state . activeThreadChartId ;
147
140
148
141
if ( focusedChartId && chartIds . includes ( focusedChartId ) ) {
149
- let leafCharts = charts . filter ( c => c . intermediate == undefined ) ;
142
+ let leafCharts = charts ;
150
143
focusedChartId = leafCharts . length > 0 ? leafCharts [ 0 ] . id : undefined ;
151
- activeThreadChartId = focusedChartId ;
152
144
153
145
state . focusedTableId = charts . find ( c => c . id == focusedChartId ) ?. tableRef ;
154
146
}
@@ -157,14 +149,10 @@ let deleteChartsRoutine = (state: DataFormulatorState, chartIds: string[]) => {
157
149
// update focusedChart and activeThreadChart
158
150
state . charts = charts ;
159
151
state . focusedChartId = focusedChartId ;
160
- state . activeThreadChartId = activeThreadChartId ;
161
152
162
153
let unrefedDerivedTableIds = getUnrefedDerivedTableIds ( state ) ;
163
154
let tableIdsToDelete = state . tables . filter ( t => ! t . anchored && unrefedDerivedTableIds . includes ( t . id ) ) . map ( t => t . id ) ;
164
-
165
155
state . tables = state . tables . filter ( t => ! tableIdsToDelete . includes ( t . id ) ) ;
166
- // remove intermediate charts that lead to this table
167
- state . charts = state . charts . filter ( c => ! ( c . intermediate && tableIdsToDelete . includes ( c . intermediate . resultTableId ) ) ) ;
168
156
}
169
157
170
158
export const fetchFieldSemanticType = createAsyncThunk (
@@ -289,7 +277,6 @@ export const dataFormulatorSlice = createSlice({
289
277
290
278
state . focusedTableId = undefined ;
291
279
state . focusedChartId = undefined ;
292
- state . activeThreadChartId = undefined ;
293
280
294
281
state . chartSynthesisInProgress = [ ] ;
295
282
@@ -318,7 +305,6 @@ export const dataFormulatorSlice = createSlice({
318
305
319
306
state . focusedTableId = savedState . focusedTableId || undefined ;
320
307
state . focusedChartId = savedState . focusedChartId || undefined ;
321
- state . activeThreadChartId = savedState . activeThreadChartId || undefined ;
322
308
323
309
state . chartSynthesisInProgress = [ ] ;
324
310
@@ -360,7 +346,6 @@ export const dataFormulatorSlice = createSlice({
360
346
361
347
state . focusedTableId = table . id ;
362
348
state . focusedChartId = undefined ;
363
- state . activeThreadChartId = undefined ;
364
349
} ,
365
350
deleteTable : ( state , action : PayloadAction < string > ) => {
366
351
let tableId = action . payload ;
@@ -372,9 +357,6 @@ export const dataFormulatorSlice = createSlice({
372
357
// delete charts that refer to this table and intermediate charts that produce this table
373
358
let chartIdsToDelete = state . charts . filter ( c => c . tableRef == tableId ) . map ( c => c . id ) ;
374
359
deleteChartsRoutine ( state , chartIdsToDelete ) ;
375
-
376
- // separate this, so that we only delete on tier of table a time
377
- state . charts = state . charts . filter ( c => ! ( c . intermediate && c . intermediate . resultTableId == tableId ) ) ;
378
360
} ,
379
361
updateTableAnchored : ( state , action : PayloadAction < { tableId : string , anchored : boolean } > ) => {
380
362
let tableId = action . payload . tableId ;
@@ -456,15 +438,15 @@ export const dataFormulatorSlice = createSlice({
456
438
createNewChart : ( state , action : PayloadAction < { chartType ?: string , tableId ?: string } > ) => {
457
439
let chartType = action . payload . chartType ;
458
440
let tableId = action . payload . tableId || state . tables [ 0 ] . id ;
459
- let freshChart = generateFreshChart ( tableId , chartType ) as Chart ;
441
+ let freshChart = generateFreshChart ( tableId , chartType , "user" ) as Chart ;
460
442
state . charts = [ freshChart , ...state . charts ] ;
461
443
state . focusedTableId = tableId ;
462
444
state . focusedChartId = freshChart . id ;
463
- state . activeThreadChartId = freshChart . id ;
464
445
} ,
465
- addChart : ( state , action : PayloadAction < Chart > ) => {
446
+ addAndFocusChart : ( state , action : PayloadAction < Chart > ) => {
466
447
let chart = action . payload ;
467
- state . charts = [ chart , ...state . charts ]
448
+ state . charts = [ chart , ...state . charts ] ;
449
+ state . focusedChartId = chart . id ;
468
450
} ,
469
451
duplicateChart : ( state , action : PayloadAction < string > ) => {
470
452
let chartId = action . payload ;
@@ -516,7 +498,8 @@ export const dataFormulatorSlice = createSlice({
516
498
let chartId = action . payload . chartId ;
517
499
let chart = state . charts . find ( c => c . id == chartId ) as Chart ;
518
500
let table = action . payload . table ;
519
- let currentTableRef = getDataTable ( chart , state . tables , state . charts , state . conceptShelfItems ) . id ;
501
+ let allCharts = dfSelectors . getAllCharts ( state ) ;
502
+ let currentTableRef = getDataTable ( chart , state . tables , allCharts , state . conceptShelfItems ) . id ;
520
503
state . charts = state . charts . map ( c => {
521
504
if ( c . id == chartId ) {
522
505
return { ...c , tableRef : table . id }
@@ -525,7 +508,7 @@ export const dataFormulatorSlice = createSlice({
525
508
}
526
509
} )
527
510
528
- if ( ! state . charts . some ( c => c . id != chartId && getDataTable ( c , state . tables , state . charts , state . conceptShelfItems ) . id == currentTableRef ) ) {
511
+ if ( ! state . charts . some ( c => c . id != chartId && getDataTable ( c , state . tables , allCharts , state . conceptShelfItems ) . id == currentTableRef ) ) {
529
512
state . tables = [ ...state . tables . filter ( t => t . id != currentTableRef ) , table ] ;
530
513
} else {
531
514
state . tables = [ ...state . tables , table ] ;
@@ -680,8 +663,8 @@ export const dataFormulatorSlice = createSlice({
680
663
} ,
681
664
clearUnReferencedTables : ( state ) => {
682
665
// remove all tables that are not referred
683
- let charts = state . charts ;
684
- let referredTableId = charts . map ( chart => getDataTable ( chart , state . tables , state . charts , state . conceptShelfItems ) . id ) ;
666
+ let allCharts = dfSelectors . getAllCharts ( state ) ;
667
+ let referredTableId = allCharts . map ( chart => getDataTable ( chart , state . tables , allCharts , state . conceptShelfItems ) . id ) ;
685
668
state . tables = state . tables . filter ( t => ! ( t . derive && ! referredTableId . some ( tableId => tableId == t . id ) ) ) ;
686
669
} ,
687
670
clearUnReferencedCustomConcepts : ( state ) => {
@@ -716,26 +699,6 @@ export const dataFormulatorSlice = createSlice({
716
699
let chartId = action . payload ;
717
700
state . focusedChartId = chartId ;
718
701
state . visViewMode = "carousel" ;
719
-
720
- let chart = state . charts . find ( c => c . id == chartId )
721
-
722
- // update activeThread based on focused chart
723
- if ( chart ?. intermediate == undefined ) {
724
- state . activeThreadChartId = chartId ;
725
- } else {
726
- let currentActiveThreadChart = state . charts . find ( c => c . id == state . activeThreadChartId ) ;
727
- let activeThreadChartTable = state . tables . find ( t => t . id == currentActiveThreadChart ?. tableRef ) ;
728
-
729
- if ( activeThreadChartTable ) {
730
- let triggers = getTriggers ( activeThreadChartTable , state . tables ) ;
731
- if ( triggers . map ( tg => tg . tableId ) . includes ( chart ?. intermediate ?. resultTableId ) ) {
732
- let nextChart = state . charts . find ( c => c . intermediate == undefined && c . tableRef == chart ?. intermediate ?. resultTableId ) ;
733
- if ( nextChart ) {
734
- state . activeThreadChartId = nextChart . id ;
735
- }
736
- }
737
- }
738
- }
739
702
} ,
740
703
setVisViewMode : ( state , action : PayloadAction < "carousel" | "gallery" > ) => {
741
704
state . visViewMode = action . payload ;
@@ -844,7 +807,19 @@ export const dfSelectors = {
844
807
let focusedTable = tables . find ( t => t . id == focusedTableId ) ;
845
808
let sourceTables = focusedTable ?. derive ?. source || [ focusedTable ?. id ] ;
846
809
return sourceTables ;
847
- }
810
+ } ,
811
+
812
+ // Memoized chart selector that combines both sources
813
+ getAllCharts : createSelector (
814
+ [ ( state : DataFormulatorState ) => state . charts ,
815
+ ( state : DataFormulatorState ) => state . tables ] ,
816
+ ( userCharts , tables ) => {
817
+ const triggerCharts = tables
818
+ . filter ( t => t . derive ?. trigger ?. chart )
819
+ . map ( t => t . derive ?. trigger ?. chart ) as Chart [ ] ;
820
+ return [ ...userCharts , ...triggerCharts ] ;
821
+ }
822
+ ) ,
848
823
}
849
824
850
825
// derived field: extra all field items from the table
0 commit comments