Skip to content

Commit

Permalink
feat: Add ui.table press event listener support
Browse files Browse the repository at this point in the history
- Depends on my web PR: deephaven/web-client-ui#1857
- Passes through the on_*_press events to IrisGrid
- Tested with the snippet from the examples, ensured all events were being printed with the correct information:
```python
import deephaven.ui as ui
import deephaven.plot.express as dx

te = (
    ui.table(dx.data.stocks())
    .on_row_press(lambda row, data: print(f"Row Press: {row}, {data}"))
    .on_row_double_press(lambda row, data: print(f"Row Double Press: {row}, {data}"))
    .on_cell_press(
        lambda cell_index, data: print(f"Cell Press: {cell_index}, {data}")
    )
    .on_cell_double_press(
        lambda cell_index, data: print(f"Cell Double Press: {cell_index}, {data}")
    )
    .on_column_press(lambda column: print(f"Column Press: {column}"))
    .on_column_double_press(
        lambda column: print(f"Column Double Press: {column}")
    )
)
```
  • Loading branch information
mofojed committed Mar 7, 2024
1 parent 5bef1a4 commit e466684
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 86 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

148 changes: 80 additions & 68 deletions plugins/ui/DESIGN.md

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions plugins/ui/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,33 @@ def stock_table_input(source, default_sym="", default_exchange=""):
sti = stock_table_input(stocks, "CAT", "TPET")
```

### ui.table Events

The `ui.table` component has a few events that you can listen to. You can listen to different kinds of press events that include the data about the region pressed.

```py
import deephaven.ui as ui
import deephaven.plot.express as dx

te = (
ui.table(dx.data.stocks())
.on_row_press(lambda row, data: print(f"Row Press: {row}, {data}"))
.on_row_double_press(lambda row, data: print(f"Row Double Press: {row}, {data}"))
.on_cell_press(
lambda cell_index, data: print(f"Cell Press: {cell_index}, {data}")
)
.on_cell_double_press(
lambda cell_index, data: print(f"Cell Double Press: {cell_index}, {data}")
)
.on_column_press(lambda column: print(f"Column Press: {column}"))
.on_column_double_press(
lambda column: print(f"Column Double Press: {column}")
)
)
```

![Table events](table_events.png)

## Re-using components

In a previous example, we created a text_filter_table component. We can re-use that component, and display two tables with an input filter side-by-side:
Expand Down
Binary file added plugins/ui/examples/assets/table_events.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 64 additions & 4 deletions plugins/ui/src/deephaven/ui/elements/UITable.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
Color,
ContextMenuAction,
CellIndex,
CellPressCallback,
ColumnPressCallback,
RowData,
ContextMenuMode,
DataBarAxis,
Expand Down Expand Up @@ -278,9 +280,13 @@ def color_row(

def context_menu(
self,
items: ContextMenuAction
| list[ContextMenuAction]
| Callable[[CellIndex, RowData], ContextMenuAction | list[ContextMenuAction]],
items: (
ContextMenuAction
| list[ContextMenuAction]
| Callable[
[CellIndex, RowData], ContextMenuAction | list[ContextMenuAction]
]
),
mode: ContextMenuMode = "CELL",
) -> "UITable":
"""
Expand Down Expand Up @@ -407,7 +413,7 @@ def on_row_press(self, callback: RowPressCallback) -> "UITable":
Returns:
A new UITable
"""
raise NotImplementedError()
return self._with_prop("on_row_press", callback)

def on_row_double_press(self, callback: RowPressCallback) -> "UITable":
"""
Expand All @@ -423,6 +429,60 @@ def on_row_double_press(self, callback: RowPressCallback) -> "UITable":
"""
return self._with_prop("on_row_double_press", callback)

def on_cell_press(self, callback: CellPressCallback) -> "UITable":
"""
Add a callback for when a cell is clicked.
Args:
callback: The callback function to run when a cell is clicked.
The first parameter is the cell index, and the second is the row data provided in a dictionary where the
column names are the keys.
Returns:
A new UITable
"""
return self._with_prop("on_cell_press", callback)

def on_cell_double_press(self, callback: CellPressCallback) -> "UITable":
"""
Add a callback for when a cell is double clicked.
Args:
callback: The callback function to run when a cell is double clicked.
The first parameter is the cell index, and the second is the row data provided in a dictionary where the
column names are the keys.
Returns:
A new UITable
"""
return self._with_prop("on_cell_double_press", callback)

def on_column_press(self, callback: ColumnPressCallback) -> "UITable":
"""
Add a callback for when a column is clicked.
Args:
callback: The callback function to run when a column is clicked.
The first parameter is the column name.
Returns:
A new UITable
"""
return self._with_prop("on_column_press", callback)

def on_column_double_press(self, callback: ColumnPressCallback) -> "UITable":
"""
Add a callback for when a column is double clicked.
Args:
callback: The callback function to run when a column is double clicked.
The first parameter is the column name.
Returns:
A new UITable
"""
return self._with_prop("on_column_double_press", callback)

def quick_filter(
self, filter: dict[ColumnName, QuickFilterExpression]
) -> "UITable":
Expand Down
71 changes: 63 additions & 8 deletions plugins/ui/src/deephaven/ui/types/types.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,70 @@
from typing import Any, Dict, Literal, Union, List, Tuple, Optional, Callable, TypedDict
from typing import Any, Dict, Literal, Union, List, Tuple, Callable, TypedDict
from deephaven import SortDirection

RowIndex = Optional[int]

class CellData(TypedDict):
"""
Data for one cell. Returned with click handlers.
"""

type: str
"""
Type of the cell data
"""

text: str
"""
Text of the cell data
"""

value: Any
"""
Raw value of the cell data
"""


class RowDataValue(CellData):
"""
Data for value of one column in a row. Returned with row press handlers.
"""

isExpandable: bool
"""
Whether this row is expandable.
"""

isGrouped: bool
"""
Whether this row is grouped.
"""


ColumnIndex = int
"""
Index of a column in a table.
"""

RowIndex = int
"""
Index of a row in a table.
"""

CellIndex = Tuple[ColumnIndex, RowIndex]
"""
Index of a cell in a table.
"""

GridIndex = Tuple[ColumnIndex | None, RowIndex | None]
"""
Index of a spot on the grid. A value of None indicates a header row or column.
"""


ColumnName = str
RowDataMap = Dict[str, Any]
RowPressCallback = Callable[[RowIndex, RowDataMap], None]
CellPressCallback = Callable[[CellIndex, CellData], None]
ColumnPressCallback = Callable[[ColumnName], None]
AggregationOperation = Literal[
"COUNT",
"COUNT_DISTINCT",
Expand All @@ -20,13 +81,9 @@
"UNIQUE",
"SKIP",
]
ColumnIndex = Union[int, None]
CellIndex = Tuple[RowIndex, ColumnIndex]
DeephavenColor = Literal["salmon", "lemonchiffon"]
HexColor = str
Color = Union[DeephavenColor, HexColor]
# A ColumnIndex of None indicates a header row
ColumnName = str
ContextMenuAction = Dict[str, Any]
ContextMenuModeOption = Literal["CELL", "ROW_HEADER", "COLUMN_HEADER"]
ContextMenuMode = Union[ContextMenuModeOption, List[ContextMenuModeOption], None]
Expand All @@ -37,8 +94,6 @@
LockType = Literal["shared", "exclusive"]
QuickFilterExpression = str
RowData = Dict[ColumnName, Any]
# A RowIndex of None indicates a header column
RowIndex = Optional[int]
ColumnData = List[Any]
TableData = Dict[ColumnName, ColumnData]
SearchMode = Literal["SHOW", "HIDE", "DEFAULT"]
Expand Down
1 change: 1 addition & 0 deletions plugins/ui/src/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@deephaven/components": "^0.67.0",
"@deephaven/dashboard": "^0.67.0",
"@deephaven/dashboard-core-plugins": "^0.67.0",
"@deephaven/grid": "^0.67.0",
"@deephaven/icons": "^0.67.0",
"@deephaven/iris-grid": "^0.67.0",
"@deephaven/jsapi-bootstrap": "^0.67.0",
Expand Down
37 changes: 35 additions & 2 deletions plugins/ui/src/js/src/elements/UITable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@ import { useApi } from '@deephaven/jsapi-bootstrap';
import type { Table } from '@deephaven/jsapi-types';
import Log from '@deephaven/log';
import { getSettings } from '@deephaven/redux';
import { EMPTY_ARRAY } from '@deephaven/utils';
import { UITableProps } from './UITableUtils';
import UITableMouseHandler from './UITableMouseHandler';

const log = Log.module('@deephaven/js-plugin-ui/UITable');

function UITable({
onCellPress,
onCellDoublePress,
onColumnPress,
onColumnDoublePress,
onRowPress,
onRowDoublePress,
canSearch,
filters,
Expand Down Expand Up @@ -77,17 +84,43 @@ function UITable({
};
}, [dh, exportedTable]);

const mouseHandlers = useMemo(
() =>
model
? [
new UITableMouseHandler(
model,
onCellPress,
onCellDoublePress,
onColumnPress,
onColumnDoublePress,
onRowPress,
onRowDoublePress
),
]
: EMPTY_ARRAY,
[
model,
onCellPress,
onCellDoublePress,
onColumnPress,
onColumnDoublePress,
onRowPress,
onRowDoublePress,
]
);

const irisGridProps: Partial<IrisGridProps> = useMemo(
() => ({
onDataSelected: onRowDoublePress,
mouseHandlers,
alwaysFetchColumns,
showSearchBar: canSearch,
sorts: hydratedSorts,
quickFilters: hydratedQuickFilters,
settings,
}),
[
onRowDoublePress,
mouseHandlers,
alwaysFetchColumns,
canSearch,
hydratedSorts,
Expand Down
Loading

0 comments on commit e466684

Please sign in to comment.