Skip to content

Commit

Permalink
feat: initial implementation #1007
Browse files Browse the repository at this point in the history
  • Loading branch information
mturoci committed Sep 29, 2021
1 parent 23d25ca commit 5eefafa
Show file tree
Hide file tree
Showing 8 changed files with 436 additions and 11 deletions.
55 changes: 55 additions & 0 deletions py/examples/meta_notification_bar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Meta / Notification
# Display a desktop #notification. #meta
# ---
from h2o_wave import main, app, Q, ui


@app('/demo')
async def serve(q: Q):
if not q.client.initialized:
q.page['form'] = ui.form_card(box='1 1 2 4', items=[
ui.button(name='top_right', label='Success top-right'),
ui.button(name='top_center', label='Error top-center'),
ui.button(name='top_left', label='Warning top-left'),
ui.button(name='bottom_right', label='Info bottom-right'),
ui.button(name='bottom_center', label='Info bottom-center'),
ui.button(name='bottom_left', label='Info bottom-left'),
])
q.client.initialized = True
if q.args.top_right:
q.page['meta'] = ui.meta_card(box='', notification_bar=ui.notification_bar(
text='Success notification',
type='success',
position='top-right',
buttons=[ui.button(name='btn1', label='Button 1', link=True)]
))
if q.args.top_center:
q.page['meta'] = ui.meta_card(box='', notification_bar=ui.notification_bar(
text='Error notification that should hopefully span at least two lines',
type='error',
position='top-center',
buttons=[ui.button(name='btn1', label='Button 1'), ui.button(name='btn2', label='Button 2')]
))
if q.args.top_left:
q.page['meta'] = ui.meta_card(box='', notification_bar=ui.notification_bar(
text='Warning notification',
type='warning',
position='top-left',
))
if q.args.bottom_right:
q.page['meta'] = ui.meta_card(box='', notification_bar=ui.notification_bar(
text='Info notification',
type='info',
position='bottom-right',
))
if q.args.bottom_center:
q.page['meta'] = ui.meta_card(box='', notification_bar=ui.notification_bar(
text='Info notification',
position='bottom-center',
))
if q.args.bottom_left:
q.page['meta'] = ui.meta_card(box='', notification_bar=ui.notification_bar(
text='Default notification',
position='bottom-left',
))
await q.page.save()
106 changes: 106 additions & 0 deletions py/h2o_wave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7429,6 +7429,102 @@ def load(__d: Dict) -> 'MarkupCard':
)


_NotificationBarType = ['info', 'error', 'warning', 'success', 'danger', 'blocked']


class NotificationBarType:
INFO = 'info'
ERROR = 'error'
WARNING = 'warning'
SUCCESS = 'success'
DANGER = 'danger'
BLOCKED = 'blocked'


_NotificationBarPosition = ['top-right', 'bottom-right', 'bottom-center', 'bottom-left', 'top-left', 'top-center']


class NotificationBarPosition:
TOP_RIGHT = 'top-right'
BOTTOM_RIGHT = 'bottom-right'
BOTTOM_CENTER = 'bottom-center'
BOTTOM_LEFT = 'bottom-left'
TOP_LEFT = 'top-left'
TOP_CENTER = 'top-center'


class NotificationBar:
"""Create a notification bar.
A notification bar is an area at the edge of a primary view that displays relevant status information.
You can use a notification bar to tell the user about a result of an action, e.g. "Data has been successfully saved".
"""
def __init__(
self,
text: str,
type: Optional[str] = None,
timeout: Optional[int] = None,
buttons: Optional[List[Component]] = None,
position: Optional[str] = None,
):
_guard_scalar('NotificationBar.text', text, (str,), False, False, False)
_guard_enum('NotificationBar.type', type, _NotificationBarType, True)
_guard_scalar('NotificationBar.timeout', timeout, (int,), False, True, False)
_guard_vector('NotificationBar.buttons', buttons, (Component,), False, True, False)
_guard_enum('NotificationBar.position', position, _NotificationBarPosition, True)
self.text = text
"""The text displayed on the notification bar."""
self.type = type
"""The icon and color of the notification bar. Defaults to 'info'. One of 'info', 'error', 'warning', 'success', 'danger', 'blocked'. See enum h2o_wave.ui.NotificationBarType."""
self.timeout = timeout
"""When should the notification bar disappear in seconds. Defaults to 5."""
self.buttons = buttons
"""Specify one or more action buttons."""
self.position = position
"""Specify the location of notification. Defaults to 'top-right'. One of 'top-right', 'bottom-right', 'bottom-center', 'bottom-left', 'top-left', 'top-center'. See enum h2o_wave.ui.NotificationBarPosition."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
_guard_scalar('NotificationBar.text', self.text, (str,), False, False, False)
_guard_enum('NotificationBar.type', self.type, _NotificationBarType, True)
_guard_scalar('NotificationBar.timeout', self.timeout, (int,), False, True, False)
_guard_vector('NotificationBar.buttons', self.buttons, (Component,), False, True, False)
_guard_enum('NotificationBar.position', self.position, _NotificationBarPosition, True)
return _dump(
text=self.text,
type=self.type,
timeout=self.timeout,
buttons=None if self.buttons is None else [__e.dump() for __e in self.buttons],
position=self.position,
)

@staticmethod
def load(__d: Dict) -> 'NotificationBar':
"""Creates an instance of this class using the contents of a dict."""
__d_text: Any = __d.get('text')
_guard_scalar('NotificationBar.text', __d_text, (str,), False, False, False)
__d_type: Any = __d.get('type')
_guard_enum('NotificationBar.type', __d_type, _NotificationBarType, True)
__d_timeout: Any = __d.get('timeout')
_guard_scalar('NotificationBar.timeout', __d_timeout, (int,), False, True, False)
__d_buttons: Any = __d.get('buttons')
_guard_vector('NotificationBar.buttons', __d_buttons, (dict,), False, True, False)
__d_position: Any = __d.get('position')
_guard_enum('NotificationBar.position', __d_position, _NotificationBarPosition, True)
text: str = __d_text
type: Optional[str] = __d_type
timeout: Optional[int] = __d_timeout
buttons: Optional[List[Component]] = None if __d_buttons is None else [Component.load(__e) for __e in __d_buttons]
position: Optional[str] = __d_position
return NotificationBar(
text,
type,
timeout,
buttons,
position,
)


_ZoneDirection = ['row', 'column']


Expand Down Expand Up @@ -8174,6 +8270,7 @@ def __init__(
title: Optional[str] = None,
refresh: Optional[int] = None,
notification: Optional[str] = None,
notification_bar: Optional[NotificationBar] = None,
redirect: Optional[str] = None,
icon: Optional[str] = None,
layouts: Optional[List[Layout]] = None,
Expand All @@ -8192,6 +8289,7 @@ def __init__(
_guard_scalar('MetaCard.title', title, (str,), False, True, False)
_guard_scalar('MetaCard.refresh', refresh, (int,), False, True, False)
_guard_scalar('MetaCard.notification', notification, (str,), False, True, False)
_guard_scalar('MetaCard.notification_bar', notification_bar, (NotificationBar,), False, True, False)
_guard_scalar('MetaCard.redirect', redirect, (str,), False, True, False)
_guard_scalar('MetaCard.icon', icon, (str,), False, True, False)
_guard_vector('MetaCard.layouts', layouts, (Layout,), False, True, False)
Expand All @@ -8213,6 +8311,8 @@ def __init__(
"""Refresh rate in seconds. A value of 0 turns off live-updates. Values != 0 are currently ignored (reserved for future use)."""
self.notification = notification
"""Display a desktop notification."""
self.notification_bar = notification_bar
"""Display an in-app notification bar."""
self.redirect = redirect
"""Redirect the page to a new URL."""
self.icon = icon
Expand Down Expand Up @@ -8246,6 +8346,7 @@ def dump(self) -> Dict:
_guard_scalar('MetaCard.title', self.title, (str,), False, True, False)
_guard_scalar('MetaCard.refresh', self.refresh, (int,), False, True, False)
_guard_scalar('MetaCard.notification', self.notification, (str,), False, True, False)
_guard_scalar('MetaCard.notification_bar', self.notification_bar, (NotificationBar,), False, True, False)
_guard_scalar('MetaCard.redirect', self.redirect, (str,), False, True, False)
_guard_scalar('MetaCard.icon', self.icon, (str,), False, True, False)
_guard_vector('MetaCard.layouts', self.layouts, (Layout,), False, True, False)
Expand All @@ -8265,6 +8366,7 @@ def dump(self) -> Dict:
title=self.title,
refresh=self.refresh,
notification=self.notification,
notification_bar=None if self.notification_bar is None else self.notification_bar.dump(),
redirect=self.redirect,
icon=self.icon,
layouts=None if self.layouts is None else [__e.dump() for __e in self.layouts],
Expand All @@ -8291,6 +8393,8 @@ def load(__d: Dict) -> 'MetaCard':
_guard_scalar('MetaCard.refresh', __d_refresh, (int,), False, True, False)
__d_notification: Any = __d.get('notification')
_guard_scalar('MetaCard.notification', __d_notification, (str,), False, True, False)
__d_notification_bar: Any = __d.get('notification_bar')
_guard_scalar('MetaCard.notification_bar', __d_notification_bar, (dict,), False, True, False)
__d_redirect: Any = __d.get('redirect')
_guard_scalar('MetaCard.redirect', __d_redirect, (str,), False, True, False)
__d_icon: Any = __d.get('icon')
Expand Down Expand Up @@ -8321,6 +8425,7 @@ def load(__d: Dict) -> 'MetaCard':
title: Optional[str] = __d_title
refresh: Optional[int] = __d_refresh
notification: Optional[str] = __d_notification
notification_bar: Optional[NotificationBar] = None if __d_notification_bar is None else NotificationBar.load(__d_notification_bar)
redirect: Optional[str] = __d_redirect
icon: Optional[str] = __d_icon
layouts: Optional[List[Layout]] = None if __d_layouts is None else [Layout.load(__e) for __e in __d_layouts]
Expand All @@ -8339,6 +8444,7 @@ def load(__d: Dict) -> 'MetaCard':
title,
refresh,
notification,
notification_bar,
redirect,
icon,
layouts,
Expand Down
33 changes: 33 additions & 0 deletions py/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2626,6 +2626,36 @@ def markup_card(
)


def notification_bar(
text: str,
type: Optional[str] = None,
timeout: Optional[int] = None,
buttons: Optional[List[Component]] = None,
position: Optional[str] = None,
) -> NotificationBar:
"""Create a notification bar.
A notification bar is an area at the edge of a primary view that displays relevant status information.
You can use a notification bar to tell the user about a result of an action, e.g. "Data has been successfully saved".
Args:
text: The text displayed on the notification bar.
type: The icon and color of the notification bar. Defaults to 'info'. One of 'info', 'error', 'warning', 'success', 'danger', 'blocked'. See enum h2o_wave.ui.NotificationBarType.
timeout: When should the notification bar disappear in seconds. Defaults to 5.
buttons: Specify one or more action buttons.
position: Specify the location of notification. Defaults to 'top-right'. One of 'top-right', 'bottom-right', 'bottom-center', 'bottom-left', 'top-left', 'top-center'. See enum h2o_wave.ui.NotificationBarPosition.
Returns:
A `h2o_wave.types.NotificationBar` instance.
"""
return NotificationBar(
text,
type,
timeout,
buttons,
position,
)


def zone(
name: str,
size: Optional[str] = None,
Expand Down Expand Up @@ -2902,6 +2932,7 @@ def meta_card(
title: Optional[str] = None,
refresh: Optional[int] = None,
notification: Optional[str] = None,
notification_bar: Optional[NotificationBar] = None,
redirect: Optional[str] = None,
icon: Optional[str] = None,
layouts: Optional[List[Layout]] = None,
Expand All @@ -2926,6 +2957,7 @@ def meta_card(
title: The title of the page.
refresh: Refresh rate in seconds. A value of 0 turns off live-updates. Values != 0 are currently ignored (reserved for future use).
notification: Display a desktop notification.
notification_bar: Display an in-app notification bar.
redirect: Redirect the page to a new URL.
icon: Shortcut icon path. Preferably a `.png` file (`.ico` files may not work in mobile browsers). Not supported in Safari.
layouts: The layouts supported by this page.
Expand All @@ -2947,6 +2979,7 @@ def meta_card(
title,
refresh,
notification,
notification_bar,
redirect,
icon,
layouts,
Expand Down
39 changes: 39 additions & 0 deletions r/R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -3062,6 +3062,41 @@ ui_markup_card <- function(
return(.o)
}

#' Create a notification bar.
#'
#' A notification bar is an area at the edge of a primary view that displays relevant status information.
#' You can use a notification bar to tell the user about a result of an action, e.g. "Data has been successfully saved".
#'
#' @param text The text displayed on the notification bar.
#' @param type The icon and color of the notification bar. Defaults to 'info'.
#' One of 'info', 'error', 'warning', 'success', 'danger', 'blocked'. See enum h2o_wave.ui.NotificationBarType.
#' @param timeout When should the notification bar disappear in seconds. Defaults to 5.
#' @param buttons Specify one or more action buttons.
#' @param position Specify the location of notification. Defaults to 'top-right'.
#' One of 'top-right', 'bottom-right', 'bottom-center', 'bottom-left', 'top-left', 'top-center'. See enum h2o_wave.ui.NotificationBarPosition.
#' @return A NotificationBar instance.
#' @export
ui_notification_bar <- function(
text,
type = NULL,
timeout = NULL,
buttons = NULL,
position = NULL) {
.guard_scalar("text", "character", text)
# TODO Validate type
.guard_scalar("timeout", "numeric", timeout)
.guard_vector("buttons", "WaveComponent", buttons)
# TODO Validate position
.o <- list(
text=text,
type=type,
timeout=timeout,
buttons=buttons,
position=position)
class(.o) <- append(class(.o), c(.wave_obj, "WaveNotificationBar"))
return(.o)
}

#' Represents an zone within a page layout.
#'
#' @param name An identifying name for this zone.
Expand Down Expand Up @@ -3385,6 +3420,7 @@ ui_stylesheet <- function(
#' @param title The title of the page.
#' @param refresh Refresh rate in seconds. A value of 0 turns off live-updates. Values != 0 are currently ignored (reserved for future use).
#' @param notification Display a desktop notification.
#' @param notification_bar Display an in-app notification bar.
#' @param redirect Redirect the page to a new URL.
#' @param icon Shortcut icon path. Preferably a `.png` file (`.ico` files may not work in mobile browsers).
#' Not supported in Safari.
Expand All @@ -3406,6 +3442,7 @@ ui_meta_card <- function(
title = NULL,
refresh = NULL,
notification = NULL,
notification_bar = NULL,
redirect = NULL,
icon = NULL,
layouts = NULL,
Expand All @@ -3423,6 +3460,7 @@ ui_meta_card <- function(
.guard_scalar("title", "character", title)
.guard_scalar("refresh", "numeric", refresh)
.guard_scalar("notification", "character", notification)
.guard_scalar("notification_bar", "WaveNotificationBar", notification_bar)
.guard_scalar("redirect", "character", redirect)
.guard_scalar("icon", "character", icon)
.guard_vector("layouts", "WaveLayout", layouts)
Expand All @@ -3441,6 +3479,7 @@ ui_meta_card <- function(
title=title,
refresh=refresh,
notification=notification,
notification_bar=notification_bar,
redirect=redirect,
icon=icon,
layouts=layouts,
Expand Down
4 changes: 3 additions & 1 deletion ui/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { stylesheet } from 'typestyle'
import Dialog from './dialog'
import { LayoutPicker } from './editor'
import { Logo } from './logo'
import NotificationBar from './notification_bar'
import { PageLayout } from './page'
import SidePanel from './side_panel'
import { clas, cssVar, pc } from './theme'
Expand Down Expand Up @@ -84,7 +85,7 @@ const
<Logo />
{config.editable && (
<>
<Fluent.DefaultButton onClick={onClick} >Edit this page...</Fluent.DefaultButton>
<Fluent.DefaultButton onClick={onClick}>Edit this page...</Fluent.DefaultButton>
<LayoutPicker visibleB={pickingLayoutB} />
</>
)}
Expand Down Expand Up @@ -119,6 +120,7 @@ const
<BusyOverlay />
<Dialog />
<SidePanel />
<NotificationBar />
</div>
</Fluent.Fabric>
)
Expand Down

0 comments on commit 5eefafa

Please sign in to comment.