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

Implement Notifications API for templates #3093

Merged
merged 7 commits into from
Jan 13, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
'panes',
'layouts',
'templates',
'global',
'indicators',
'widgets',
]
Expand Down
238 changes: 238 additions & 0 deletions examples/reference/global/Notifications.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"\n",
"pn.extension(notifications=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `NotificationsArea` component is a global component which allows users to display so called \"toasts\" that can provide information to a user. Notifications can be enabled by setting `notifications=True` via the `pn.extension` or by setting `pn.config.notifications = True` directly.\n",
"\n",
"#### Parameters:\n",
"\n",
"For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
"\n",
"##### NotificationArea\n",
"\n",
"Parameters:\n",
"\n",
"* **``position``** (str): The position of the notifications area.\n",
"\n",
"Methods:\n",
"\n",
"* **``.info()``**: Issues an info message\n",
"* **``.error()``**: Issues an error message\n",
"* **``.success()``**: Issues an success message\n",
"* **``.warning()``**: Issues an warning message\n",
"\n",
"##### Notification\n",
"\n",
"Parameters:\n",
"\n",
"* **``duration``** (int): The duration to display the notification for (if set to zero the notification will be displayed until it has been destroyed or dismissed).\n",
"* **``type``** (str): Whether the widget is editable\n",
"\n",
"Methods:\n",
"\n",
"* **``.destroy()``**: Destroys the notification\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default notifications last for the specified duration specified in milliseconds and defaulting to 3 seconds:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.state.notifications.error('This is an error notification.', duration=1000)\n",
"pn.state.notifications.info('This is a info notification.', duration=2000)\n",
"pn.state.notifications.success('This is a success notification.')\n",
"pn.state.notifications.warning('This is a warning notification.', duration=4000);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Setting a duration of zero will cause the notification to stay in place until it is either manually dismissed in the UI or destroyed programmatically:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"success = pn.state.notifications.success('This is a success notification.', duration=0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can destroy it programmatically using the destroy method:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"success.destroy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Clear all"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To clear out all current notifications we can call the clear method:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.state.notifications.error('This is an error notification.', duration=0)\n",
"pn.state.notifications.info('This is a info notification.', duration=0)\n",
"pn.state.notifications.success('This is a success notification.', duration=0)\n",
"pn.state.notifications.warning('This is a warning notification.', duration=0);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.state.notifications.clear()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Custom types"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are not limited by the four main types of notifications, by using the `.send` method we can provide a custom `background` and `icon`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.state.notifications.send('Fire!!!', background='red', icon='<i class=\"fas fa-burn\"></i>');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Position"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The position of the notification area can be controlled by setting the parameter on the `state.notifications` object, e.g.:\n",
" \n",
"```python\n",
"pn.state.notifications.position = 'top-right'\n",
"```\n",
"\n",
"If you are viewing this page in a live notebook you will be able to change the position dynamically:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.state.notifications.send('Fire!!!', background='red', icon='<i class=\"fas fa-burn\"></i>', duration=0);\n",
"\n",
"pn.widgets.RadioButtonGroup.from_param(pn.state.notifications.param.position)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Demo\n",
"\n",
"To try notifications out yourself the `NotificationArea` components provide a convenient `.demo()` method. Note that to set a custom color you have to select the `'custom'` type:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.io.notifications.NotificationArea.demo()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.8"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}
13 changes: 13 additions & 0 deletions panel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ class _config(_base_config):
loading_max_height = param.Integer(default=400, doc="""
Maximum height of the loading indicator.""")

notifications = param.Boolean(default=False, doc="""
Whether to enable notifications functionality.""")

profiler = param.Selector(default=None, allow_None=True, objects=[
'pyinstrument', 'snakeviz'], doc="""
The profiler engine to enable.""")
Expand Down Expand Up @@ -231,6 +234,13 @@ def _set_thread_pool(self):
threads = self.nthreads if self.nthreads else None
state._thread_pool = ThreadPoolExecutor(max_workers=threads)

@param.depends('notifications', watch=True)
def _enable_notifications(self):
from .io.notifications import NotificationArea
from .io.state import state
if not state.curdoc:
state._notification = NotificationArea()

@contextmanager
def set(self, **kwargs):
values = [(k, v) for k, v in self.param.values().items() if k != 'name']
Expand Down Expand Up @@ -554,6 +564,9 @@ def __call__(self, *args, **params):
if "VSCODE_PID" in os.environ:
config.comms = "vscode"

if config.notifications:
display(state.notifications) # noqa

def _apply_signatures(self):
from inspect import Parameter, Signature
from .viewable import Viewable
Expand Down
Loading