forked from deephaven/deephaven-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clean up docs a bit more. .. image assets aren't working though
- And I don't know why not
- Loading branch information
Showing
83 changed files
with
803 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,32 @@ | ||
# deephaven.ui documentation | ||
|
||
deephaven.ui is a plugin for Deephaven that allows for programmatic layouts and callbacks. It uses a React-like approach to building components and rendering them in the UI, allowing for creating reactive components that can be re-used and composed together, as well as reacting to user input from the UI. | ||
|
||
## Getting Started | ||
|
||
First, follow the guide to [Start a Deephaven Server](https://deephaven.io/core/docs/tutorials/pip-install/). Then, install the deephaven.ui plugin using `pip install`: | ||
|
||
```sh | ||
pip install deephaven-ui | ||
``` | ||
|
||
You'll then need to restart your Deephaven server to load the plugin. | ||
|
||
Once you have the Deephaven up, you can assign deephaven.ui components to variables and display them in the UI. For example, to display a simple button: | ||
|
||
```python | ||
from deephaven import ui | ||
|
||
my_button = ui.button("Click Me!", on_press=lambda e: print(f"Button was clicked! {e}")) | ||
``` | ||
|
||
## Contents | ||
|
||
```{toctree} | ||
:maxdepth: 3 | ||
:caption: Contents | ||
:glob: | ||
tutorials/* | ||
components/README | ||
hooks/README | ||
architecture | ||
``` |
Binary file not shown.
Binary file not shown.
Binary file modified
BIN
+38 Bytes
(100%)
plugins/ui/sphinx-docs/_build/doctrees/components/README.doctree
Binary file not shown.
Binary file modified
BIN
+1.17 KB
(100%)
plugins/ui/sphinx-docs/_build/doctrees/components/buttons/action_button.doctree
Binary file not shown.
Binary file modified
BIN
+28.3 KB
(110%)
plugins/ui/sphinx-docs/_build/doctrees/components/buttons/button.doctree
Binary file not shown.
Binary file modified
BIN
+1.62 KB
(100%)
plugins/ui/sphinx-docs/_build/doctrees/components/buttons/button_group.doctree
Binary file not shown.
Binary file modified
BIN
+723 Bytes
(100%)
plugins/ui/sphinx-docs/_build/doctrees/components/content/flex.doctree
Binary file not shown.
Binary file added
BIN
+37.4 KB
plugins/ui/sphinx-docs/_build/doctrees/components/content/fragment.doctree
Binary file not shown.
Binary file modified
BIN
+1.91 KB
(140%)
plugins/ui/sphinx-docs/_build/doctrees/components/content/icon.doctree
Binary file not shown.
Binary file modified
BIN
+939 Bytes
(100%)
plugins/ui/sphinx-docs/_build/doctrees/components/content/table.doctree
Binary file not shown.
Binary file modified
BIN
+1.16 KB
(100%)
plugins/ui/sphinx-docs/_build/doctrees/components/inputs/picker.doctree
Binary file not shown.
Binary file modified
BIN
+2.36 KB
(130%)
plugins/ui/sphinx-docs/_build/doctrees/components/layout/column.doctree
Binary file not shown.
Binary file modified
BIN
+2.36 KB
(140%)
plugins/ui/sphinx-docs/_build/doctrees/components/layout/dashboard.doctree
Binary file not shown.
Binary file modified
BIN
+951 Bytes
(110%)
plugins/ui/sphinx-docs/_build/doctrees/components/layout/panel.doctree
Binary file not shown.
Binary file modified
BIN
+2.36 KB
(130%)
plugins/ui/sphinx-docs/_build/doctrees/components/layout/row.doctree
Binary file not shown.
Binary file modified
BIN
+2.25 KB
(120%)
plugins/ui/sphinx-docs/_build/doctrees/components/layout/stack.doctree
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# Architecture | ||
|
||
Detailed architecture of the deephaven.ui plugin. | ||
|
||
## Rendering | ||
|
||
When you call a function decorated by `@ui.component`, it will return an `Element` object that has a reference to the function it is decorated; that is to say, the function does *not* get run immediately. The function is only run when the `Element` is rendered by the client, and the result is sent back to the client. This allows the `@ui.component` decorator to execute the function with the appropriate rendering context. The client must also set the initial state before rendering, allowing the client to persist the state and re-render in the future. | ||
|
||
Let’s say we execute the following, where a table is filtered based on the value of a text input: | ||
|
||
```python | ||
from deephaven import ui | ||
|
||
|
||
@ui.component | ||
def text_filter_table(source, column, initial_value=""): | ||
value, set_value = ui.use_state(initial_value) | ||
ti = ui.text_field(value=value, on_change=set_value) | ||
tt = source.where(f"{column}=`{value}`") | ||
return [ti, tt] | ||
|
||
|
||
# This will render two panels, one filtering the table by Sym, and the other by Exchange | ||
@ui.component | ||
def double_text_filter_table(source): | ||
tft1 = text_filter_table(source, "sym") | ||
tft2 = text_filter_table(source, "exchange") | ||
return ui.panel(tft1, title="Sym"), ui.panel(tft2, title="Exchange") | ||
|
||
|
||
import deephaven.plot.express as dx | ||
|
||
_stocks = dx.data.stocks() | ||
|
||
tft = double_text_filter_table(_stocks) | ||
``` | ||
|
||
Which should result in a UI like this: | ||
|
||
![Double Text Filter Tables](assets/double-tft.png) | ||
|
||
How does that look when the notebook is executed? When does each code block execute? | ||
|
||
```mermaid | ||
sequenceDiagram | ||
participant U as User | ||
participant W as Web UI | ||
participant UIP as UI Plugin | ||
participant C as Core | ||
participant SP as Server Plugin | ||
U->>W: Run notebook | ||
W->>C: Execute code | ||
C->>SP: is_type(object) | ||
SP-->>C: Matching plugin | ||
C-->>W: VariableChanges(added=[t, tft]) | ||
W->>UIP: Open tft | ||
UIP->>C: Export tft | ||
C-->>UIP: tft (Element) | ||
Note over UIP: UI knows about object tft<br/>double_text_filter_table not executed yet | ||
UIP->>SP: Render tft (initialState) | ||
SP->>SP: Run double_text_filter_table | ||
Note over SP: double_text_filter_table executes, running text_filter_table twice | ||
SP-->>UIP: Result (document=[panel(tft1), pane(tft2)], exported_objects=[tft1, tft2]) | ||
UIP-->>W: Display Result | ||
U->>UIP: Change text input 1 | ||
UIP->>SP: Change state | ||
SP->>SP: Run double_text_filter_table | ||
Note over SP: double_text_filter_table executes, text_filter_table only <br/>runs once for the one changed input<br/>only exports the new table, as client already has previous tables | ||
SP-->>UIP: Result (document=[panel(tft1'), panel(tft2)], state={}, exported_objects=[tft1']) | ||
UIP-->>W: Display Result | ||
``` | ||
|
||
## Communication/Callbacks | ||
|
||
When the document is first rendered, it will pass the entire document to the client. When the client makes a callback, it needs to send a message to the server indicating which callback it wants to trigger, and with which parameters. For this, we use [JSON-RPC](https://www.jsonrpc.org/specification). When the client opens the message stream to the server, the communication looks like: | ||
|
||
```mermaid | ||
sequenceDiagram | ||
participant UIP as UI Plugin | ||
participant SP as Server Plugin | ||
Note over UIP, SP: Uses JSON-RPC | ||
UIP->>SP: setState(initialState) | ||
SP-->>UIP: documentUpdated(Document, State) | ||
loop Callback | ||
UIP->>SP: foo(params) | ||
SP-->>UIP: foo result | ||
SP->>UIP: documentUpdated(Document, State) | ||
Note over UIP: Client can store State to restore the same state later | ||
end | ||
``` | ||
|
||
## Communication Layers | ||
|
||
A component that is created on the server side runs through a few steps before it is rendered on the client side: | ||
|
||
1. [Element](../src/deephaven/ui/elements/Element.py) - The basis for all UI components. Generally a [FunctionElement](../src/deephaven/ui/elements/FunctionElement.py) created by a script using the [@ui.component](../src/deephaven/ui/components/make_component.py) decorator, and does not run the function until it is rendered. The result can change depending on the context that it is rendered in (e.g. what “state” is set). | ||
2. [ElementMessageStream](../src/deephaven/ui/object_types/ElementMessageStream.py) - The `ElementMessageStream` is responsible for rendering one instance of an element in a specific rendering context and handling the server-client communication. The element is rendered to create a [RenderedNode](../src/deephaven/ui/renderer/RenderedNode.py), which is an immutable representation of a rendered document. The `RenderedNode` is then encoded into JSON using [NodeEncoder](../src/deephaven/ui/renderer/NodeEncoder.py), which pulls out all the non-serializable objects (such as Tables) and maps them to exported objects, and all the callables to be mapped to commands that can be accepted by JSON-RPC. This is the final representation of the document that is sent to the client, and ultimately handled by the `WidgetHandler`. | ||
3. [DashboardPlugin](../src/js/src/DashboardPlugin.tsx) - Client side `DashboardPlugin` that listens for when a widget of type `Element` is opened, and manage the `WidgetHandler` instances that are created for each widget. | ||
4. [WidgetHandler]() - Uses JSON-RPC communication with an `ElementMessageStream` instance to load the initial rendered document and associated exported objects. Listens for any changes and updates the document accordingly. | ||
5. [DocumentHandler]() - Handles the root of a rendered document, laying out the appropriate panels or dashboard specified. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 13 additions & 2 deletions
15
plugins/ui/sphinx-docs/_build/markdown/components/content/flex.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,15 @@ | ||
### deephaven.ui.flex(\*children: Any, direction: Literal['row', 'column', 'row-reverse', 'column-reverse'] | None = None, wrap: Literal['wrap', 'nowrap', 'wrap-reverse'] | None = None, justify_content: Literal['start', 'end', 'center', 'left', 'right', 'space-between', 'space-around', 'space-evenly', 'stretch', 'baseline', 'first baseline', 'last baseline', 'safe center', 'unsafe center'] | None = None, align_content: Literal['start', 'end', 'center', 'space-between', 'space-around', 'space-evenly', 'stretch', 'baseline', 'first baseline', 'last baseline', 'safe center', 'unsafe center'] | None = None, align_items: Literal['start', 'end', 'center', 'stretch', 'self-start', 'self-end', 'baseline', 'first baseline', 'last baseline', 'safe center', 'unsafe center'] | None = None, gap: str | int | float | None = 'size-100', column_gap: str | int | float | None = None, row_gap: str | int | float | None = None, \*\*props: Any) | ||
|
||
Python implementation for the Adobe React Spectrum Flex component. | ||
[https://react-spectrum.adobe.com/react-spectrum/Flex.html](https://react-spectrum.adobe.com/react-spectrum/Flex.html) | ||
Based on Spectrum’s [Flex](https://react-spectrum.adobe.com/react-spectrum/Flex.html) component. | ||
Displays children in a flex layout. | ||
|
||
Usage: | ||
|
||
```python | ||
my_flex = ui.flex( | ||
ui.text("Hello"), | ||
ui.text("World"), | ||
direction="column", | ||
gap="size-200", | ||
) | ||
``` |
15 changes: 15 additions & 0 deletions
15
plugins/ui/sphinx-docs/_build/markdown/components/content/fragment.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
### deephaven.ui.flex(\*children: Any, direction: Literal['row', 'column', 'row-reverse', 'column-reverse'] | None = None, wrap: Literal['wrap', 'nowrap', 'wrap-reverse'] | None = None, justify_content: Literal['start', 'end', 'center', 'left', 'right', 'space-between', 'space-around', 'space-evenly', 'stretch', 'baseline', 'first baseline', 'last baseline', 'safe center', 'unsafe center'] | None = None, align_content: Literal['start', 'end', 'center', 'space-between', 'space-around', 'space-evenly', 'stretch', 'baseline', 'first baseline', 'last baseline', 'safe center', 'unsafe center'] | None = None, align_items: Literal['start', 'end', 'center', 'stretch', 'self-start', 'self-end', 'baseline', 'first baseline', 'last baseline', 'safe center', 'unsafe center'] | None = None, gap: str | int | float | None = 'size-100', column_gap: str | int | float | None = None, row_gap: str | int | float | None = None, \*\*props: Any) | ||
|
||
Based on Spectrum’s [Flex](https://react-spectrum.adobe.com/react-spectrum/Flex.html) component. | ||
Displays children in a flex layout. | ||
|
||
Usage: | ||
|
||
```python | ||
my_flex = ui.flex( | ||
ui.text("Hello"), | ||
ui.text("World"), | ||
direction="column", | ||
gap="size-200", | ||
) | ||
``` |
Oops, something went wrong.