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: ui.fragment, ui.tabs, ui.tab_list, ui.tab_panels #138

Merged
merged 5 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docker/data/storage/notebooks/DEMO.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,32 @@ def order_table():

result = order_table()
```

## Using Tabs

You can add [Tabs](https://react-spectrum.adobe.com/react-spectrum/Tabs.html) within a panel by using the `ui.tabs` method. In this example, we create a tabbed panel with multiple tabs:

- Unfiltered table
- Table filtered on sym `CAT`. We also include an icon in the tab header.
- Table filtered on sym `DOG`

```python
@ui.component
def table_tabs(source):
return ui.tabs(
ui.tab_list(
ui.item("Unfiltered", key="Unfiltered"),
ui.item(ui.icon("vsGithubAlt"), "CAT", key="CAT"),
ui.item("DOG", key="DOG"),
),
ui.tab_panels(
ui.item(source, key="Unfiltered"),
ui.item(source.where("sym=`CAT`"), key="CAT"),
ui.item(source.where("sym=`DOG`"), key="DOG"),
),
flex_grow=1,
)


result = table_tabs(stocks)
```
67 changes: 35 additions & 32 deletions plugins/ui/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,15 @@ ui_table.sort(
| `by` | `str \| Sequence[str]` | The column(s) to sort by. May be a single column name, or a list of column names. |
| `direction` | `SortDirection \| Sequence[SortDirection] \| None` | The sort direction(s) to use. If provided, that must match up with the columns provided. Defaults to "ASC". |

#### ui.fragment

A fragment maps to a [React.Fragment](https://react.dev/reference/react/Fragment). This lets you group elements without using a wrapper node. It only takes children, and does not take any additional props.

```py
import deephaven.ui as ui
ui_fragment = ui.fragment(*children: Element) -> Element
```

#### Deprecations

The functionality provided my `ui.table` replaces some of the existing functions on `Table`. Below are the functions that are planned for deprecation/deletion of the `Table` interface, and their replacements with the new `ui.table` interface.
Expand Down Expand Up @@ -1450,7 +1459,7 @@ use_table_listener(

Capture the data in a table. If the table is still loading, a sentinel value will be returned.
Data should already be filtered to the desired rows and columns before passing to this hook as it is best to filter before data is retrieved.
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve specific rows and functions such
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve specific rows and functions such
as [select or view](https://deephaven.io/core/docs/how-to-guides/use-select-view-update/) to retrieve specific columns.

###### Syntax
Expand All @@ -1464,17 +1473,16 @@ use_table_data(

###### Parameters

| Parameter | Type | Description |
|--------------------|--------------------------------------|------------------------------------------------------------------------------|
| `table` | `Table` | The table to retrieve data from. |
| `sentinel` | `Sentinel` | A sentinel value to return if the viewport is still loading. Default `None`. |

| Parameter | Type | Description |
| ---------- | ---------- | ---------------------------------------------------------------------------- |
| `table` | `Table` | The table to retrieve data from. |
| `sentinel` | `Sentinel` | A sentinel value to return if the viewport is still loading. Default `None`. |

##### use_column_data

Capture the data in a column. If the table is still loading, a sentinel value will be returned.
Data should already be filtered to desired rows and a specific column before passing to this hook as it is best to filter before data is retrieved and this hook will only return data for the first column.
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve specific rows and functions such
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve specific rows and functions such
as [select or view](https://deephaven.io/core/docs/how-to-guides/use-select-view-update/) to retrieve a specific column.

###### Syntax
Expand All @@ -1488,17 +1496,16 @@ use_column_data(

###### Parameters

| Parameter | Type | Description |
|-------------------|-----------------|----------------------------------------------------------------------------|
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the column is still loading. Default `None`. |

| Parameter | Type | Description |
| ---------- | ---------- | -------------------------------------------------------------------------- |
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the column is still loading. Default `None`. |

##### use_row_data

Capture the data in a row. If the table is still loading, a sentinel value will be returned.
Data should already be filtered to a single row and desired columns before passing to this hook as it is best to filter before data is retrieved and this hook will only return data for the first row.
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve a specific row and functions such
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve a specific row and functions such
as [select or view](https://deephaven.io/core/docs/how-to-guides/use-select-view-update/) to retrieve specific columns.

###### Syntax
Expand All @@ -1512,17 +1519,16 @@ use_row_data(

###### Parameters

| Parameter | Type | Description |
|------------|--------------------------------------|----------------------------------------------------------------------------------|
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the row is still loading. Default `None`. |

| Parameter | Type | Description |
| ---------- | ---------- | ----------------------------------------------------------------------- |
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the row is still loading. Default `None`. |

##### use_row_list

Capture the data in a row. If the table is still loading, a sentinel value will be returned. This function is identical to `use_row_data` except that it always returns a list of data instead of a `RowData` object for convenience.
Data should already be filtered to a single row and desired columns before passing to this hook as it is best to filter before data is retrieved and this hook will only return data for the first row.
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve a specific row and functions such
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve a specific row and functions such
as [select or view](https://deephaven.io/core/docs/how-to-guides/use-select-view-update/) to retrieve specific columns.

###### Syntax
Expand All @@ -1536,18 +1542,18 @@ use_row_list(

###### Parameters

| Parameter | Type | Description |
|------------|--------------------------------------|----------------------------------------------------------------------------------|
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the row is still loading. Default `None`. |

| Parameter | Type | Description |
| ---------- | ---------- | ----------------------------------------------------------------------- |
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the row is still loading. Default `None`. |

##### use_cell_data

Capture the data in a cell. If the table is still loading, a sentinel value will be returned.
Data should already be filtered to a single row and column before passing to this hook as it is best to filter before data is retrieved and this hook will only return data for the first cell.
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve a specific row and functions such
Use functions such as [head](https://deephaven.io/core/docs/reference/table-operations/filter/head/) or [slice](https://deephaven.io/core/docs/reference/table-operations/filter/slice/) to retrieve a specific row and functions such
as [select or view](#https://deephaven.io/core/docs/how-to-guides/use-select-view-update/) to retrieve a specific column.

```py
use_cell_data(
table: Table,
Expand All @@ -1557,11 +1563,10 @@ use_cell_data(

###### Parameters

| Parameter | Type | Description |
|-------------|--------------------------------------|--------------------------------------------------------------------------|
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the cell is still loading. Default `None`. |

| Parameter | Type | Description |
| ---------- | ---------- | ------------------------------------------------------------------------ |
| `table` | `Table` | The table to create a viewport on. |
| `sentinel` | `Sentinel` | A sentinel value to return if the cell is still loading. Default `None`. |

#### Custom Types

Expand Down Expand Up @@ -1635,8 +1640,6 @@ class LinkPoint(TypedDict):

```



#### Context

By default, the context of a `@ui.component` will be created per client session (same as [Parameterized Query's "parallel universe" today](https://github.com/deephaven-ent/iris/blob/868b868fc9e180ee948137b10b6addbac043605e/ParameterizedQuery/src/main/java/io/deephaven/query/parameterized/impl/ParameterizedQueryServerImpl.java#L140)). However, it would be interesting if it were possible to share a context among all sessions for the current user, and/or share a context with other users even; e.g. if one user selects and applies a filter, it updates immediately for all other users with that dashboard open. So three cases:
Expand Down
75 changes: 55 additions & 20 deletions plugins/ui/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ dt = double_table(stocks)

## Stock rollup

You can use the `rollup` method to create a rollup table. In this example, we create a rollup table that shows the average price of each stock and/or exchange. You can toggle the rollup by clicking on the [ToggleButton](https://react-spectrum.adobe.com/react-spectrum/ToggleButton.html). You can also highlight a specific stock by entering the symbol in the text field.
You can use the `rollup` method to create a rollup table. In this example, we create a rollup table that shows the average price of each stock and/or exchange. You can toggle the rollup by clicking on the [ToggleButton](https://react-spectrum.adobe.com/react-spectrum/ToggleButton.html). You can also highlight a specific stock by entering the symbol in the text field, but only when a rollup option isn't selected. We wrap the highlight input field with a `ui.fragment` that is conditionally used so that it doesn't appear when the rollup is selected. We also use the `ui.contextual_help` component to display a help message when you hover over the help icon.

```python
import deephaven.ui as ui
Expand All @@ -584,11 +584,10 @@ stocks = dx.data.stocks()
def get_by_filter(**byargs):
"""
Gets a by filter where the arguments are all args passed in where the value is true.

Examples:
get_by_filter(sym=True, exchange=False) == ["sym"]
get_by_filter(exchange=False) == []
get_by_filter(sym=True, exchange=True) == ["sym", "exchange"]
e.g.
get_by_filter(sym=True, exchange=False) == ["sym"]
get_by_filter(exchange=False) == []
get_by_filter(sym=True, exchange=True) == ["sym", "exchange"]

"""
return [k for k in byargs if byargs[k]]
Expand All @@ -608,10 +607,7 @@ def stock_table(source):
[source, highlight],
)
rolled_table = use_memo(
lambda: formatted_table
if len(by) == 0
else formatted_table.rollup(aggs=aggs, by=by),
[formatted_table, aggs, by],
lambda: t if len(by) == 0 else t.rollup(aggs=aggs, by=by), [t, aggs, by]
)

return ui.flex(
Expand All @@ -620,16 +616,20 @@ def stock_table(source):
ui.toggle_button(
ui.icon("vsBell"), "By Exchange", on_change=set_is_exchange
),
ui.text_field(
label="Highlight Sym",
label_position="side",
value=highlight,
on_change=set_highlight,
),
ui.contextual_help(
ui.heading("Highlight Sym"),
ui.content("Enter a sym you would like highlighted."),
),
ui.fragment(
ui.text_field(
label="Highlight Sym",
label_position="side",
value=highlight,
on_change=set_highlight,
),
ui.contextual_help(
ui.heading("Highlight Sym"),
ui.content("Enter a sym you would like highlighted."),
),
)
if not is_sym and not is_exchange
else None,
align_items="center",
gap="size-100",
margin="size-100",
Expand Down Expand Up @@ -711,3 +711,38 @@ monitor = monitor_changed_data(t)
```

![Stock Rollup](assets/change_monitor.png)

## Tabs

You can add [Tabs](https://react-spectrum.adobe.com/react-spectrum/Tabs.html) within a panel by using the `ui.tabs` method. In this example, we create a tabbed panel with multiple tabs:

- Unfiltered table
- Table filtered on sym `CAT`. We also include an icon in the tab header.
- Table filtered on sym `DOG`

```python
from deephaven import ui
from deephaven.plot import express as dx

stocks = dx.data.stocks()


@ui.component
def table_tabs(source):
return ui.tabs(
ui.tab_list(
ui.item("Unfiltered", key="Unfiltered"),
ui.item(ui.icon("vsGithubAlt"), "CAT", key="CAT"),
ui.item("DOG", key="DOG"),
),
ui.tab_panels(
ui.item(source, key="Unfiltered"),
ui.item(source.where("sym=`CAT`"), key="CAT"),
ui.item(source.where("sym=`DOG`"), key="DOG"),
),
flex_grow=1,
)


tt = table_tabs(stocks)
```
6 changes: 6 additions & 0 deletions plugins/ui/src/deephaven/ui/components/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .icon import icon
from .make_component import make_component as component
from .fragment import fragment
from .panel import panel
from .spectrum import *
from .table import table
Expand All @@ -16,19 +17,24 @@
"contextual_help",
"flex",
"form",
"fragment",
"grid",
"heading",
"icon",
"icon_wrapper",
"illustrated_message",
"html",
"number_field",
"item",
"panel",
"range_slider",
"slider",
"spectrum_element",
"switch",
"table",
"tab_list",
"tab_panels",
"tabs",
"text",
"text_field",
"toggle_button",
Expand Down
15 changes: 15 additions & 0 deletions plugins/ui/src/deephaven/ui/components/fragment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import annotations

from typing import Any
from ..elements import BaseElement


def fragment(*children: Any):
"""
A React.Fragment: https://react.dev/reference/react/Fragment.
Used to group elements together without a wrapper node.

Args:
children: The children in the fragment.
"""
return BaseElement("deephaven.ui.components.Fragment", children=children)
34 changes: 33 additions & 1 deletion plugins/ui/src/deephaven/ui/components/spectrum/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def action_button(*children, **props):
return spectrum_element("ActionButton", *children, **props)


def button(*children, **props):
def button(*children, **props: int):
mofojed marked this conversation as resolved.
Show resolved Hide resolved
"""
Python implementation for the Adobe React Spectrum Button component.
https://react-spectrum.adobe.com/react-spectrum/Button.html
Expand Down Expand Up @@ -83,6 +83,14 @@ def icon_wrapper(*children, **props):
return spectrum_element("Icon", *children, **props)


def item(*children, **props):
"""
Python implementation for the Adobe React Spectrum Item component.
Used with Tabs: https://react-spectrum.adobe.com/react-spectrum/Tabs.html
"""
return spectrum_element("Item", *children, **props)


def illustrated_message(*children, **props):
"""
Python implementation for the Adobe React Spectrum IllustratedMessage component.
Expand Down Expand Up @@ -131,6 +139,30 @@ def switch(*children, **props):
return spectrum_element("Switch", *children, **props)


def tabs(*children, **props):
"""
Python implementation for the Adobe React Spectrum Tabs component.
https://react-spectrum.adobe.com/react-spectrum/Tabs.html
"""
return spectrum_element("Tabs", *children, **props)


def tab_list(*children, **props):
"""
Python implementation for the Adobe React Spectrum TabList component.
https://react-spectrum.adobe.com/react-spectrum/Tabs.html
"""
return spectrum_element("TabList", *children, **props)


def tab_panels(*children, **props):
"""
Python implementation for the Adobe React Spectrum TabPanels component.
https://react-spectrum.adobe.com/react-spectrum/Tabs.html
"""
return spectrum_element("TabPanels", *children, **props)


def text(*children, **props):
"""
Python implementation for the Adobe React Spectrum Text component.
Expand Down
Loading