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: Add clickable links for Table #1321

Merged
merged 11 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 47 additions & 0 deletions py/examples/markdown_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Markdown / Table
# Display a #table using #markdown. That's different than having a table with Markdown content.
# ---
from h2o_wave import site, ui

air_passengers_fields = ['Year', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
air_passengers_rows = [
['1949', '112', '118', '132', '129', '121', '135'],
['1950', '115', '126', '141', '135', '125', '149'],
['1951', '145', '150', '178', '163', '172', '178'],
['1952', '171', '180', '193', '181', '183', '218'],
['1953', '196', '196', '236', '235', '229', '243'],
['1954', '204', '188', '235', '227', '234', '264'],
['1955', '242', '233', '267', '269', '270', '315'],
['1956', '284', '277', '317', '313', '318', '374'],
['1957', '315', '301', '356', '348', '355', '422'],
['1958', '340', '318', '362', '348', '363', '435'],
['1959', '360', '342', '406', '396', '420', '472'],
['1960', '417', '391', '419', '461', '472', '535'],
]


def make_markdown_row(values):
return f"| {' | '.join([str(x) for x in values])} |"


def make_markdown_table(fields, rows):
return '\n'.join([
make_markdown_row(fields),
make_markdown_row('-' * len(fields)),
'\n'.join([make_markdown_row(row) for row in rows]),
])


page = site['/demo']

v = page.add('example', ui.form_card(
box='1 1 4 5',
items=[
ui.text(make_markdown_table(
fields=air_passengers_fields,
rows=air_passengers_rows,
)),
],
))

page.save()
72 changes: 30 additions & 42 deletions py/examples/table_markdown.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
# Table / Markdown
# Display a #table using #markdown.
# Creates a table with Markdown content.
# #table #markdown
# ---
from h2o_wave import site, ui

air_passengers_fields = ['Year', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
air_passengers_rows = [
['1949', '112', '118', '132', '129', '121', '135'],
['1950', '115', '126', '141', '135', '125', '149'],
['1951', '145', '150', '178', '163', '172', '178'],
['1952', '171', '180', '193', '181', '183', '218'],
['1953', '196', '196', '236', '235', '229', '243'],
['1954', '204', '188', '235', '227', '234', '264'],
['1955', '242', '233', '267', '269', '270', '315'],
['1956', '284', '277', '317', '313', '318', '374'],
['1957', '315', '301', '356', '348', '355', '422'],
['1958', '340', '318', '362', '348', '363', '435'],
['1959', '360', '342', '406', '396', '420', '472'],
['1960', '417', '391', '419', '461', '472', '535'],
]


def make_markdown_row(values):
return f"| {' | '.join([str(x) for x in values])} |"


def make_markdown_table(fields, rows):
return '\n'.join([
make_markdown_row(fields),
make_markdown_row('-' * len(fields)),
'\n'.join([make_markdown_row(row) for row in rows]),
from h2o_wave import main, Q, ui, app


@app('/demo')
async def serve(q: Q):
q.page['example'] = ui.form_card(box='1 1 3 6', items=[
ui.text_xl(content='Table with Markdown'),
ui.table(
name='table',
columns=[
ui.table_column(name='description', label='Description', min_width='200',
cell_type=ui.markdown_table_cell_type(target='_blank')),
ui.table_column(name='markdown', label='Markdown',
cell_type=ui.markdown_table_cell_type(target='_blank')),
],
height='450px',
rows=[
ui.table_row(name='row1', cells=['Normal text', 'Hello World!']),
ui.table_row(name='row2', cells=['Bold text', 'This is a **bold** text.']),
ui.table_row(name='row3', cells=['Italicized text', 'This is a _italicized_ text.']),
ui.table_row(name='row4', cells=['Link', '<http://wave.h2o.ai>']),
ui.table_row(name='row5', cells=['Absolute link with label', '[Wave website](http://wave.h2o.ai/)']),
ui.table_row(name='row6', cells=['Relative link with label', '[Go to /wave](/wave)']),
ui.table_row(name='row7', cells=['Email', '<fake@email.com>']),
ui.table_row(name='row8', cells=['Code', '``inline code``']), # change to monospaced font
]
)
])


page = site['/demo']

v = page.add('example', ui.form_card(
box='1 1 4 5',
items=[
ui.text(make_markdown_table(
fields=air_passengers_fields,
rows=air_passengers_rows,
)),
],
))

page.save()
await q.page.save()
4 changes: 2 additions & 2 deletions py/examples/table_menu.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Table / Commands
# Table / Menu
# Allow group of commands with context menu for each row.
# #table #commands
# #table #commands #menu
# ---
from h2o_wave import main, app, Q, ui
from faker import Faker
Expand Down
3 changes: 2 additions & 1 deletion py/examples/tour.conf
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ form_frame_path.py
form_template.py
form_markup.py
stepper.py
table_markdown.py
table_markdown_pandas.py
table.py
table_sort.py
Expand All @@ -97,6 +96,7 @@ table_pagination_search.py
table_pagination_download.py
table_pagination_groups.py
table_menu.py
table_markdown.py
tags.py
image.py
file_stream.py
Expand All @@ -105,6 +105,7 @@ frame_path.py
template.py
template_data.py
markdown.py
markdown_table.py
markdown_data.py
markdown_submit_text.py
markup.py
Expand Down
49 changes: 49 additions & 0 deletions py/h2o_wave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3223,6 +3223,45 @@ def load(__d: Dict) -> 'MenuTableCellType':
)


class MarkdownTableCellType:
"""Create a cell type that renders Markdown content.
"""
def __init__(
self,
name: Optional[str] = None,
target: Optional[str] = None,
):
_guard_scalar('MarkdownTableCellType.name', name, (str,), False, True, False)
_guard_scalar('MarkdownTableCellType.target', target, (str,), False, True, False)
self.name = name
"""An identifying name for this component."""
self.target = target
"""Where to display the link. Setting this to '_blank'` opens the link in a new tab or window."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
_guard_scalar('MarkdownTableCellType.name', self.name, (str,), False, True, False)
_guard_scalar('MarkdownTableCellType.target', self.target, (str,), False, True, False)
return _dump(
name=self.name,
target=self.target,
)

@staticmethod
def load(__d: Dict) -> 'MarkdownTableCellType':
"""Creates an instance of this class using the contents of a dict."""
__d_name: Any = __d.get('name')
_guard_scalar('MarkdownTableCellType.name', __d_name, (str,), False, True, False)
__d_target: Any = __d.get('target')
_guard_scalar('MarkdownTableCellType.target', __d_target, (str,), False, True, False)
name: Optional[str] = __d_name
target: Optional[str] = __d_target
return MarkdownTableCellType(
name,
target,
)


class TableCellType:
"""Defines cell content to be rendered instead of a simple text.
"""
Expand All @@ -3232,11 +3271,13 @@ def __init__(
icon: Optional[IconTableCellType] = None,
tag: Optional[TagTableCellType] = None,
menu: Optional[MenuTableCellType] = None,
markdown: Optional[MarkdownTableCellType] = None,
):
_guard_scalar('TableCellType.progress', progress, (ProgressTableCellType,), False, True, False)
_guard_scalar('TableCellType.icon', icon, (IconTableCellType,), False, True, False)
_guard_scalar('TableCellType.tag', tag, (TagTableCellType,), False, True, False)
_guard_scalar('TableCellType.menu', menu, (MenuTableCellType,), False, True, False)
_guard_scalar('TableCellType.markdown', markdown, (MarkdownTableCellType,), False, True, False)
self.progress = progress
"""Renders a progress arc with a percentage value in the middle."""
self.icon = icon
Expand All @@ -3245,18 +3286,22 @@ def __init__(
"""Renders one or more tags."""
self.menu = menu
"""Renders a command menu."""
self.markdown = markdown
"""Renders text using markdown."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
_guard_scalar('TableCellType.progress', self.progress, (ProgressTableCellType,), False, True, False)
_guard_scalar('TableCellType.icon', self.icon, (IconTableCellType,), False, True, False)
_guard_scalar('TableCellType.tag', self.tag, (TagTableCellType,), False, True, False)
_guard_scalar('TableCellType.menu', self.menu, (MenuTableCellType,), False, True, False)
_guard_scalar('TableCellType.markdown', self.markdown, (MarkdownTableCellType,), False, True, False)
return _dump(
progress=None if self.progress is None else self.progress.dump(),
icon=None if self.icon is None else self.icon.dump(),
tag=None if self.tag is None else self.tag.dump(),
menu=None if self.menu is None else self.menu.dump(),
markdown=None if self.markdown is None else self.markdown.dump(),
)

@staticmethod
Expand All @@ -3270,15 +3315,19 @@ def load(__d: Dict) -> 'TableCellType':
_guard_scalar('TableCellType.tag', __d_tag, (dict,), False, True, False)
__d_menu: Any = __d.get('menu')
_guard_scalar('TableCellType.menu', __d_menu, (dict,), False, True, False)
__d_markdown: Any = __d.get('markdown')
_guard_scalar('TableCellType.markdown', __d_markdown, (dict,), False, True, False)
progress: Optional[ProgressTableCellType] = None if __d_progress is None else ProgressTableCellType.load(__d_progress)
icon: Optional[IconTableCellType] = None if __d_icon is None else IconTableCellType.load(__d_icon)
tag: Optional[TagTableCellType] = None if __d_tag is None else TagTableCellType.load(__d_tag)
menu: Optional[MenuTableCellType] = None if __d_menu is None else MenuTableCellType.load(__d_menu)
markdown: Optional[MarkdownTableCellType] = None if __d_markdown is None else MarkdownTableCellType.load(__d_markdown)
return TableCellType(
progress,
icon,
tag,
menu,
markdown,
)


Expand Down
18 changes: 18 additions & 0 deletions py/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,24 @@ def menu_table_cell_type(
))


def markdown_table_cell_type(
name: Optional[str] = None,
target: Optional[str] = None,
) -> TableCellType:
"""Create a cell type that renders Markdown content.

Args:
name: An identifying name for this component.
target: Where to display the link. Setting this to '_blank'` opens the link in a new tab or window.
Returns:
A `h2o_wave.types.MarkdownTableCellType` instance.
"""
return TableCellType(markdown=MarkdownTableCellType(
name,
target,
))


def table_column(
name: str,
label: str,
Expand Down
18 changes: 18 additions & 0 deletions r/R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,24 @@ ui_menu_table_cell_type <- function(
return(.o)
}

#' Create a cell type that renders Markdown content.
#'
#' @param name An identifying name for this component.
#' @param target Where to display the link. Setting this to '_blank'` opens the link in a new tab or window.
#' @return A MarkdownTableCellType instance.
#' @export
ui_markdown_table_cell_type <- function(
name = NULL,
target = NULL) {
.guard_scalar("name", "character", name)
.guard_scalar("target", "character", target)
.o <- list(markdown=list(
name=name,
target=target))
class(.o) <- append(class(.o), c(.wave_obj, "WaveTableCellType"))
return(.o)
}

#' Create a table column.
#'
#' @param name An identifying name for this column.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,13 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_markdown_table_cell_type" value="ui.markdown_table_cell_type(name='$name$',target='$target$'),$END$" description="Create Wave MarkdownTableCellType with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="target" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_markup" value="ui.markup(content='$content$',name='$name$',width='$width$',visible=$visible$),$END$" description="Create Wave Markup with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="content" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
Expand Down Expand Up @@ -2094,11 +2101,12 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_table_cell_type" value="ui.table_cell_type(progress=$progress$,icon=$icon$,tag=$tag$,menu=$menu$),$END$" description="Create Wave TableCellType with full attributes." toReformat="true" toShortenFQNames="true">
<template name="w_full_table_cell_type" value="ui.table_cell_type(progress=$progress$,icon=$icon$,tag=$tag$,menu=$menu$,markdown=$markdown$),$END$" description="Create Wave TableCellType with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="progress" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="icon" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="tag" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="menu" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="markdown" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
Expand Down
9 changes: 8 additions & 1 deletion tools/vscode-extension/component-snippets.json
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,13 @@
],
"description": "Create a full Wave MarkdownCard."
},
"Wave Full MarkdownTableCellType": {
"prefix": "w_full_markdown_table_cell_type",
"body": [
"ui.markdown_table_cell_type(name='$1', target='$2'),$0"
],
"description": "Create a full Wave MarkdownTableCellType."
},
"Wave Full Markup": {
"prefix": "w_full_markup",
"body": [
Expand Down Expand Up @@ -1535,7 +1542,7 @@
"Wave Full TableCellType": {
"prefix": "w_full_table_cell_type",
"body": [
"ui.table_cell_type(progress=$1, icon=$2, tag=$3, menu=$4),$0"
"ui.table_cell_type(progress=$1, icon=$2, tag=$3, menu=$4, markdown=$5),$0"
],
"description": "Create a full Wave TableCellType."
},
Expand Down
34 changes: 34 additions & 0 deletions ui/src/markdown_table_cell_type.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2020 H2O.ai, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { render } from '@testing-library/react'
import React from 'react'
import { XMarkdownTableCellType } from './markdown_table_cell_type'

const
label = 'wave',
link = `[${label}](https://wave.h2o.ai)`

describe('MarkdownTableCellType.tsx', () => {

it('Opens link in same tab', () => {
const { getByText } = render(<XMarkdownTableCellType model={{content: link}} />)
expect(getByText(label).getAttribute('target')).toBeNull()
})

it('Opens link in new tab', () => {
const { getByText } = render(<XMarkdownTableCellType model={{ target: '_blank', content: link }} />)
expect(getByText(label).getAttribute('target')).toBe('_blank')
})
})