@@ -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,11 +76,12 @@ 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
71- if ( value !== null && this . isDataClass ( id , name ) ) {
84+ if ( valueToSend !== null && this . isDataClass ( id , name ) ) {
7285 if ( Array . isArray ( value ) ) {
7386 // array[id...]
7487 valueToSend = value . map ( ( v ) => v . _id ) ;
@@ -86,10 +99,13 @@ 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 ) {
103+ console . log (
104+ "skip" ,
105+ valueToSend ,
106+ "server>" ,
107+ this . dataStates [ id ] . server [ name ] ,
108+ ) ;
93109 continue ;
94110 }
95111 if ( ! msg [ id ] ) {
@@ -116,13 +132,45 @@ export class DataclassManager {
116132 }
117133
118134 isDataClass ( id , name ) {
119- return this . typeDefinitions [
120- this . dataTypes [ id ]
121- ] . dataclass_containers . includes ( name ) ;
135+ return this . typeDefinitions [ this . dataTypes [ id ] ] . dataclass_containers [ name ] ;
122136 }
123137
124138 isClientOnly ( id , name ) {
125- return this . typeDefinitions [ this . dataTypes [ id ] ] ?. client_only . includes ( name ) ;
139+ return this . typeDefinitions [ this . dataTypes [ id ] ] ?. client_only [ name ] ;
140+ }
141+
142+ isDeepReactive ( id , name ) {
143+ const result =
144+ this . typeDefinitions [ this . dataTypes [ id ] ] ?. deep_reactive [ name ] ;
145+ return result ;
146+ }
147+
148+ makeDeepReactive ( id , name , value ) {
149+ console . log ( "makeDeepReactive" , id , name , value ) ;
150+ const fullKey = `${ id } ::${ name } ` ;
151+ const unwatch = this . deepReactiveWatchers [ fullKey ] ;
152+ if ( unwatch ) {
153+ console . log ( "unwatch" ) ;
154+ unwatch ( ) ;
155+ }
156+ this . deepReactiveWatchers [ fullKey ] = null ;
157+
158+ if ( value === null || value === undefined ) {
159+ return value ;
160+ }
161+
162+ const r = reactive ( value ) ;
163+ const trigger = this . triggers [ fullKey ] ;
164+ if ( ! trigger ) {
165+ if ( ! this . pendingDeepReactives [ id ] ) {
166+ this . pendingDeepReactives [ id ] = [ ] ;
167+ }
168+ this . pendingDeepReactives [ id ] . push ( [ fullKey , r ] ) ;
169+ } else {
170+ console . log ( "add watch" , fullKey ) ;
171+ this . deepReactiveWatchers [ fullKey ] = watch ( r , trigger ) ;
172+ }
173+ return r ;
126174 }
127175
128176 async handleNestedDataClass ( id , key , value ) {
@@ -156,7 +204,19 @@ export class DataclassManager {
156204 }
157205 }
158206 if ( ! this . dataStates [ id ] . refs [ key ] ) {
159- this . dataStates [ id ] . refs [ key ] = ref ( newArray ) ;
207+ if ( this . isDeepReactive ( id , key ) ) {
208+ this . dataStates [ id ] . refs [ key ] = ref (
209+ this . makeDeepReactive ( id , key , newArray ) ,
210+ ) ;
211+ } else {
212+ this . dataStates [ id ] . refs [ key ] = ref ( newArray ) ;
213+ }
214+ } else if ( this . isDeepReactive ( id , key ) ) {
215+ this . dataStates [ id ] . refs [ key ] . value = this . makeDeepReactive (
216+ id ,
217+ key ,
218+ newArray ,
219+ ) ;
160220 } else {
161221 this . dataStates [ id ] . refs [ key ] . value = newArray ;
162222 }
@@ -204,6 +264,19 @@ export class DataclassManager {
204264 }
205265 }
206266
267+ getTrigger ( id , key , refs ) {
268+ const fullKey = `${ id } ::${ key } ` ;
269+ const fn = this . triggers [ fullKey ] ;
270+ if ( fn ) {
271+ return fn ;
272+ }
273+ this . triggers [ fullKey ] = ( ) => {
274+ this . updateServer ( id , key , refs [ key ] . value ) ;
275+ console . log ( "push to server" , id , key ) ;
276+ } ;
277+ return this . triggers [ fullKey ] ;
278+ }
279+
207280 async fetchState ( id ) {
208281 const refs = { _id : id } ;
209282 const data = await this . client
@@ -212,7 +285,10 @@ export class DataclassManager {
212285 . call ( "trame.dataclass.state.get" , [ id ] ) ;
213286
214287 this . dataTypes [ id ] = data . definition ;
215- this . dataStates [ id ] = { refs, server : data . state } ;
288+ this . dataStates [ id ] = {
289+ refs,
290+ server : JSON . parse ( JSON . stringify ( data . state ) ) ,
291+ } ;
216292
217293 if ( ! this . typeDefinitions [ data . definition ] ) {
218294 await this . fetchDefinition ( data . definition ) ;
@@ -223,14 +299,22 @@ export class DataclassManager {
223299 if ( this . isDataClass ( id , key ) ) {
224300 refs [ key ] = ref ( null ) ;
225301 await this . handleNestedDataClass ( id , key , value ) ;
302+ } else if ( this . isDeepReactive ( id , key ) ) {
303+ refs [ key ] = ref ( this . makeDeepReactive ( id , key , value ) ) ;
226304 } else {
227305 refs [ key ] = ref ( value ) ;
228306 }
229307 if ( ! this . isClientOnly ( id , key ) ) {
230- watch (
231- ( ) => refs [ key ] . value ,
232- ( v ) => this . updateServer ( id , key , v ) ,
233- ) ;
308+ const trigger = this . getTrigger ( id , key , refs ) ;
309+ watch ( refs [ key ] , trigger ) ;
310+
311+ const items = this . pendingDeepReactives [ id ] || [ ] ;
312+ while ( items . length ) {
313+ const [ fullKey , r ] = items . pop ( ) ;
314+ const trigger = this . getTrigger ( id , key , refs ) ;
315+ this . deepReactiveWatchers [ fullKey ] = watch ( r , trigger ) ;
316+ console . log ( "watch" , fullKey , r ) ;
317+ }
234318 }
235319 }
236320
@@ -251,7 +335,19 @@ export class DataclassManager {
251335 . getSession ( )
252336 . call ( "trame.dataclass.definition.get" , [ id ] ) ;
253337
254- this . typeDefinitions [ id ] = data ;
338+ this . typeDefinitions [ id ] = {
339+ ...data ,
340+ dataclass_containers : { } ,
341+ client_only : { } ,
342+ deep_reactive : { } ,
343+ } ;
344+ const toDict = [ "dataclass_containers" , "client_only" , "deep_reactive" ] ;
345+ while ( toDict . length ) {
346+ const arrayName = toDict . pop ( ) ;
347+ for ( let i = 0 ; i < data [ arrayName ] . length ; i ++ ) {
348+ this . typeDefinitions [ id ] [ arrayName ] [ data [ arrayName ] [ i ] ] = 1 ;
349+ }
350+ }
255351 }
256352
257353 unlink ( dataId , componentId ) {
0 commit comments