Open ginazhouhuiwu opened 2 weeks ago
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.
Should be good to go now!
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)
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:
handle.close()
(and showing loading
only makes sense for (3), assuming some "task" is blocking the notification from closing)
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)
Added some different types of notifications as per suggested! Can be indicated via type
when declaring a notif.
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!
https://github.com/nerfstudio-project/viser/assets/42229107/5196024c-eb8a-467a-8669-85e9d46fb649
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!
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:
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:
Actually, would it be possible to disable the automatic synchronization between clients? Make it an opt-in feature (not default)? What do you think?
Actually, would it be possible to disable the automatic synchronization between clients?
Do you mean for everything, including both GUI elements and scene elements?
Disabling synchronization seems hard without some API changes. Notably, attributes like .value
currently make sense to read when we know that they should be consistent across all clients:
text_handle = server.gui.add_text("Some text input")
while True:
print(text_handle.value) # Makes sense because all clients have the same value for this input.
time.sleep(1.0)
But things become more complicated if different clients can have different values for the text input. To support this use case we do support creating separate handles for each client though, eg via client.gui.add_text()
.
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.
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/
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.
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.
https://github.com/nerfstudio-project/viser/assets/42229107/9a080da8-1751-4392-9bd5-fcf794d54fd4
(Currently I'm a bit unsure on the design in accordance with the rest of the gui api.)
TODO: