-
Notifications
You must be signed in to change notification settings - Fork 11.7k
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
Live: broadcast events when dashboard is saved #27583
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments, but before I read your description in detail. so missed your own comment on the router thing :)
this subscribes to a channel for each dashboard -- this would let use out-of-the-box centrifuge presence features for dashboards. Alternatively we could have a single channel and manage the notifications internally (not too hard and may be better)
Any pros / cons? I assume a centrifuge channel is just an internal thing for routing events? (so not a new websocket connection). And don't we have to use that in order route events efficiently? (So we do not need implement our own event routing so only browsers who are interested in specific events get's them). For example we only want browsers who have a specific dashboard open to get events related to it, not get events for all open dashboards. So given that I think we need to use a channel per dashboard right?
🕺 |
Yes -- i went in circles on this and yes one channel for each dashboard is the right approach. @torkelo -- I made a bunch of improvements since you looked, I would love feedback :) |
I certainly find this an interesting feature. Hard to say exactly what the default behavior should be for the viewer who gets the new version pushed. |
Sorry for no follow-up review, 7.2 release and fixes have been pressing. And after that, the annotation/exemplar architecture is higher prio |
type dashboardEvent struct { | ||
UID string `json:"uid"` | ||
Action string `json:"action"` // saved, editing | ||
UserID int64 `json:"userId,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working with event systems before, it's always nice if the events are information-rich and more usable standalone.
It would mean including more dashboard & user info here like dashboard name, (maybe a user object, that includes id, login, email, avatarUrl) makes consuming and using these events much easier without requiring further API calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add the whole json model... But I think we would still need to do a full refresh in the current system regardless. If only dashboard were an observable 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was more thinking of other uses for this event (like an admin viewing a list of activity), and for the modal, we might want to show the user name & profile image of the user who updated the same dashboard you have.
So ash much meta info about the entities in the event is usually good. Could also be used by a search or cache subsystem for example to update index state and for that we do not want to issue further db/api calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to add more info now -- but since this is an internal event, I think we should wait and add more info when we have a real use for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was more thinking of other uses for this event
That is info that should be attached on the 'presense' side -- that still needs to be explored some more, but I fear this PR is getting too big as is :)
if (event.message.sessionId === sessionId) { | ||
return; // skip internal messages | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there away to filter this out in liveSrv?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! left a few nits. But yea the typing looks a bit messy.
const dashboardConfig: LiveChannelConfig = { | ||
path: '${uid}', | ||
description: 'Dashboard change events', | ||
variables: [{ value: 'uid', label: '${uid}', description: 'unique id for a dashboard' }], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how are dashboardConfig.variables used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idea here is that this is mostly documentation for what variables exist and what they need to be. Looking now, we should likely remove this until it has something concrete, but I want to be careful that the path based routing has some way to be more constrained
|
||
return ( | ||
<Modal | ||
isOpen={!!!dismiss} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this not the same as !dismiss ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed -- looks like !
and !!!
are identical for a boolean value, but different if the value can be undefined of falsey
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use !Boolean(dismiss)
const radioClass = css` | ||
cursor: pointer; | ||
width: 100%; | ||
padding: 20px; | ||
background: ${config.theme.colors.dropdownBg}; | ||
|
||
&:hover { | ||
background: ${config.theme.colors.formCheckboxBgCheckedHover}; | ||
} | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this feels like a new design system component. Not sure what to do for this PR if there is no current component that fits.
For a new component & we should use useTheme & useStyles
Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
@@ -104,3 +96,17 @@ export class DashboardChangedModal extends PureComponent<Props, State> { | |||
); | |||
} | |||
} | |||
|
|||
const getStyles = (theme: GrafanaTheme) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use stylesFactory here so we only build the styles once
g.running = true | ||
|
||
// Run in the background | ||
go g.runRandomCSV() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this threadsafe? For example if nothing is subscribed to yet, but then two or more clients subscribe at around the same time is there any guarantee that multiple threads running runRandomCSV
won't be started?
Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
func (b *GrafanaLive) Publish(channel string, data []byte) bool { | ||
_, err := b.node.Publish(channel, data) | ||
// GetChannelHandler gives threadsafe access to the channel | ||
func (g *GrafanaLive) GetChannelHandler(channel string) (models.ChannelHandler, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marefr -- can you audit this function? It is called frequently and potentially from multiple threads.
Looking good! Just left some small comments. |
Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
dooh -- just dyslexia and poor spelling. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
When the "live" feature flag is enabled and a dashboard is saved, an event is broadcast to everyone looking at that dashboard.
If the viewer is in edit mode, or has local edits, we show a popup asking what to do. Otherwise the dashboard is updated automatically.