FlowFuse / node-red-dashboard

https://dashboard.flowfuse.com
Apache License 2.0
204 stars 48 forks source link

Widget: UI Event #274

Closed joepavitt closed 1 year ago

joepavitt commented 1 year ago

Description

It has been discussed on many occasions that it would be beneficial to have the context of user data available in Node-RED when a Dashboard is rendered, i.e. if a page is rendered, having context on which user is viewing that page in both NR and Dashboard.

Given that we do have FF & basic auth available to Dashboard through the NR middleware, this is data we should be able to have an expose.

Similarly, we've had a request whereby we want to have different data show for different users, as you would expect on any standard software product when a user logs in.

Underpinning this, I believe there is an architecture within the flows that could be accomplished with a ui-event node. This node would send a payload whenever a set of given events takes place, and could include things like pageview, with accompanying data included in it's transmitted payload that details the authenticated user.

The most significant complexity for the above use cases is server-side state management (SSSM), which would essentially need to be turned off, and moved to a Database (most likely user managed, rather than something we offer as a service with Dashboard). With SSSM till on, a user viewing a page would trigger a database lookup, sending that data to the chart, and be made visible to the given user, but because that data would be retained server-side, any user viewing that dashboard would now see that user's data.

Instead, we would need to look at SSSM on a connection-by-connection basis - which could get very messy, or no SSSR at all, which feels cleaner given that state would need to be database managed anyway.

So a side-issue of this implementation may need to be the ability to turn off SSSR for a given widget/group/page/ui

Have you provided an initial effort estimate for this issue?

I have provided an initial effort estimate

robmarcer commented 1 year ago

Thanks for the issue creation @joepavitt, really clear write up.

One thing that I think there is value in is the ability to pass a user identifier into a flow once a user has been authenticated. That would allow much more complex interactions such as showing relevant data to team members who work at a specific location. I appreciate there may be significant complexities in that feature but I also suspect it would see significant usage within FlowFuse users.

joepavitt commented 1 year ago

showing relevant data to team members who work at a specific location

The additional difficulty here is that Dashboard 2.0 follows the same architecture as 1.0, whereby there is a single copy of the dashboard/visuals, maintained server-side, so all users would see the same content.

It's a significant shift, although possible, to change this.

joepavitt commented 1 year ago

One thing that I think there is value in is the ability to pass a user identifier into a flow once a user has been authenticated.

Completely agree, I got a basic ui-event node up and running on https://github.com/FlowFuse/node-red-dashboard/tree/274-ui-event this morning, and Ben is taking over to see if we can utilise middleware to inject user data

SynoUser-NL commented 1 year ago

Hi,

With the implementation of FlowFuse we can now have user authentication with Azure AD (SSO) for Node-RED instances even for Dashboards. For our use case however it is imperative that we can see in Node-RED flows who is performing which action in Dashboard v2. With that information available the action can be logged completely (which is a security requirement). And indeed, Dashboard user actions of one user should not visible to other Dashboard users.

Thanks for any efforts in working to make this happen! :) DenW

joepavitt commented 1 year ago

It would be great for us to get a comprehensive list from you for what kind of events you'd be hoping to track? Or re tou thinking, everything?

Button clicks, form inputs, selections, page views, etc?

SynoUser-NL commented 1 year ago

No, we're not looking for anything fancy.. :)

Our primary use case requires a user to fill out a form, which then triggers an action. Sometimes we let the user fill out form fields using a (our of form) dropdown (with either static information or dynamically generated items), but the central user action is always a form submit.

But really, it's not even (web) events we'd like to track. The only things we really need is: 1) user authentication (which has been realised by FlowFuse SSO) 2) to be able to see who (which SSO authenticated user) is triggering a flow from a Dashboard form (i.e. have that user name be available in the message that is sent from the form, or be able to pick that info up in a subsequent node)

Tracking web events like button clicks etc. is something that we're not going to use, so that use case is not for us. If a demo of what we're doing (and how we're doing it) would be beneficial, please let me know. I'd be happy to set this up.

MarianRaphael commented 1 year ago

Thanks @joepavitt , for the description. This would full fill the requirements from: https://github.com/FlowFuse/node-red-dashboard/issues/1

Consider providing the "Widget: UI Event" as the first Dashboard extension because the functionality should be EE.

joepavitt commented 1 year ago

Consider providing the "Widget: UI Event" as the first Dashboard extension because the functionality should be EE.

I understand the thinking here, but I would like to justify why I don't think this is quite the right move, as proposed.

ui-event as a node just sends different socketio topics when users do particular things in the Dashboard, e.g. a page load. This is very easily reproduced using custom nodes, and even if we licensed accordingly, what we are then licensing is very niche to the particular event/topic names, which can just be changed, and therefore no IP infringement.

However, where the EE value is truly added is with the addition of req.user data. So, whilst I propose that ui-event stays Apche 2.0, as per the rest of Dashboard 2.0, the inclusion of user data on any ui-event transmission (and potentially every other event transmitted back from the UI, e.g. button clicks, form submissions), would be EE through and through because that piece would require auth providers anyway.

MarianRaphael commented 1 year ago

Let me understand this better: What is the concrete use case of ui-event if it is not related to "multi-user" scenarios?

joepavitt commented 1 year ago

What is the concrete use case of ui-event if it is not related to "multi-user" scenarios?

There is no single concrete use case of the widget, just as there is no single concrete use case for a ui-button.

As an example though, a user may want to trigger a flow once a page is loaded, automatically calling API updates to render latest data in charts.

joepavitt commented 1 year ago

Playing with event structure here. Want to have a set of defined events, e.g. $pageview, $pageleave. We send these as the topic of the Socket IO event, and we then send a payload which contains appropriate data.

I'm thinking the ui-event node could then send() a message structure like this:

msg = {
    topic: "$pageview"
    payload: {
        page: <page object>
    }
}

Is topic appropriate here? Should it be event? Should event be part of the payload and then we nest what is now payload into payload.data?

Steve-Mcl commented 1 year ago

@joepavitt I see advantaged and disadvantages in either format but feel Format 1 is more intuitive and in-keeping with common convention established in Node-RED

Format 1 (slightly different to your proposal - the payload is the data object (its not in a sub property e.g. payload.page)

msg = {
    topic: "$pageview",
    payload: { ...pageObject }
}

Advantages:

Format 2

msg = {
    payload: { 
        event: "$pageview",
        data: { ...pageObject }
    }
}

Advantages:

Steve-Mcl commented 1 year ago

To provide some no-code means of finer filtering, we might want to consider offering scope and event name separately. For example:

msg = {
    topic: "$pageview",
    event: {
        scope: "$page", // (or "some_future_scope")
        name: "view" // (or "leave" or "...")
    },
    payload: { ...pageObject }
}

We could simplify for MVP - make the topic easily "splitable" e.g. topic: "page:view". The disadvantage is users dont have a simple no-code means of differentiating "$page" events from say "$widget" events.

joepavitt commented 1 year ago

Thanks Steve - I think I'm okay with Option 1 as it stands in that case. I understand the benefit of the broken hierarchy of evens, but cautious of over complicating it.

joepavitt commented 1 year ago

What this has lead me to change though is the Socket IO structure. previously I was emitting the event ui-event:$pageleave and the topic of the widget's ID. Instead, I'm now emitting a ui-event event, with the topic $pageleave. This means that any custom integrations, or ui-template nodes can also trigger the ui-event watcher with their own custom events.