# How to sync the FULL config between server and client side state

**URL:** <https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252>\
**Category:** Dashboard\
**Tags:** flexdash, dashboard-2\
**Created:** [4 July 2024 05:55 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252 "2024-07-04T05:55:31Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![joepavitt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/joepavitt/32/59722_2.png) [@joepavitt](https://discourse.nodered.org/u/joepavitt)\
**Post date:** [11 July 2024 09:06 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/41 "2024-07-11T09:06:34Z")

</div>

My main concern here is when is it appropriate to store, and when is it not. Let's take an example for UI Notification (as I explain [here](https://github.com/FlowFuse/node-red-dashboard/pull/932#issuecomment-2222405511) too):

1. Send `msg = { color: 'red', payload: 'Hello'}`
2. Notification shows with that color/message
3. Send `msg = { payload: 'Goodbye'}`

What colour should the notification be for "Goodbye"? I would argue it should be the default colour, _not_ the color defined in a previous message.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [11 July 2024 09:35 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/42 "2024-07-11T09:35:15Z")

</div>

And indeed - is it even appropriate for notifications to be stored? Shouldn't they be transient anyway?

---

<div class="post-metadata">

**Author:** ![arturv2000](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/arturv2000/32/88724_2.png) [@arturv2000](https://discourse.nodered.org/u/arturv2000)\
**Post date:** [11 July 2024 10:24 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/43 "2024-07-11T10:24:30Z")

</div>

> [@joepavitt](#):
>
> What colour should the notification be for "Goodbye"? I would argue it should be the default colour, _not_ the color defined in a previous message.

Just my opinion, but that would depend on the type of widget. For a notification can agree that `color` if not specified should return to default. But for a `UI-Text` or `UI-Button` would expect the color to remain until a new `msg.ui_update.color` is sent.

Now, if I understand correctly, and everything that is related to widget configuration `ui_update` such as `label`, `icon` and others that may exist is saved and restored correctly uppon widget load/reload, and if the question is on what to do with properties that are not present in the `ui_update` configuration, can agree that it should return to default and the user should handle those states if necessary.

Although `msg.payload` should also be preserved like another configuration.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [11 July 2024 13:01 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/44 "2024-07-11T13:01:39Z")

</div>

> [@joepavitt](#):
>
> I prefer the idea of having `state` for anything linked to the Node-RED config (and relevant overrides), and then the `data` store linked to data it renders, e.g. `msg.payload`.
> 
> Re-architecting the `datastore` to support both use as a `msg` history/latest store, _and_ a place to store an accumulated picture of the live `data` that a node is using feels very sensible to me?

There is indeed some logic to that, though if the api to access them will be the same I am not sure what is the benefit of having two stores. Is not the only difference how the state is fed to the node on connection?

> [@joepavitt](#):
>
> What colour should the notification be for "Goodbye"?

That is a question about the spec of the node, rather than about how the stores are organised.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [11 July 2024 21:11 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/45 "2024-07-11T21:11:18Z")

</div>

Thanks everybody for joining 🤩  
All these ideas are very illuminating, since everybody has his own use specific cases. .

> [@arturv2000](#):
>
> but that would depend on the type of widget

Yes absolutely true. I had used the ui-notification as example, simply because I was stuck last night on the msg replay mechanism for the ui-notification node. But for example for my ui-svg node, there will be a lot of state that users want to store, and lots of state that people don't want to store.

Imho I would even go a step further: it doesn't only on the type of widget, but on what the user wants to do with the widget. The user wants to store the color of a widget for use case A, but not for use case B. _I think we should only offer a list of supported properties per widget, but is up to the user whether he wants to store the injected property values or not..._

> [@joepavitt](#):
>
> My main concern here is when is it appropriate to store, and when is it not.

That is a VERY good one! Hadn't seen that one coming 💩  
How stupid of me to forget about transient property values in my proposal.  
Again back to the drawing table 🥴

So the user should be able to finetune following information, to determine the widget state:

1. The _ **static properties** _, as specified in the flow editor via the ui node config screen.
2. The _ **dynamic properties** _, as specified in the input message.
3. The 'flags' that determine whether these dynamic properties are _ **persistent** _ (i.e. stored in the state store) or _ **transient** _ (i.e. not stored in the state store). The latter ones will only be send once to the client(s), and will not survive a refresh.
4. The 'socketId' that determines whether these dynamic properties are to be send to a _ **single client or all clients** _.

Suppose the `msg.ui_update` would be replaced by `msg.ui_stored` (for persistent dynamic properties) and `msg.ui_temporary` (for transient dynamic properties). Then we could have a setup like this:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/6/a64f70b46f7462a699a8b70e102423590fef5276.jpeg)

That way the user can decide completely on his own what to do with the properties offered by the widget. And (imho) for developers it is quite easy to understand how stuff works...

Shoot 🥶

---

<div class="post-metadata">

**Author:** ![arturv2000](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/arturv2000/32/88724_2.png) [@arturv2000](https://discourse.nodered.org/u/arturv2000)\
**Post date:** [12 July 2024 10:22 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/46 "2024-07-12T10:22:10Z")

</div>

> [@BartButenaers](#):
>
> Suppose the `msg.ui_update` would be replaced by `msg.ui_stored` (for persistent dynamic properties) and `msg.ui_temporary` (for transient dynamic properties). Then we could have a setup like this:

My one possible issue with this approach (if my understand is correct) is that (not taking in consideration the use of `client_id`) if any of the `ui_temporary` properties affects the UI, opening a new browser window will render a different page, which could be intended.

If any property can live either in `ui_temporary` or `ui_update` is not an issue, since is the user/programmer responsibility to handle it.

One thing i would change / add to this concept, the squares on the right shouldn't be only associated to existing clients or new clients, should be also associated to `widget-load`/`mount` specially the top right one.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [12 July 2024 16:25 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/47 "2024-07-12T16:25:34Z")

</div>

> [@arturv2000](#):
>
> if any of the `ui_temporary` properties affects the UI, opening a new browser window will render a different page, which could be intended.

Yes you are right, that is something that should certainly be added to the documentation (if this proposal would ever see the daylight). Because this design offers lots of flexibility to the users, but of course they should get some simple examples to explain it, otherwise they would have a lot of headache.

- If you inject a `msg.ui_temporary.color=red` then only this message will result in a red notification.
- If you inject a `msg.ui_stored.color=red` then all messages from here on will result in a red notification.

I don't think a dashboard contributor or ui node developer should constrain this flexibility too much.

> [@arturv2000](#):
>
> One thing i would change / add to this concept, the squares on the right shouldn't be only associated to existing clients or new clients, should be also associated to `widget-load`/`mount` specially the top right one.

That is something that is not clear from me in the current design of the dashboard. Do you mean that the widget-load not only happens for a refresh or new client connection, but also at other event? Perhaps at a tabsheet change or something like that?

---

<div class="post-metadata">

**Author:** ![arturv2000](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/arturv2000/32/88724_2.png) [@arturv2000](https://discourse.nodered.org/u/arturv2000)\
**Post date:** [12 July 2024 17:45 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/48 "2024-07-12T17:45:50Z")

</div>

> [@BartButenaers](#):
>
> That is something that is not clear from me in the current design of the dashboard. Do you mean that the widget-load not only happens for a refresh or new client connection, but also at other event? Perhaps at a tabsheet change or something like that?

Yes, the event I am speaking is in case of tab change. When a widget is mounted to appear on the GUI (webPage) it will send the `widget-load` event and is supposed to receive the configuration at that time. And when changing tabs is necessary to resend stuff that was sent while the widget was not visible.

I think (for what I can see on the websocket connection) that the widget-load only happens when the widget is mount, not when the page is refresh.

There are some issues with that:

> <https://github.com/FlowFuse/node-red-dashboard/issues/871#issue-2302486678>
>
> \### Current Behavior
> 
> Hello
> 
> This can be a unique situation due to the way i h…ave things implemented in Node-Red.
> 
> I have a dashboard with several tabs (up to 6 tabs, 42 groups, and a total of 332 widgets). Since i have devices communicating at a rate of 100ms (up to 3 devices at the same time) i have filters before any widget to only send stuff to the widgets if the value \`payload\` for that specific widget has changed. This was implemented because i started to see performance degradation of too much traffic in the websocket.
> 
> What is happening, that i find strange is that for example:
> 
> \- I am in tab '1', and a message is received from the device that requires updating a text label in tab \`2\`
> \- Node-Red sends the message for the text label correct (I can see the message was sent in the \_debug page)
> !\[image\](https://github.com/FlowFuse/node-red-dashboard/assets/17281826/ea470a06-4b8a-4e66-af34-61484cb925fe)
> \- The tab properties still indicate the old \`class\` value
> !\[image\](https://github.com/FlowFuse/node-red-dashboard/assets/17281826/c04bad14-3fc5-4424-b77f-018e7857385a)
> \- If I change to tab \`2\` the \`text\` content is correctly updated, but the class is still the old one (in this case the color of the text is still \`orange\`), the \`tab properties\` maintains the same indication as before.
> 
> If I force a \`refresh\` of the page, the correct text and color is presented.
> 
> Is this behaviour expected?
> 
> At the moment the only workaround seems to have a ui-config (that seems to have also some issues) to detect when the tab is loaded, and issue a \`msg.reset = true\` to all filter nodes, to force the update of values.
> 
> \### Expected Behavior
> 
> In the same way that the \`text\` content is updated so the other dynamic properties should be.
> 
> \### Steps To Reproduce
> 
> \_No response\_
> 
> \### Environment
> 
> \- Dashboard version: v1.7.1
> \- Node-RED version: v3.1.7
> \- Node.js version:
> \- npm version:
> \- Platform/OS:
> \- Browser: Edge
> 
> \### Have you provided an initial effort estimate for this issue?
> 
> I have provided an initial effort estimate

And i made this PR with an attempt to solve the issue, at least for the UI-Button:

> <https://github.com/FlowFuse/node-red-dashboard/pull/1059#issue-2386808424>
>
> \## Description
> 
> Needed a way to preserve the changes we send via \`ui\_update\` e…ven if the widget is hidden in another tab or after a page refresh.
> 
> As it was now, depending on the widget, it would only recuperate the last \`ui\_update\` property sent. 
> For the moment only did this for the \`UI-Button\` but if it is correct will make changes to at least \`UI-Dropdown\`, \`UI-Slider\` and \`UI-Switch\`, they are the widgets that at the moment I require this behaviour.
> 
> Changes:
> 
> \- Unsubscribe from event 'widget-load:' to avoid multiple widget-Load messages, seems to solve #909
> \- When emitting a \`widget-load\` event, add to the message the \`ui\_update\` parameters in store
> \- Add \`ui\_update.enable\` as a valid parameter for \`UI-Button\`
> \- Add \`onLoad\` event to \`UI-Button\`
> \- Store the last message sent to \`UI-Button\` to force a \`widget-load\` event upon refresh of page/widget.
> - This one, not quite sure about it. I needed a way for the \`UI-Button\` to trigger a \`widget-load\` event and this was the only way I could find to do that
> 
> This if applied to other widgets should also solve this issue #871
> 
> 
> 
> \## Related Issue(s)
> 
> 
> 
> \## Checklist
> 
> 
> 
> - \[\] I have read the \[contribution guidelines\](https://github.com/FlowFuse/flowfuse/blob/main/CONTRIBUTING.md)
> - \[\] Suitable unit/system level tests have been added and they pass 
> - \[\] Documentation has been updated
> - \[\] Upgrade instructions
> - \[\] Configuration details
> - \[\] Concepts
> - \[\] Changes \`flowforge.yml\`?
> - \[\] Issue/PR raised on \`FlowFuse/helm\` to update ConfigMap Template
> - \[\] Issue/PR raised on \`FlowFuse/CloudProject\` to update values for Staging/Production
> 
> \## Labels
> 
> - \[\] Includes a DB migration? -\> add the \`area:migration\` label

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [12 July 2024 20:46 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/49 "2024-07-12T20:46:48Z")

</div>

> [@arturv2000](#):
>
> I think (for what I can see on the websocket connection) that the widget-load only happens when the widget is mount, not when the page is refresh.

Widget load occurs on a refresh, new connection (which is identical to a refresh) and tab change.

I am confused about the ui\_temporary suggestion. Is the suggestion that it should change the property for the current session, but not for other sessions, or is it that it just applies to this message?

---

<div class="post-metadata">

**Author:** ![arturv2000](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/arturv2000/32/88724_2.png) [@arturv2000](https://discourse.nodered.org/u/arturv2000)\
**Post date:** [12 July 2024 21:17 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/50 "2024-07-12T21:17:51Z")

</div>

> [@Colin](#):
>
> Widget load occurs on a refresh, new connection (which is identical to a refresh) and tab change.

I think that is only valid if the widget is in the visible tab at that time.

> [@Colin](#):
>
> I am confused about the ui\_temporary suggestion. Is the suggestion that it should change the property for the current session, but not for other sessions, or is it that it just applies to this message?

From my understanding it would only be for that specific message, in this case i don't think it is even necessary to have a `store`.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 July 2024 07:37 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/51 "2024-07-13T07:37:17Z")

</div>

> [@arturv2000](#):
>
> > [@Colin](#):
> >
> > Widget load occurs on a refresh, new connection (which is identical to a refresh) and tab change.
> 
> I think that is only valid if the widget is in the visible tab at that time.

Yes, I should probably have written  
Widget load occurs on a refresh, a new connection (which is identical to a refresh) and a page change to the page containing the widget.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [13 July 2024 10:40 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/52 "2024-07-13T10:40:08Z")

</div>

> [@Colin](#):
>
> page change

Page change or page-tab change (e.g. an SPA route change)? On an SPA route change, does D2 unload the widget from memory or not?

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 July 2024 13:10 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/53 "2024-07-13T13:10:43Z")

</div>

> [@TotallyInformation](#):
>
> Page change or page-tab change

Page as in the D2 definition of a page. The equivalent of a tab in D1.

> [@TotallyInformation](#):
>
> On an SPA route change, does D2 unload the widget from memory or not?

Someone else will have to answer that, but when the user selects a page it 'mounts' the widgets on that page, and remounts them if the user goes away from that page then back again.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [13 July 2024 17:03 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/54 "2024-07-13T17:03:29Z")

</div>

> [@Colin](#):
>
> page

OK, probably worth ensuring clarity since D2 supports both actual pages and SPA "pages" and the two will have two very different paths and requirements to caching.

> [@Colin](#):
>
> it 'mounts' the widgets on that page, and remounts them if the user goes away from that page then back again

OK, so I think that implies that just changing an SPA page requires the cache to resend each time?

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 July 2024 19:10 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/55 "2024-07-13T19:10:59Z")

</div>

> [@TotallyInformation](#):
>
> changing an SPA page requires the cache to resend each time?

Do you mean the data and state stores? If so then yes.

---

<div class="post-metadata">

**Author:** ![arturv2000](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/arturv2000/32/88724_2.png) [@arturv2000](https://discourse.nodered.org/u/arturv2000)\
**Post date:** [13 July 2024 21:29 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/56 "2024-07-13T21:29:07Z")

</div>

> [@Colin](#):
>
> > [@TotallyInformation](#):
> >
> > On an SPA route change, does D2 unload the widget from memory or not?
> 
> Someone else will have to answer that, but when the user selects a page it 'mounts' the widgets on that page, and remounts them if the user goes away from that page then back again.

Can confirm, there is a `mount` event when the user enter the `tab`/`page` and an `unmount` event when the user exits the `tab`/`page`.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [15 July 2024 08:14 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/57 "2024-07-15T08:14:46Z")

</div>

Has anybody worked out what the client side vuex data store should be used for? I don't see the point in it.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [15 July 2024 12:21 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/58 "2024-07-15T12:21:52Z")

</div>

Very valid question Colin. I started a new ui node this week, but I have now 3 unfinished ui nodes. And I realize now that all 3 ui nodes are stuck at similar state management issues (refreshes, ...). I had hoped that by drawing the design above, I would get enough knowledge to get back on track. But with my current free time, I find it a bit too complicated to be honest. So I really hope that things can be simplified a bit. And I also don't know if my last [suggestion](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/45) above does make sense at all... Because I still don't understand why the datastores are needed, both server-side and client-side.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [15 July 2024 12:52 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/59 "2024-07-15T12:52:55Z")

</div>

I have switched to using the state store for state (!) and the data store only for replaying the most recent message (where needed). Client side I use local data for storing any state that is not in `props`. It has worked out pretty simple. If you want to see how it has turned out you could look at [GitHub - colinl/node-red-dashboard-2-ui-dropdown-cdl: A dropdown node with background colour change while waiting for confirmation via input msg](https://github.com/colinl/node-red-dashboard-2-ui-dropdown-cdl) which is a simple replacement for the dropdown node, with a tweak. After the user makes a selection it changes the background colour, reverting it when the node receives a confirmation that the value has changed. It is for the situation where the dropdown is making a change in a remote location and I want to know that it has got to that location and a confirmation come back (via MQTT in my case). I haven't got any plans to publish it at the moment, hence the lack of help text.

I am in the process of updating my flow that creates a basic ui node, to include the changes.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [17 July 2024 15:33 UTC](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252/60 "2024-07-17T15:33:09Z")

</div>

> [@Colin](#):
>
> I have switched to using the state store for state (!)

Hi Colin,  
Thanks for sharing your workaround for our state issues!  
Very useful indeed!!  
Had only a very quick look at your code, but there are some things I don't get yet:

1. When an input message is injected, you update the State store. But how does these State store changes arrive in your Vue frontend?

2. You don't send your message to the next nodes in the flow. Does this mean there is no passthrough of input messages possible?

3. You watch a `value` in your frontend. How does this work for you?

[Previous page](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252.md?page=2)

[Next page](https://discourse.nodered.org/t/how-to-sync-the-full-config-between-server-and-client-side-state/89252.md?page=4)
