Skip to content

Commit

Permalink
Added shout-button-message widget example. (#243)
Browse files Browse the repository at this point in the history
* Initial shout button extension.

* Updated workflow.

* Added preview and metadata.

* Removed unneeded notebooks.

* Added signals note/recommendation.

* Added guide link to README.

* Add improved description to root/proj READMEs.

* Update README/fix links.

* Updated title.

* Updated title.

* Added a basic test.

* Linting/formatting.

* Formatting.

* Fixed hello world config file diff in CI.

* Added required yarnrc file needed by CI.

* Update template

* Improve widget example
Add listeners

* Fix CI

* Update reference snapshot

---------

Co-authored-by: Frédéric Collonval <fcollonval@gmail.com>
  • Loading branch information
ericsnekbytes and fcollonval authored Nov 14, 2023
1 parent 834e87d commit f3b2b0b
Show file tree
Hide file tree
Showing 30 changed files with 1,119 additions and 10 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
- notifications
- react-widget
- settings
- shout-button-message
- signals
- state
- toolbar-button
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
1. [Context Menu](#context-menu)
1. [Custom Log Console](#custom-log-console)
1. [Datagrid](#datagrid)
1. [Dual Compatibility Shout Button](#dual-compatibility-shout-button)
1. [Collaborative Document](#collaborative-document)
1. _[Hello World](#hello-world)_
1. [Kernel Messaging](#kernel-messaging)
Expand Down Expand Up @@ -101,6 +102,7 @@ Start with the [Hello World](hello-world) and then jump to the topic you are int
- [Context Menu](context-menu)
- [Custom Log Console](custom-log-console)
- [Datagrid](datagrid)
- [Dual Compatibility Shout Button](shout-button-message)
- [Collaborative Document](documents)
- [Hello World](hello-world)
- [Kernel Messaging](kernel-messaging)
Expand Down Expand Up @@ -179,6 +181,16 @@ Display a Datagrid as a Lumino Widget.

[![Datagrid](datagrid/preview.png)](datagrid)

### [Dual Compatibility Shout Button](shout-button-message)

This example shows dual compatibility: Make an extension that is compatible
with both JupyterLab and Jupyter Notebook by using optional features. Adds
a shout button to the right sidebar, and if running in JupyterLab, also adds
a status bar widget. This example is part of the [Extension Dual Compatibility Guide](https://jupyterlab.readthedocs.io/en/latest/extension_dual_compatibility.html).
Read more about this example on that page.

[![Dual compatibility shout button](shout-button-message/preview.jpg)](shout-button-message)

### [Collaborative Document](documents)

Create new documents and make them collaborative.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"react-widget",
"server-extension",
"settings",
"shout-button-message",
"signals",
"state",
"toolbar-button",
Expand Down
20 changes: 20 additions & 0 deletions shout-button-message/.copier-answers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
_commit: v4.2.4
_src_path: https://github.com/jupyterlab/extension-template
author_email: ''
author_name: Project Jupyter Contributors
data_format: string
file_extension: ''
has_binder: false
has_settings: false
kind: frontend
labextension_name: '@jupyterlab-examples/shout-button'
mimetype: ''
mimetype_name: ''
project_short_description: An extension that adds a button and message to the right
toolbar, with optional status bar widget in JupyterLab.
python_name: jupyterlab_examples_shout_button
repository: https://github.com/jupyterlab/extension-examples
test: true
viewer_name: ''

125 changes: 125 additions & 0 deletions shout-button-message/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
*.bundle.*
lib/
node_modules/
*.log
.eslintcache
.stylelintcache
*.egg-info/
.ipynb_checkpoints
*.tsbuildinfo
jupyterlab_examples_shout_button/labextension
# Version file is handled by hatchling
jupyterlab_examples_shout_button/_version.py

# Integration tests
ui-tests/test-results/
ui-tests/playwright-report/

# Created by https://www.gitignore.io/api/python
# Edit at https://www.gitignore.io/?templates=python

### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage/
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# End of https://www.gitignore.io/api/python

# OSX files
.DS_Store

# Yarn cache
.yarn/
6 changes: 6 additions & 0 deletions shout-button-message/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
**/node_modules
**/lib
**/package.json
!/package.json
jupyterlab_examples_shout_button
1 change: 1 addition & 0 deletions shout-button-message/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
106 changes: 106 additions & 0 deletions shout-button-message/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Shout button (cross compatible extension)

This example defines an extension that adds a button in the right sidebar that
if clicked will display an alert to the user and in JupyterLab will update
a widget in the status bar.

![preview](./preview.jpg)

We strongly advice to look to those examples before diving into this one:

- [signals](../signals/): Communication between JavaScript objects.
- [widgets](../widgets): The basic DOM Jupyter component

## Jupyter Notebook / JupyterLab compatibility

As Jupyter Notebook 7+ is built with components from JupyterLab, and since
both use the same building blocks, that means your extension can work
on both (or any other frontend built with JupyterLab components) with
little or no modification depending on its design.

This example has a part specific to JupyterLab. This translate by having
optional dependency for your extension plugin.

```ts
// src/index.ts#L120-L120

optional: [IStatusBar],
```

If your dependency is optional, the object pass to the `activate` method
will be `null` if no other plugin provides it.

```ts
// src/index.ts#L124-L124

activate: (app: JupyterFrontEnd, statusBar: IStatusBar | null) => {
```
## Add the button in the sidebar
You can add a widget to the right sidebar through the application shell:
```ts
// src/index.ts#L128-L131

const shoutWidget: ShoutWidget = new ShoutWidget();
shoutWidget.id = 'JupyterShoutWidget'; // Widgets need an id

app.shell.add(shoutWidget, 'right');
```
The `ShoutWidget` is a widget that contains a button that when clicked
emit a signal `messageShouted` that any callback can listen to to react
to it and display an alert to the user.
```ts
// src/index.ts#L99-L103

shout() {
this._lastShoutTime = new Date();
this._messageShouted.emit(this._lastShoutTime);
window.alert('Shouting at ' + this._lastShoutTime);
}
```
## Connect the button and the status bar
The status bar does not exist in all Jupyter applications (e.g. in
Jupyter Notebook). So a good practice is to make that dependency
optional and test for it to be non-null to carry related action:
```ts
// src/index.ts#L135-L135

if (statusBar) {
```
In this specific case, the action is to create a widget to add to the
status bar. You can achieve that by calling the `registerStatusItem`
method from the status bar object.
```ts
// src/index.ts#L136-L138

const statusBarWidget = new ShoutStatusBarSummary();

statusBar.registerStatusItem('shoutStatusBarSummary', {
```
If you want to react to a click on the button, you can `connect` to the
widget `messageShouted` signal. In which for example, you update the
text displayed in the status bar.
```ts
// src/index.ts#L142-L144

// Connect to the messageShouted to be notified when a new message
// is published and react to it by updating the status bar widget.
shoutWidget.messageShouted.connect((widget: ShoutWidget, time: Date) => {
```
## Where to Go Next
You can have more information about making extension compatible with
multiple applications in the
[Extension Dual Compatibility Guide](https://jupyterlab.readthedocs.io/en/latest/extension_dual_compatibility.html).
5 changes: 5 additions & 0 deletions shout-button-message/install.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"packageManager": "python",
"packageName": "jupyterlab_examples_shout_button",
"uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyterlab_examples_shout_button"
}
16 changes: 16 additions & 0 deletions shout-button-message/jupyterlab_examples_shout_button/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
try:
from ._version import __version__
except ImportError:
# Fallback when using the package in dev mode without installing
# in editable mode with pip. It is highly recommended to install
# the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
import warnings
warnings.warn("Importing 'jupyterlab_examples_shout_button' outside a proper installation.")
__version__ = "dev"


def _jupyter_labextension_paths():
return [{
"src": "labextension",
"dest": "@jupyterlab-examples/shout-button"
}]
Loading

0 comments on commit f3b2b0b

Please sign in to comment.