@@ -12,6 +12,12 @@ function updateWidget(id, objectState, widgetState) {
1212 Object . assign ( widgetState . data , objectState . refs ) ;
1313}
1414
15+ function updateServerState ( serverState , partialState ) {
16+ for ( const [ key , value ] of Object . entries ( partialState ) ) {
17+ serverState [ key ] = JSON . stringify ( value ) ;
18+ }
19+ }
20+
1521export class DataclassManager {
1622 constructor ( ) {
1723 this . client = null ;
@@ -24,6 +30,9 @@ export class DataclassManager {
2430 this . dataToVue = { } ;
2531 this . pendingClientServerQueue = [ ] ;
2632 this . pendingFlushRequest = 0 ;
33+ this . triggers = { } ;
34+ this . deepReactiveWatchers = { } ;
35+ this . pendingDeepReactives = { } ;
2736 }
2837
2938 connect ( client ) {
@@ -40,10 +49,13 @@ export class DataclassManager {
4049 return ;
4150 }
4251
43- Object . assign ( this . dataStates [ id ] . server , state ) ;
52+ // Capture server state for update comparison
53+ updateServerState ( this . dataStates [ id ] . server , state ) ;
4454 for ( const [ key , value ] of Object . entries ( state ) ) {
4555 if ( this . isDataClass ( id , key ) ) {
4656 await this . handleNestedDataClass ( id , key , value ) ;
57+ } else if ( this . isDeepReactive ( id , key ) ) {
58+ this . dataStates [ id ] . refs [ key ] . value = reactive ( value ) ;
4759 } else {
4860 this . dataStates [ id ] . refs [ key ] . value = value ;
4961 }
@@ -52,7 +64,7 @@ export class DataclassManager {
5264 }
5365
5466 updateServer ( id , name , value ) {
55- this . pendingClientServerQueue . push ( [ id , name , value ] ) ;
67+ this . pendingClientServerQueue . push ( [ id , name , JSON . stringify ( value ) ] ) ;
5668 this . flushToServer ( ) ;
5769 }
5870
@@ -64,7 +76,8 @@ export class DataclassManager {
6476 const msg = { } ;
6577 let sendingSomething = 0 ;
6678 while ( this . pendingClientServerQueue . length ) {
67- const [ id , name , value ] = this . pendingClientServerQueue . shift ( ) ;
79+ const [ id , name , strValue ] = this . pendingClientServerQueue . shift ( ) ;
80+ const value = JSON . parse ( strValue ) ;
6881 let valueToSend = value ;
6982
7083 // Handle nested dataclass
@@ -86,10 +99,7 @@ export class DataclassManager {
8699 }
87100 }
88101 }
89- if (
90- JSON . stringify ( this . dataStates [ id ] . server [ name ] ) ===
91- JSON . stringify ( valueToSend )
92- ) {
102+ if ( this . dataStates [ id ] . server [ name ] === strValue ) {
93103 continue ;
94104 }
95105 if ( ! msg [ id ] ) {
@@ -116,13 +126,45 @@ export class DataclassManager {
116126 }
117127
118128 isDataClass ( id , name ) {
119- return this . typeDefinitions [
120- this . dataTypes [ id ]
121- ] . dataclass_containers . includes ( name ) ;
129+ return this . typeDefinitions [ this . dataTypes [ id ] ] . dataclass_containers [ name ] ;
122130 }
123131
124132 isClientOnly ( id , name ) {
125- return this . typeDefinitions [ this . dataTypes [ id ] ] ?. client_only . includes ( name ) ;
133+ return this . typeDefinitions [ this . dataTypes [ id ] ] ?. client_only [ name ] ;
134+ }
135+
136+ isDeepReactive ( id , name ) {
137+ const result =
138+ this . typeDefinitions [ this . dataTypes [ id ] ] ?. deep_reactive [ name ] ;
139+ return result ;
140+ }
141+
142+ makeDeepReactive ( id , name , value ) {
143+ console . log ( "makeDeepReactive" , id , name , value ) ;
144+ const fullKey = `${ id } ::${ name } ` ;
145+ const unwatch = this . deepReactiveWatchers [ fullKey ] ;
146+ if ( unwatch ) {
147+ console . log ( "unwatch" ) ;
148+ unwatch ( ) ;
149+ }
150+ this . deepReactiveWatchers [ fullKey ] = null ;
151+
152+ if ( value === null || value === undefined ) {
153+ return value ;
154+ }
155+
156+ const r = reactive ( value ) ;
157+ const trigger = this . triggers [ fullKey ] ;
158+ if ( ! trigger ) {
159+ if ( ! this . pendingDeepReactives [ id ] ) {
160+ this . pendingDeepReactives [ id ] = [ ] ;
161+ }
162+ this . pendingDeepReactives [ id ] . push ( [ fullKey , r ] ) ;
163+ } else {
164+ console . log ( "add watch" , fullKey ) ;
165+ this . deepReactiveWatchers [ fullKey ] = watch ( r , trigger ) ;
166+ }
167+ return r ;
126168 }
127169
128170 async handleNestedDataClass ( id , key , value ) {
@@ -156,7 +198,19 @@ export class DataclassManager {
156198 }
157199 }
158200 if ( ! this . dataStates [ id ] . refs [ key ] ) {
159- this . dataStates [ id ] . refs [ key ] = ref ( newArray ) ;
201+ if ( this . isDeepReactive ( id , key ) ) {
202+ this . dataStates [ id ] . refs [ key ] = ref (
203+ this . makeDeepReactive ( id , key , newArray ) ,
204+ ) ;
205+ } else {
206+ this . dataStates [ id ] . refs [ key ] = ref ( newArray ) ;
207+ }
208+ } else if ( this . isDeepReactive ( id , key ) ) {
209+ this . dataStates [ id ] . refs [ key ] . value = this . makeDeepReactive (
210+ id ,
211+ key ,
212+ newArray ,
213+ ) ;
160214 } else {
161215 this . dataStates [ id ] . refs [ key ] . value = newArray ;
162216 }
@@ -204,6 +258,19 @@ export class DataclassManager {
204258 }
205259 }
206260
261+ getTrigger ( id , key , refs ) {
262+ const fullKey = `${ id } ::${ key } ` ;
263+ const fn = this . triggers [ fullKey ] ;
264+ if ( fn ) {
265+ return fn ;
266+ }
267+ this . triggers [ fullKey ] = ( ) => {
268+ this . updateServer ( id , key , refs [ key ] . value ) ;
269+ console . log ( "push to server" , id , key ) ;
270+ } ;
271+ return this . triggers [ fullKey ] ;
272+ }
273+
207274 async fetchState ( id ) {
208275 const refs = { _id : id } ;
209276 const data = await this . client
@@ -212,7 +279,10 @@ export class DataclassManager {
212279 . call ( "trame.dataclass.state.get" , [ id ] ) ;
213280
214281 this . dataTypes [ id ] = data . definition ;
215- this . dataStates [ id ] = { refs, server : data . state } ;
282+ this . dataStates [ id ] = {
283+ refs,
284+ server : JSON . parse ( JSON . stringify ( data . state ) ) ,
285+ } ;
216286
217287 if ( ! this . typeDefinitions [ data . definition ] ) {
218288 await this . fetchDefinition ( data . definition ) ;
@@ -223,14 +293,22 @@ export class DataclassManager {
223293 if ( this . isDataClass ( id , key ) ) {
224294 refs [ key ] = ref ( null ) ;
225295 await this . handleNestedDataClass ( id , key , value ) ;
296+ } else if ( this . isDeepReactive ( id , key ) ) {
297+ refs [ key ] = ref ( this . makeDeepReactive ( id , key , value ) ) ;
226298 } else {
227299 refs [ key ] = ref ( value ) ;
228300 }
229301 if ( ! this . isClientOnly ( id , key ) ) {
230- watch (
231- ( ) => refs [ key ] . value ,
232- ( v ) => this . updateServer ( id , key , v ) ,
233- ) ;
302+ const trigger = this . getTrigger ( id , key , refs ) ;
303+ watch ( refs [ key ] , trigger ) ;
304+
305+ const items = this . pendingDeepReactives [ id ] || [ ] ;
306+ while ( items . length ) {
307+ const [ fullKey , r ] = items . pop ( ) ;
308+ const trigger = this . getTrigger ( id , key , refs ) ;
309+ this . deepReactiveWatchers [ fullKey ] = watch ( r , trigger ) ;
310+ console . log ( "watch" , fullKey , r ) ;
311+ }
234312 }
235313 }
236314
@@ -251,7 +329,19 @@ export class DataclassManager {
251329 . getSession ( )
252330 . call ( "trame.dataclass.definition.get" , [ id ] ) ;
253331
254- this . typeDefinitions [ id ] = data ;
332+ this . typeDefinitions [ id ] = {
333+ ...data ,
334+ dataclass_containers : { } ,
335+ client_only : { } ,
336+ deep_reactive : { } ,
337+ } ;
338+ const toDict = [ "dataclass_containers" , "client_only" , "deep_reactive" ] ;
339+ while ( toDict . length ) {
340+ const arrayName = toDict . pop ( ) ;
341+ for ( let i = 0 ; i < data [ arrayName ] . length ; i ++ ) {
342+ this . typeDefinitions [ id ] [ arrayName ] [ data [ arrayName ] [ i ] ] = 1 ;
343+ }
344+ }
255345 }
256346
257347 unlink ( dataId , componentId ) {
0 commit comments