Skip to content

Commit

Permalink
feat: Add Markdown support to table cell
Browse files Browse the repository at this point in the history
closes #428
  • Loading branch information
aalencar committed Apr 26, 2022
1 parent e6a22e8 commit 5239696
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 7 deletions.
14 changes: 9 additions & 5 deletions py/examples/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@


class Issue:
def __init__(self, text: str, status: str, progress: float, icon: str, state: str, created: str):
def __init__(self, text: str, status: str, progress: float, icon: str, state: str, created: str, markdown: str):
global _id
_id += 1
self.id = f'I{_id}'
Expand All @@ -24,6 +24,7 @@ def __init__(self, text: str, status: str, progress: float, icon: str, state: st
self.icon = icon
self.created = created
self.state = state
self.markdown = markdown


# Create some issues
Expand All @@ -34,7 +35,9 @@ def __init__(self, text: str, status: str, progress: float, icon: str, state: st
progress=random.random(),
icon=('BoxCheckmarkSolid' if random.random() > 0.5 else 'BoxMultiplySolid'),
state=('RUNNING' if random.random() > 0.5 else 'DONE,SUCCESS'),
created=fake.iso8601()) for i in range(100)
created=fake.iso8601(),
markdown=f'[]({"https://" if random.random() > 0.5 else ""}{fake.domain_name()})'
) for i in range(100)
]

# Create columns for our issue table.
Expand All @@ -51,10 +54,11 @@ def __init__(self, text: str, status: str, progress: float, icon: str, state: st
]
)),
ui.table_column(name='created', label='Created', sortable=True, data_type='time'),
ui.table_column(name='md', label='md', sortable=True, cell_type=ui.markdown_table_cell_type()),
]


@app('/demo')
@ app('/demo')
async def serve(q: Q):
q.page['form'] = ui.form_card(box='1 1 -1 10', items=[
ui.table(
Expand All @@ -63,12 +67,12 @@ async def serve(q: Q):
rows=[ui.table_row(
name=issue.id,
cells=[issue.text, issue.status, issue.icon, str(issue.views), str(issue.progress),
issue.state, issue.created]
issue.state, issue.created, issue.markdown]
) for issue in issues],
groupable=True,
downloadable=True,
resettable=True,
height='800px'
)
])
await q.page.save()
await q.page.save()
29 changes: 29 additions & 0 deletions py/examples/table_markdown_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Table / Markdown
# Creates a table with relative and absolute links.
# #table #markdown
# ---

from h2o_wave import main, Q, ui, app


@app('/demo')
async def serve(q: Q):

q.page['example'] = ui.form_card(box='1 1 5 3', items=[
ui.text_xl(content='Table with Markdown links'),
ui.table(
name='table',
columns=[
ui.table_column(name='description', label='Description', min_width="200"),
ui.table_column(name='newtab', label='Open in new tab'),
ui.table_column(name='markdown', label='Link',
cell_type=ui.markdown_table_cell_type())
],
rows=[
ui.table_row(name='row1', cells=['Absolute URL', 'Yes', '[Wave](http://wave.h2o.ai/)']),
ui.table_row(name='row2', cells=['Relative URL', 'No', '[Go to /wave](wave)']),
]
)
])

await q.page.save()
39 changes: 39 additions & 0 deletions py/h2o_wave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3223,6 +3223,35 @@ def load(__d: Dict) -> 'MenuTableCellType':
)


class MarkdownTableCellType:
"""No documentation available.
"""
def __init__(
self,
name: Optional[str] = None,
):
_guard_scalar('MarkdownTableCellType.name', name, (str,), False, True, False)
self.name = name
"""An identifying name for this component."""

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

@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)
name: Optional[str] = __d_name
return MarkdownTableCellType(
name,
)


class TableCellType:
"""Defines cell content to be rendered instead of a simple text.
"""
Expand All @@ -3232,11 +3261,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 +3276,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 +3305,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
15 changes: 15 additions & 0 deletions py/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,21 @@ def menu_table_cell_type(
))


def markdown_table_cell_type(
name: Optional[str] = None,
) -> TableCellType:
"""No documentation available.
Args:
name: An identifying name for this component.
Returns:
A `h2o_wave.types.MarkdownTableCellType` instance.
"""
return TableCellType(markdown=MarkdownTableCellType(
name,
))


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

#' No documentation available.
#'
#' @param name An identifying name for this component.
#' @return A MarkdownTableCellType instance.
#' @export
ui_markdown_table_cell_type <- function(
name = NULL) {
.guard_scalar("name", "character", name)
.o <- list(markdown=list(
name=name))
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,12 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_markdown_table_cell_type" value="ui.markdown_table_cell_type(name='$name$'),$END$" description="Create Wave MarkdownTableCellType with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="name" 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 +2100,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'),$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
35 changes: 35 additions & 0 deletions ui/src/markdown_table_cell_type.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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 { S } from 'h2o-wave'
import React from 'react'
import { XLink } from './link'
import { Markdown } from './markdown'

export interface MarkdownTableCellType {
/** An identifying name for this component. */
name?: S
}

export const XMarkdownTableCellType = ({ content }: { content: S}) => {
const [, label, path] = /\[(.*)\]\((.+)\)/.exec(content) || []
if (path) {
const isPathAbsolute = /https*:\/\//.exec(path)
return <XLink model={{ label, path, target: isPathAbsolute ? '_blank' : undefined }} />
} else {
return (
<Markdown source={content} />
)
}
}
4 changes: 4 additions & 0 deletions ui/src/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React from 'react'
import { stylesheet } from 'typestyle'
import { MenuTableCellType as MenuTableCellType, XMenuTableCellType } from './menu_table_cell_type'
import { IconTableCellType, XIconTableCellType } from "./icon_table_cell_type"
import { MarkdownTableCellType, XMarkdownTableCellType } from './markdown_table_cell_type'
import { ProgressTableCellType, XProgressTableCellType } from "./progress_table_cell_type"
import { TagTableCellType, XTagTableCellType } from "./tag_table_cell_type"
import { border, cssVar, important, margin, rem } from './theme'
Expand All @@ -41,6 +42,8 @@ interface TableCellType {
tag?: TagTableCellType
/** Renders a command menu. */
menu?: MenuTableCellType
/** Renders text using markdown. */
markdown?: MarkdownTableCellType
}

/** Create a table column. */
Expand Down Expand Up @@ -478,6 +481,7 @@ const
if (col.cellType?.icon) return <XIconTableCellType model={col.cellType.icon} icon={item[col.key]} />
if (col.cellType?.tag) return <XTagTableCellType model={col.cellType.tag} serializedTags={item[col.key]} />
if (col.cellType?.menu) return <XMenuTableCellType model={{...col.cellType.menu, rowId: String(item.key)}} />
if (col.cellType?.markdown) return <XMarkdownTableCellType content={item[col.key]} />
if (col.dataType === 'time') v = new Date(v).toLocaleString()
if (col.key === primaryColumnKey && !isMultiple) {
const onClick = () => {
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions website/widgets/form/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,30 @@ q.page['example'] = ui.form_card(box='1 1 3 3', items=[
)
])
```

## Markdown support

Leverage the power and versatility of [Markdown](https://www.markdownguide.org/) by setting `cell_type` to `markdown_cell_type`.

### Links

To open in a new tab use absolute links.

```py
q.page['example'] = ui.form_card(box='1 1 5 5', items=[
ui.text_xl(content='Table with Markdown links'),
ui.table(
name='table',
columns=[
ui.table_column(name='description', label='Description', min_width="200"),
ui.table_column(name='newtab', label='Open in new tab'),
ui.table_column(name='markdown', label='Link',
cell_type=ui.markdown_table_cell_type())
],
rows=[
ui.table_row(name='row1', cells=['Absolute URL', 'Yes', '[Wave](http://wave.h2o.ai/)']),
ui.table_row(name='row2', cells=['Relative URL', 'No', '[Go to /wave](wave)']),
]
)
])
```

0 comments on commit 5239696

Please sign in to comment.