-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ui-notification retains and emits properties from all previous messages #1602
Comments
Hi @gemini86, Thanks for sharing a simple example flow, because that allows people to quickly reproduce it. I did quite a lot of changes to the ui-notification node last year, but - although it indeed really should be fixed- I am not tempted to start digging into the code to solve this one. I will try to explain below why... The old AngularJs dashboard contained a mechanism called message replay, which replays the last input message as soon as you e.g. refresh your browser window. That way your dashboard in the browser is updated to show the state from the last message content. While that sounds like a good approach, it caused a LOT of headache for ui node developers in the past. Unfortunately the message replay mechanism has also been used in this new dashboard D2, and again it keeps causing issues like this one you reported. I could fix the code to solve your problem, but that would be nothing more than a nasty workaround. By keep continuing that way, the entire dashboard code becomes more and more polluted with dirty workarounds. As a result the dashboard code becomes very hard to maintain, and the chance for regression issues increases a lot. Imho the only decent solution is to completely remove the entire message replay mechanism from the internals of this dashboard. But that is a lot of work. And at the moment I am the only one from our entire community that is willing to contribute to this repository, so that certainly will not happen in my limited free time. Hopefully Joe (who is very busy at the moment with non-dashboard stuff) has some time in the near future to have a look at that. He can always give me a call for a meet and greet to discuss all of this ;-) Hopefully that gives you enough context to understand the root of the problem. |
Understandable. My company is a FlowFuse subscriber, so my hope is that since they're heavily developing dashboard-2 for their commercial efforts, it could see more attention than just volunteers. I am more than willing to contribute, since I'm using this for a work project, but I also don't have much free time. For now, it seems the best work-around is to NOT reuse notification nodes where the presence of other msg properties may vary. If you're able to point me to a style guide or other needed documentation in order to effectively contribute, I'll look at submitting some pull requests. |
Yes sure they do!! Allmost all of the code in this repo is contributed by Flowfuse. It is only recently that they are busy with other things, so developments here are currently lower. But that will be a temporary hickup. But anyway it would be nice to get some extra help from our community...
Here you can find the contribution documentation. But you can also ask for extra info here, and I/we will try to assist as much as possible.
I assume you are talking about a workaround to fix the ui-notification node? If you need some guidance, please ask and I will try to put you on track if needed. |
For this specific task, yes. I'm already diggin into because my ADHD won't let me stop right now, I see the issue in data.js in the
I'm sure there's some reason we need to merge the incoming message with the existing one in the store for each widget? Changing this would obviously impact ALL widgets, so I'm inclined to think this would be a breaking change but I'll look into that tomorrow. If you or anyone else have any insight, it would be greatly appreciated. |
But for now I can confirm in my testing that this fixes the issue and my ADHD can let me rest:
Who knows what can of worms it opens up... |
Ah ok. Indeed if you want to solve it at that point in the code, then indeed you are opening the famous can of worms. Be aware that those messages - stored in the state store - are also emitted to the frontend. You hit the point where all troubles started. There are 2 separate stores unfortunately in dashboard D2: the statestore (which I like) and that datastore (which I don't like). There have been already a few good refactorings in Q4 of last years, to tackle issues with that datastore, but it is still there.
That is what I mean: the datastore should only contain a single state, which should be constructed at the server-side (based on the information in the successive message payloads) and then synced to the clients. Not simply store the N latest messages, because that makes no sense and results in all kind of troubles. But yes your patch might indeed be an improvement for your single use case. However I have no idea whether e.g. third-party ui nodes (from other developers) make use of the other information (e.g. Hopefully you understand now why the store/replay of messages seems like a brilliant (Node-RED compliant) idea, but isn't at all... |
Thank you for the time to explain the different functions of the stores. Could you point me to the state store code? I would like to look at the implementation, but from what you're describing, it still doesn't make any sense from a functional point of view to only merge in new messages without clearing any other previously set properties. Here are some points I'd like to argue if I may, not a criticism but just some feedback as a long time (node-red 0.xx) user:
I have a similar but different datastore issue with UIform, where it doesn't even store the input msg into the state at all, only the payload (and topic if you configure it to do so), so when the submit button is pressed, all other msg properties that you had wanted to pass through are dropped. So you see how it's more an issue of code consistency and variability of intentions between nodes, which is why I asked if there was a style guide or code document to reference. For now I will study the rest of the code and other widgets to see what my changes do to alter their behavior. |
You are welcome!
Here you can find the code for both stores.
The state store is more or like you describe. But the data store not: it is just a store to keep track of the latest N messages. Perhaps you can find a bit more informating about the merging in this pull request.
We can only learn from 'constructive' feedback like yours...
Yes that is indeed a bit into the direction I was pointing to. You don't need to store the N latest messages, but imho only keeping the last message is not enough. Because then you assume that the last message contains the entire state. That is only correct for simple ui nodes, e.g. for a simple switch, led, ... However that does not work for other nodes:
That is why I say that the data store should not simply store the last message or last N messages. Or last payload or last N payloads. Instead the datastore should keep track of the entire state, which it needs to create based upon messages that are injected containing the full or partial state. How the full state is constructed based on payloads from input messages, is up to every ui node itself. When you refresh your browser window or when a new client connects, that current (entire) state can simply be passed to it and visualized.
Yes indeed keeping the last message somewhere is very useful when it needs to be resend to the output. But imho not for sending it to the frontend via the datastore... |
Ah, I understand. Again, my argument is to ask the user to send messages with explicit intent. In your SVG node example; if I am sending in a In the chart node example, the configuration of the node should dictate what is done with the payload unless there's a dynamic input ( Say I set Back to the topic of this ui-notification node: here's another flow snippet example where a user would want to disable the confirm and dismiss buttons for a particular notification, but then expect the node to go back to its default configuration, since it's not expressed in the help file that it wouldn't. The current behavior causes the user to have to explicitly define every
This is quite the opposite of what users of D1 expected nodes to do when setting dynamic properties, hence the frustration when trying to migrate to D2 and find all these undocumented and unexpected behaviors. Also, regarding a node's output; the help page should tell the user what to expect on the output. Many of the D2 nodes don't follow the node-help style guide or provide all the needed information such as the expected output. In the D1 chart node, it's always been the 'state' of the chart as it, so you can store it in a persistent storage external to the node for reloading. Again, I really appreciate the information and I enjoy discussing, so thank you for your time and I hope my rambling isn't coming off as ungrateful. I'm not experienced enough to make all the contributions I feel are needed, and I also see a need for more group discussion to come to a consensus on how nodes should behave before any of these types of changes can happen, but I do think they need to happen before I can fully adopt D2 for my own production use. |
Yes that is indeed something I have been considering over and over again in the past. Because users where injecting weeks after weeks messages into their floorplan to update the state of their devices. And then suddenly Node-RED was restarting and all their state was lost. I had a lot of feedback and discussions with users about that all over the years. They tried to find all kinds of workarounds, but I have never seen one that did the job completely. It is rather complex. You could e.g. add a css class "light" to evey light bulb icon in your floorplan. Then you can turn all lights on in the floorplan by injecting a message with that class as CSS selector. But then some light is turned off, you inject a message to turn 1 light bulb icon off. And when you start animations for some elements it becomes even more complicated, because these e.g. might have a finite length duration. So when meanwhile another client dashboard is opened, it should only see the remaining part of the animation. And so on... That is what I mean that each ui node should have its own way to update its own state in the dashboard, in case of the ui-svg node the best way seemed to be at the end to maintain a single server-side lightweight DIM tree with CSS selector support. Believe me, LOTs of ideas have already been reviewed in the past... But if you have any ideas, please share them!
That indeed makes sense yes, to me at least...
Ah I had already forgotten how D1 worked. Yes indeed via the dynamic messages the properties from the config screen are overwritten from then on with that new value. Quite some time ago, I already had some ideas about persistent and volatile properties: see discussion. I am completely not claiming that all my ideas are great, but we did discuss it quite a lot. However the dashboard at that moment was already grown quite a lot, so it became more and more difficult to introduce such large changes to the core (without breaking everything). Moreover it is easy to talk about it, but somebody needs to have time to implement it...
Yes I totally agree about that too. But to be very honest: if you put a debug on the output, then you see what comes out. And then you know which information is missing in the documentation. And most of the people in our community are intelligent enough to contribute such textual changes to the documentation of this repo. However I see nearly nobody contributing changes to the documentation. Only a lot of frustrated people pointing their finger at a few guys, which they expect to do it all for free for them. That way I can assure it will never happen...
Unlike a lot of other discussions I had (unfortunately) recently, I consider this one as constructive. However I am not sure if it is still possible to implement such a large change as you suggest, although I also think it is really needed to do it. But would be a lot of work, and I am afraid a lot of breaking changes would be involved. Especially since there are now also custom ui nodes available in the wild. I have too less knowledge about the core and Vue to put a solution on the table unfortunately... BTW this might also be interesting for you. |
Thank you for linking my concerns on that issue. I can see as well that the API doesn't need to change, just how nodes are calling it (although it would be nice if there was a method for resetting all dynamic properties at once). For instance, ui-notification calls |
Current Behavior
When sending a msg to ui-notification configured with manual confirmation/dismissal, any property that's set aside from
msg.payload
ormsg.topic
is retained and emitted any time the confirm or dismiss buttons are clicked, even when the incoming message that triggered the notification does not have that property.Expected Behavior
The output that's emitted from a notification when a confirm or cancel button is clicked should only contain the msg that was sent to it, with msg.payload modified per the node help info.
Steps To Reproduce
Example flow:
Click the first inject node, then click confirm or close on the dashboard notification, then click the second inject node and click confirm or close and see that the extra properties from the first inject are being emitted every time. Removing the node and replacing the node does not help.
[{"id":"fcf752aa7785e4fa","type":"inject","z":"df36d1113fdcc60e","name":"click first","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"extraProp","v":"foo bar","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"hello world","payloadType":"str","x":560,"y":660,"wires":[["9c5952c1756c5cb9"]]},{"id":"84bdee650d1a43df","type":"inject","z":"df36d1113fdcc60e","name":"click second","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"hello world","payloadType":"str","x":550,"y":700,"wires":[["9c5952c1756c5cb9"]]},{"id":"a16d019f36a00697","type":"debug","z":"df36d1113fdcc60e","name":"debug 4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":940,"y":680,"wires":[]},{"id":"9c5952c1756c5cb9","type":"ui-notification","z":"df36d1113fdcc60e","ui":"4021fffb356dc9de","position":"center center","colorDefault":true,"color":"#000000","displayTime":"","showCountdown":true,"outputs":1,"allowDismiss":true,"dismissText":"Close","allowConfirm":true,"confirmText":"Confirm","raw":false,"className":"","name":"","x":750,"y":680,"wires":[["a16d019f36a00697"]]},{"id":"4021fffb356dc9de","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"navigationStyle":"default","titleBarStyle":"default"}]
Environment
Have you provided an initial effort estimate for this issue?
I am not a FlowFuse team member
The text was updated successfully, but these errors were encountered: