Skip to content
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

Notifications #225

Merged
merged 37 commits into from
Aug 29, 2024
Merged

Notifications #225

merged 37 commits into from
Aug 29, 2024

Conversation

ginazhouhuiwu
Copy link
Contributor

@ginazhouhuiwu ginazhouhuiwu commented Jun 13, 2024

Can add and clear notifications all using the mantine notifications system! The first notification in the example below disappears because it is set to auto-close after some time.

Screen.Recording.2024-06-12.at.10.19.06.PM.mov

(Currently I'm a bit unsure on the design in accordance with the rest of the gui api.)

TODO:

  • match setter/getter-style properties of other handles

@ginazhouhuiwu
Copy link
Contributor Author

I think add_notification being in the gui api seems reasonable, but the clear_notification part kind of breaks the harmony of the rest of the api. There is probably a cleaner way to organize it, especially if there are future notification features.

@ginazhouhuiwu ginazhouhuiwu marked this pull request as draft June 13, 2024 21:18
@ginazhouhuiwu ginazhouhuiwu marked this pull request as ready for review June 13, 2024 21:46
@ginazhouhuiwu
Copy link
Contributor Author

Should be good to go now!

src/viser/_gui_api.py Outdated Show resolved Hide resolved
src/viser/_gui_api.py Outdated Show resolved Hide resolved
src/viser/_gui_handles.py Outdated Show resolved Hide resolved
@chungmin99
Copy link
Collaborator

chungmin99 commented Jun 18, 2024

For clear_notifications, can we remove them on a per-message basis, Instead of having a global clear? (https://v4.mantine.dev/others/notifications/#functions)

E.g., we can track the message ID and do the following:

case "AddNotificationMessage": {
  notifications.show({
    id: message.id,
    ...
    });
  return;
}

// Clear all notifications.
case "ClearNotificationMessage": {
  notifications.hide(message.id);
  return;
}

... but this would require us to send messages from the GuiNotificationHandle. To this point, I was wondering if we could do:

@dataclasses.dataclass
class GuiNotificationHandle:
    """Handle for a notification in our visualizer."""

    id: str
    ...
    _send_msg_fn: Callable[[Message], None]

    def open(self) -> None:
        self._send_msg_fn(...

and set _send_msg_fn to self._websock_interface.queue_message (mostly to avoid setting gui_api as one of the handle properties).

(We could also use the message.id to update the message later on, etc)

@chungmin99
Copy link
Collaborator

Also curious about people's thoughts, but I feel like the mantine notifications control (autoClose seconds, loading, ) are quite low-level.

Mainly, I can only think of 3 notif types:

  1. disappear both automatically (after 5 seconds) and manually (via click)
  2. can be closed only manually
  3. can be closed only programmatically, via some handle.close()

(and showing loading only makes sense for (3), assuming some "task" is blocking the notification from closing)

@ginazhouhuiwu
Copy link
Contributor Author

ginazhouhuiwu commented Jun 18, 2024

Also curious about people's thoughts, but I feel like the mantine notifications control (autoClose seconds, loading, ) are quite low-level.

I was also thinking about this but was kind of unsure about how to separate them, so thank you for your breakdown of the notif types! I think the abstraction makes a lot of sense and is easy to change.

(changing this pr to draft for now and also realizing that I didn't add docs yet)

@ginazhouhuiwu ginazhouhuiwu marked this pull request as draft June 18, 2024 15:26
@ginazhouhuiwu
Copy link
Contributor Author

Added some different types of notifications as per suggested! Can be indicated via type when declaring a notif.

  1. "persistent" (default): user close
  2. "timed": auto close
  3. "controlled": code close

loading is just an additional optional argument.

I also added an individual notification clear option along with the global clear (can be renamed 'close' for clarity if needed). It has a bit of funky behavior if you open the same notification too many times and just clears all of it, but I actually don't think it's a huge issue irl use cases for now.

Still didn't add docs yet but can easily do so in the end after all design is finalized!

Screen.Recording.2024-06-18.at.6.19.38.PM.mov

@ginazhouhuiwu ginazhouhuiwu marked this pull request as ready for review June 19, 2024 01:27
@ginazhouhuiwu
Copy link
Contributor Author

ginazhouhuiwu commented Jun 21, 2024

I noticed a problem with multiple clients: unless all the notifications are explicitly cleared in the backend (gui.clear_all_notification or notif.clear()), when another client connects or when you reload the window, all the notifications will be reopened. This happens to both timed notifications that are auto-closed as well as the manually closed notifications. The notifications that are code-closed as mentioned earlier, will not reopen. So it looks like we need to explicitly close all the notifications in the backend regardless.

I tried attaching a callback for notifications.show(...onClose: () => notifications.hide(message.id)), but it didn't do anything. Another idea I had is clear the notifications every time a client disconnects, which also didn't solve the problem and is a bit of a poor patchy solution imo... Would appreciate any other ideas!

@brentyi
Copy link
Collaborator

brentyi commented Jun 22, 2024

when another client connects or when you reload the window, all the notifications will be reopened. This happens to both timed notifications that are auto-closed as well as the manually closed notifications.

This seems like the result of some viser state management logic, particularly the concept of "persistent" messages, see:

Broadcasted messages are persistent: if a new client connects to the server,
they will receive a buffered set of previously broadcasted messages. The buffer
is culled using the value of `message.redundancy_key()`."""

as well as references to the redundancy_key() method: https://github.com/search?q=repo%3Anerfstudio-project%2Fviser%20redundancy_key&type=code

This is usually nice, since when we make scene or GUI updates we want them to take effect even for new clients, but it does complicate the notification logic. It shouldn't be too hard to fix, but we'd need to figure out what the expected behavior is:

  • if we broadcast a notification, then a new client connects, should the new client receive the notification at all?
  • if we broadcast a notification that autocloses in 5 seconds, then a new client connects 1 second later, is the notification shown for 4 seconds or 5 seconds?
  • if a notification is closed from one client, does it get closed in the others as well?
  • etc

@jkulhanek
Copy link
Contributor

Actually, would it be possible to disable the automatic synchronization between clients? Make it an opt-in feature (not default)? What do you think?

@ginazhouhuiwu
Copy link
Contributor Author

if we broadcast a notification, then a new client connects, should the new client receive the notification at all?

I imagine in some cases, notifications would be client-specific (e.g. rendering a video, downloading things, etc), so a new client should not receive the same set of notifications. But I can also think of some cases where everybody should receive all the notifs (e.g. training complete). Mostly speaking from a nerfstudio pov.

Does this mean that all connected clients would always receive all the broadcasted notifications though? I guess this question applies to the other things to consider. I feel like there are these two types of notifications in terms of broadcasting (global or client-specific). But I'm unsure if making this distinction between the two types of notifications will make it inconvenient for users and if client-specific messages are even possible.

@brentyi
Copy link
Collaborator

brentyi commented Jun 25, 2024

I guess this question applies to the other things to consider. I feel like there are these two types of notifications in terms of broadcasting (global or client-specific). But I'm unsure if making this distinction between the two types of notifications will make it inconvenient for users and if client-specific messages are even possible.

I think this should be already supported actually, if you call client.gui.add_notification then the notification will only go to a single client. If you want to test you can get the client handle from the GUI callback like in this example: https://viser.studio/latest/examples/19_get_renders/

@ginazhouhuiwu
Copy link
Contributor Author

Ok that makes sense, for client notifications! Then I think the behavior for global broadcasting of notifications should be:

if we broadcast a notification, then a new client connects, should the new client receive the notification at all?

Yes, since the broadcasted notification isn't client specific then everybody should probably receive it.

if we broadcast a notification that autocloses in 5 seconds, then a new client connects 1 second later, is the notification shown for 4 seconds or 5 seconds?

I don't feel super strongly about this. I do think having the full temporary display of notification makes slightly more sense for users, so somebody doesn't get stuck with a 0.5 second notification that immediately disappears. But whatever makes the implementation cleaner I'm ok with.

if a notification is closed from one client, does it get closed in the others as well?

I don't think so, I think clients should control their own notification queue.

Let me know if you have any thoughts.

@ginazhouhuiwu ginazhouhuiwu marked this pull request as draft July 13, 2024 00:34
@ginazhouhuiwu ginazhouhuiwu marked this pull request as ready for review August 26, 2024 04:33
Copy link
Collaborator

@brentyi brentyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎊

@brentyi brentyi changed the title Basic notifications Notifications Aug 29, 2024
@brentyi brentyi merged commit 2e09df7 into main Aug 29, 2024
9 checks passed
@brentyi brentyi deleted the gina/notification branch August 29, 2024 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants