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

feat: Document delta updates (DH-18090) #1119

Merged
merged 17 commits into from
Feb 28, 2025

Conversation

mofojed
Copy link
Member

@mofojed mofojed commented Feb 19, 2025

from deephaven import ui, empty_table
from random import randint
from time import time

counter = 0
_tables = []
for i in range(10):
    _tables.append(empty_table(i).update(f"X{i}=i"))


@ui.component
def delta_test():
    global counter
    items, set_items = ui.use_state([])
    i1, seti1 = ui.use_state(0)
    i2, seti2 = ui.use_state(0)
    colour, set_colour = ui.use_state([255, 255, 255])

    def _handle_add():
        global counter
        num = counter
        set_items(
            lambda old_items: [
                *old_items,
                ui.button(f"{num}", on_press=lambda: print(num)),
                ui.table(_tables[num], width="80px"),
            ]
        )
        counter += 1

    handle_add = ui.use_callback(_handle_add, [])

    def _handle_swap():
        def _swap_items(old_items):
            new_items = [*old_items]
            new_items[i1] = old_items[i2]
            new_items[i2] = old_items[i1]
            return new_items

        set_items(_swap_items)

    handle_swap = ui.use_callback(_handle_swap, [i1, i2])

    handle_delete = ui.use_callback(
        lambda: set_items(lambda old_items: [*old_items[:-1]]), []
    )

    handle_i1_change = ui.use_callback(lambda i: seti1(int(i)), [])
    handle_i2_change = ui.use_callback(lambda i: seti2(int(i)), [])
    handle_color_change = ui.use_callback(
        lambda: set_colour([randint(0, 255), randint(0, 255), randint(0, 255)]), []
    )

    return [
        ui.flex(
            ui.button("Add", on_press=handle_add),
            ui.button("Delete", on_press=handle_delete),
            ui.button("Swap", on_press=handle_swap),
            ui.text_field(value=i1, on_change=handle_i1_change, width="80px"),
            ui.text_field(value=i2, on_change=handle_i2_change, width="80px"),
            ui.button("Colour", on_press=handle_color_change),
            ui.view(
                width="80px",
                background_color=f"rgb({colour[0]}, {colour[1]}, {colour[2]})",
                key="test",
            ),
            max_height="32px",
        ),
        ui.flex(*items, direction="row", flex_grow=1),
    ]


my_delta = delta_test()
  • Checked the browser logs by opening devtools and running DHLog.setLogLevel(10), then filtering on documentUpdated
  • Checked the python logs by running:
import logging
import sys

# Have the root logger output to stdout instead of stderr
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)

# Set the log level for the deephaven.ui logger to DEBUG
logging.getLogger("deephaven.ui.object_types.ElementMessageStream").setLevel(level=logging.DEBUG)

@mofojed mofojed requested a review from mattrunyon February 19, 2025 20:30
@mofojed mofojed self-assigned this Feb 19, 2025
@mofojed mofojed mentioned this pull request Feb 19, 2025
Copy link

ui docs preview (Available for 14 days)

@mofojed mofojed requested a review from mattrunyon February 21, 2025 16:16
- Wire up NodeEncoder and EventEncoder to use it
- Add tests for it as well
Copy link
Collaborator

@mattrunyon mattrunyon left a comment

Choose a reason for hiding this comment

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

Looking pretty good. Just a few minor things

Comment on lines 135 to 145
def _transform_node(self, key: str, value: Any):
if isinstance(value, RenderedNode):
return self._convert_rendered_node(value)
elif callable(value):
return self._convert_callable(value)
elif not is_serializable(value):
# This is a non-serializable object. We'll store a reference to the object in the objects array.
return self._convert_object(value)
else:
# Just return the value itself, it should be serializable
return value
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is an edge case here (that we probably don't need to support) if a dict has non-serializable keys. With the previous code this would hit the except block. Here we'd end up returning a dict with non-serializable keys which would fail to serialize later.

Like I said it probably doesn't matter though as I don't think we should support complex keys

Copy link
Member Author

Choose a reason for hiding this comment

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

Yea in theory I suppose the transform_node should take an Any instead of just a str for the key... though I don't think we want to support that.

- Change name of is_serializable function/functionality
- Clean up some other areas
Copy link

ui docs preview (Available for 14 days)

@mofojed mofojed requested a review from mattrunyon February 26, 2025 19:28
@mofojed mofojed merged commit 3ac3a22 into deephaven:main Feb 28, 2025
16 checks passed
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.

Handle document delta updates sent from the server
3 participants