Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion py/examples/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def serve(q: Q):
]),
ui.file_upload(name='file_upload', label='File upload'),
ui.table(name='table', columns=[
ui.table_column(name='col1', label='Column 1'),
ui.table_column(name='col1', label='Column 1', tooltip="This is a tooltip"),
ui.table_column(name='col2', label='Column 2'),
], rows=[
ui.table_row(name='row1', cells=['Text A', 'Text B']),
Expand Down
10 changes: 10 additions & 0 deletions py/h2o_lightwave/h2o_lightwave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3562,6 +3562,7 @@ def __init__(
cell_overflow: Optional[str] = None,
filters: Optional[List[str]] = None,
align: Optional[str] = None,
tooltip: Optional[str] = None,
):
_guard_scalar('TableColumn.name', name, (str,), True, False, False)
_guard_scalar('TableColumn.label', label, (str,), False, False, False)
Expand All @@ -3576,6 +3577,7 @@ def __init__(
_guard_enum('TableColumn.cell_overflow', cell_overflow, _TableColumnCellOverflow, True)
_guard_vector('TableColumn.filters', filters, (str,), False, True, False)
_guard_enum('TableColumn.align', align, _TableColumnAlign, True)
_guard_scalar('TableColumn.tooltip', tooltip, (str,), False, True, False)
self.name = name
"""An identifying name for this column."""
self.label = label
Expand All @@ -3602,6 +3604,8 @@ def __init__(
"""Explicit list of values to allow filtering by, needed when pagination is set or custom order is needed. Only applicable to filterable columns."""
self.align = align
"""Defines how to align values in a column. One of 'left', 'center', 'right'. See enum h2o_wave.ui.TableColumnAlign."""
self.tooltip = tooltip
"""Tooltip text."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
Expand All @@ -3618,6 +3622,7 @@ def dump(self) -> Dict:
_guard_enum('TableColumn.cell_overflow', self.cell_overflow, _TableColumnCellOverflow, True)
_guard_vector('TableColumn.filters', self.filters, (str,), False, True, False)
_guard_enum('TableColumn.align', self.align, _TableColumnAlign, True)
_guard_scalar('TableColumn.tooltip', self.tooltip, (str,), False, True, False)
return _dump(
name=self.name,
label=self.label,
Expand All @@ -3632,6 +3637,7 @@ def dump(self) -> Dict:
cell_overflow=self.cell_overflow,
filters=self.filters,
align=self.align,
tooltip=self.tooltip,
)

@staticmethod
Expand Down Expand Up @@ -3663,6 +3669,8 @@ def load(__d: Dict) -> 'TableColumn':
_guard_vector('TableColumn.filters', __d_filters, (str,), False, True, False)
__d_align: Any = __d.get('align')
_guard_enum('TableColumn.align', __d_align, _TableColumnAlign, True)
__d_tooltip: Any = __d.get('tooltip')
_guard_scalar('TableColumn.tooltip', __d_tooltip, (str,), False, True, False)
name: str = __d_name
label: str = __d_label
min_width: Optional[str] = __d_min_width
Expand All @@ -3676,6 +3684,7 @@ def load(__d: Dict) -> 'TableColumn':
cell_overflow: Optional[str] = __d_cell_overflow
filters: Optional[List[str]] = __d_filters
align: Optional[str] = __d_align
tooltip: Optional[str] = __d_tooltip
return TableColumn(
name,
label,
Expand All @@ -3690,6 +3699,7 @@ def load(__d: Dict) -> 'TableColumn':
cell_overflow,
filters,
align,
tooltip,
)


Expand Down
3 changes: 3 additions & 0 deletions py/h2o_lightwave/h2o_lightwave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ def table_column(
cell_overflow: Optional[str] = None,
filters: Optional[List[str]] = None,
align: Optional[str] = None,
tooltip: Optional[str] = None,
) -> TableColumn:
"""Create a table column.

Expand All @@ -1343,6 +1344,7 @@ def table_column(
cell_overflow: Defines what to do with a cell's contents in case it does not fit inside the cell. One of 'tooltip', 'wrap'. See enum h2o_wave.ui.TableColumnCellOverflow.
filters: Explicit list of values to allow filtering by, needed when pagination is set or custom order is needed. Only applicable to filterable columns.
align: Defines how to align values in a column. One of 'left', 'center', 'right'. See enum h2o_wave.ui.TableColumnAlign.
tooltip: Tooltip text.
Returns:
A `h2o_wave.types.TableColumn` instance.
"""
Expand All @@ -1360,6 +1362,7 @@ def table_column(
cell_overflow,
filters,
align,
tooltip,
)


Expand Down
10 changes: 10 additions & 0 deletions py/h2o_wave/h2o_wave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3562,6 +3562,7 @@ def __init__(
cell_overflow: Optional[str] = None,
filters: Optional[List[str]] = None,
align: Optional[str] = None,
tooltip: Optional[str] = None,
):
_guard_scalar('TableColumn.name', name, (str,), True, False, False)
_guard_scalar('TableColumn.label', label, (str,), False, False, False)
Expand All @@ -3576,6 +3577,7 @@ def __init__(
_guard_enum('TableColumn.cell_overflow', cell_overflow, _TableColumnCellOverflow, True)
_guard_vector('TableColumn.filters', filters, (str,), False, True, False)
_guard_enum('TableColumn.align', align, _TableColumnAlign, True)
_guard_scalar('TableColumn.tooltip', tooltip, (str,), False, True, False)
self.name = name
"""An identifying name for this column."""
self.label = label
Expand All @@ -3602,6 +3604,8 @@ def __init__(
"""Explicit list of values to allow filtering by, needed when pagination is set or custom order is needed. Only applicable to filterable columns."""
self.align = align
"""Defines how to align values in a column. One of 'left', 'center', 'right'. See enum h2o_wave.ui.TableColumnAlign."""
self.tooltip = tooltip
"""Tooltip text."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
Expand All @@ -3618,6 +3622,7 @@ def dump(self) -> Dict:
_guard_enum('TableColumn.cell_overflow', self.cell_overflow, _TableColumnCellOverflow, True)
_guard_vector('TableColumn.filters', self.filters, (str,), False, True, False)
_guard_enum('TableColumn.align', self.align, _TableColumnAlign, True)
_guard_scalar('TableColumn.tooltip', self.tooltip, (str,), False, True, False)
return _dump(
name=self.name,
label=self.label,
Expand All @@ -3632,6 +3637,7 @@ def dump(self) -> Dict:
cell_overflow=self.cell_overflow,
filters=self.filters,
align=self.align,
tooltip=self.tooltip,
)

@staticmethod
Expand Down Expand Up @@ -3663,6 +3669,8 @@ def load(__d: Dict) -> 'TableColumn':
_guard_vector('TableColumn.filters', __d_filters, (str,), False, True, False)
__d_align: Any = __d.get('align')
_guard_enum('TableColumn.align', __d_align, _TableColumnAlign, True)
__d_tooltip: Any = __d.get('tooltip')
_guard_scalar('TableColumn.tooltip', __d_tooltip, (str,), False, True, False)
name: str = __d_name
label: str = __d_label
min_width: Optional[str] = __d_min_width
Expand All @@ -3676,6 +3684,7 @@ def load(__d: Dict) -> 'TableColumn':
cell_overflow: Optional[str] = __d_cell_overflow
filters: Optional[List[str]] = __d_filters
align: Optional[str] = __d_align
tooltip: Optional[str] = __d_tooltip
return TableColumn(
name,
label,
Expand All @@ -3690,6 +3699,7 @@ def load(__d: Dict) -> 'TableColumn':
cell_overflow,
filters,
align,
tooltip,
)


Expand Down
3 changes: 3 additions & 0 deletions py/h2o_wave/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ def table_column(
cell_overflow: Optional[str] = None,
filters: Optional[List[str]] = None,
align: Optional[str] = None,
tooltip: Optional[str] = None,
) -> TableColumn:
"""Create a table column.

Expand All @@ -1343,6 +1344,7 @@ def table_column(
cell_overflow: Defines what to do with a cell's contents in case it does not fit inside the cell. One of 'tooltip', 'wrap'. See enum h2o_wave.ui.TableColumnCellOverflow.
filters: Explicit list of values to allow filtering by, needed when pagination is set or custom order is needed. Only applicable to filterable columns.
align: Defines how to align values in a column. One of 'left', 'center', 'right'. See enum h2o_wave.ui.TableColumnAlign.
tooltip: Tooltip text.
Returns:
A `h2o_wave.types.TableColumn` instance.
"""
Expand All @@ -1360,6 +1362,7 @@ def table_column(
cell_overflow,
filters,
align,
tooltip,
)


Expand Down
8 changes: 6 additions & 2 deletions r/R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,7 @@ ui_markdown_table_cell_type <- function(
#' @param filters Explicit list of values to allow filtering by, needed when pagination is set or custom order is needed. Only applicable to filterable columns.
#' @param align Defines how to align values in a column.
#' One of 'left', 'center', 'right'. See enum h2o_wave.ui.TableColumnAlign.
#' @param tooltip Tooltip text.
#' @return A TableColumn instance.
#' @export
ui_table_column <- function(
Expand All @@ -1575,7 +1576,8 @@ ui_table_column <- function(
cell_type = NULL,
cell_overflow = NULL,
filters = NULL,
align = NULL) {
align = NULL,
tooltip = NULL) {
.guard_scalar("name", "character", name)
.guard_scalar("label", "character", label)
.guard_scalar("min_width", "character", min_width)
Expand All @@ -1589,6 +1591,7 @@ ui_table_column <- function(
# TODO Validate cell_overflow
.guard_vector("filters", "character", filters)
# TODO Validate align
.guard_scalar("tooltip", "character", tooltip)
.o <- list(
name=name,
label=label,
Expand All @@ -1602,7 +1605,8 @@ ui_table_column <- function(
cell_type=cell_type,
cell_overflow=cell_overflow,
filters=filters,
align=align)
align=align,
tooltip=tooltip)
class(.o) <- append(class(.o), c(.wave_obj, "WaveTableColumn"))
return(.o)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2376,7 +2376,7 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_table_column" value="ui.table_column(name='$name$',label='$label$',min_width='$min_width$',max_width='$max_width$',sortable=$sortable$,searchable=$searchable$,filterable=$filterable$,link=$link$,data_type='$data_type$',cell_type=$cell_type$,cell_overflow='$cell_overflow$',align='$align$',filters=[&#10; $filters$ &#10;]),$END$" description="Create Wave TableColumn with full attributes." toReformat="true" toShortenFQNames="true">
<template name="w_full_table_column" value="ui.table_column(name='$name$',label='$label$',min_width='$min_width$',max_width='$max_width$',sortable=$sortable$,searchable=$searchable$,filterable=$filterable$,link=$link$,data_type='$data_type$',cell_type=$cell_type$,cell_overflow='$cell_overflow$',align='$align$',tooltip='$tooltip$',filters=[&#10; $filters$ &#10;]),$END$" description="Create Wave TableColumn with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="label" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="min_width" expression="" defaultValue="" alwaysStopAt="true"/>
Expand All @@ -2389,6 +2389,7 @@
<variable name="cell_type" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="cell_overflow" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="align" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="tooltip" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="filters" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
Expand Down
2 changes: 1 addition & 1 deletion tools/vscode-extension/component-snippets.json
Original file line number Diff line number Diff line change
Expand Up @@ -1745,7 +1745,7 @@
"Wave Full TableColumn": {
"prefix": "w_full_table_column",
"body": [
"ui.table_column(name='$1', label='$2', min_width='$3', max_width='$4', sortable=${5:False}, searchable=${6:False}, filterable=${7:False}, link=${8:False}, data_type='${9:string}', cell_type=${10:None}, cell_overflow='$11', align='$12', filters=[\n\t\t$13\t\t\n]),$0"
"ui.table_column(name='$1', label='$2', min_width='$3', max_width='$4', sortable=${5:False}, searchable=${6:False}, filterable=${7:False}, link=${8:False}, data_type='${9:string}', cell_type=${10:None}, cell_overflow='$11', align='$12', tooltip='$13', filters=[\n\t\t$14\t\t\n]),$0"
],
"description": "Create a full Wave TableColumn."
},
Expand Down
36 changes: 35 additions & 1 deletion ui/src/table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2114,4 +2114,38 @@ describe('Table.tsx', () => {
expect(emitMock).toHaveBeenCalledTimes(1)
})
})
})

describe('Tooltip', () => {
it('renders info icon only when tooltip prop is specified', () => {
tableProps = {
...tableProps,
columns: [
{ name: 'colname1', label: 'Col1', sortable: true, searchable: true, tooltip: 'Tooltip for Col1' },
{ name: 'colname2', label: 'Col2', sortable: true, filterable: true },
],
rows: [
{ name: 'rowname1', cells: [cell11, '2'] },
{ name: 'rowname2', cells: [cell21, '1'] },
],
}

const { container, getAllByRole } = render(<XTable model={tableProps} />)
const headers = getAllByRole('columnheader')
const infoIcons = container.querySelectorAll("[data-icon-name='info-icon']") as NodeListOf<HTMLElement>
expect(infoIcons).toHaveLength(1)

const headerKey1 = headers[0].getAttribute('data-item-key')
if (headerKey1 === 'colname1') {
expect(headers[0]).toContainElement(infoIcons[0])
} else {
expect(headers[0]).not.toContainElement(infoIcons[0])
}
const headerKey2 = headers[1].getAttribute('data-item-key')
if (headerKey2 === 'colname1') {
expect(headers[1]).toContainElement(infoIcons[0])
} else {
expect(headers[1]).not.toContainElement(infoIcons[0])
}
})
})
})
51 changes: 48 additions & 3 deletions ui/src/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ interface TableColumn {
filters?: S[]
/** Defines how to align values in a column. */
align?: 'left' | 'center' | 'right'
/** Tooltip text. */
tooltip?: S
}

/** Create a table row. */
Expand Down Expand Up @@ -167,6 +169,7 @@ type WaveColumn = Fluent.IColumn & {
cellOverflow?: 'tooltip' | 'wrap'
filters?: S[]
align?: 'left' | 'center' | 'right'
tooltip?: S
}

type DataTable = {
Expand Down Expand Up @@ -434,18 +437,55 @@ const
isResizable: true,
isMultiline: c.cell_overflow === 'wrap',
filters: c.filterable ? c.filters : undefined,
tooltip: c.tooltip ? c.tooltip : undefined,
}
}, [onColumnClick, onColumnContextMenu, selectedFilters, sortCols]),
[columns, setColumns] = React.useState(m.columns.map(tableToWaveColumn)),
primaryColumnKey = m.columns.find(c => c.link)?.name || (m.columns[0].link === false ? undefined : m.columns[0].name),
onRenderDetailsHeader = React.useCallback((props?: Fluent.IDetailsHeaderProps) => {
if (!props) return <span />

const renderColumnHeaderTooltip = (tooltipHostProps?: Fluent.IDetailsColumnRenderTooltipProps) => {
const column = props.columns.find(col => col.key === tooltipHostProps?.column?.key) as WaveColumn
if (!tooltipHostProps?.children) return null
return (
<div style={{ display: 'flex', alignItems: 'center' }}>
{tooltipHostProps.children}
{
column?.tooltip && (
<Fluent.TooltipHost
content={column.tooltip}
calloutProps={{
gapSpace: -10,
styles: {
beakCurtain: { backgroundColor: cssVar('$neutralLighterAlt') },
beak: { backgroundColor: cssVar('$neutralLighterAlt') },
calloutMain: { backgroundColor: cssVar('$neutralLighterAlt') }
}
}}
>
<Fluent.Icon
iconName="Info"
data-icon-name="info-icon"
styles={{
root: {
fontSize: '16px',
fontWeight: 'bold',
paddingLeft: '0px',
}
}}
/>
</Fluent.TooltipHost>
)
}
</div>
)
}
return (
<Fluent.Sticky stickyPosition={Fluent.StickyPositionType.Header} isScrollSynced>
<Fluent.DetailsHeader
{...props}
isAllCollapsed={groups?.every(group => group.isCollapsed)}
onRenderColumnHeaderTooltip={renderColumnHeaderTooltip}
styles={{
...props.styles,
root: {
Expand All @@ -454,14 +494,19 @@ const
lineHeight: '48px',
background: cssVar('$neutralLight'),
borderBottom: 'none',
selectors: {
'.ms-DetailsHeader-cellTitle': {
paddingLeft: '0px',
},
}
},
cellSizerEnd: {
marginLeft: -8,
},
cellIsGroupExpander: {
// HACK: fixed size of expand/collapse button in column header
height: 48
}
height: 48,
},
}}
/>
</Fluent.Sticky>
Expand Down