Skip to content

Commit

Permalink
Log console (jupyterlab#101)
Browse files Browse the repository at this point in the history
* Two new examples about log console.

* Added a context menu exaple issue jupyterlab#100.

* Added the new examples to readme

* Add log-console and context-menu to CI workflow

* Fix log-console linting

* Fix context-menu linting

* Fix eslint for log-console/custom-log-console

* Disable eslint camelcase rule

* Remove eslint warnings for the log console example

* Switch to warn for @typescript-eslint/camelcase

* Minor wording pass on log-console and context-menu

* Delete Untitled.ipynb

* README improvements

* Correct author to align with jupyterlab#103

Co-authored-by: Carlos <[email protected]>
Co-authored-by: Jeremy Tuloup <[email protected]>
Co-authored-by: Frederic Collonval <[email protected]>
  • Loading branch information
4 people authored Jul 13, 2020
1 parent 3cd1f85 commit 616ee92
Show file tree
Hide file tree
Showing 48 changed files with 1,276 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ jobs:
- basics/signals
- command-palette
- commands
- context-menu
- launcher
- log-console/custom-log-console
- log-console/log-messages
- main-menu
- react/react-widget
- settings
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ Start with the [Hello World](basics/hello-world) and then jump to the topic you
- [State](state)
- [React Widget](react/react-widget)
- [Widgets](widget-tracker/widgets)
- [Log Messages](log-console/log-messages)
- [Custom Log Console](log-console/custom-log-console)
- [Context Menu](context-menu)
- [Kernel Output](advanced/kernel-output)
- [Kernel Messaging](advanced/kernel-messaging)
- [Server Hello World](advanced/server-extension)
Expand Down Expand Up @@ -139,6 +142,28 @@ Add a new Widget element to the main window.

[![Custom Tab](widget-tracker/widgets/preview.png)](widget-tracker/widgets)

## Log Console

### [Log Messages](log-messages)

Send a log message to the log console.

[![Log Messages](log-console/log-messages/preview.gif)](log-console/log-messages)

### [Custom Log Console](custom-log-console)

Create a new log console.

[![Custom Log Console](log-console/custom-log-console/preview.gif)](log-console/custom-log-console)

## Context Menu

### [Context Menu](context-menu)

Add a new button to an existent context menu.

[![Context Menu](context-menu/preview.gif)](context-menu)

## Advanced

### [Kernel Output](advanced/kernel-output)
Expand Down
1 change: 1 addition & 0 deletions advanced/kernel-messaging/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions advanced/kernel-output/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions advanced/server-extension/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions basics/datagrid/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions basics/hello-world/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions basics/signals/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions command-palette/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
1 change: 1 addition & 0 deletions commands/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
Expand Down
4 changes: 4 additions & 0 deletions context-menu/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
coverage
**/*.d.ts
47 changes: 47 additions & 0 deletions context-menu/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:jsdoc/recommended',
'plugin:prettier/recommended',
'plugin:react/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module'
},
plugins: ['@typescript-eslint', 'jsdoc'],
rules: {
'@typescript-eslint/interface-name-prefix': [
'error',
{ prefixWithI: 'always' }
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'warn',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
'error',
'single',
{ avoidEscape: true, allowTemplateLiterals: false }
],
curly: ['error', 'all'],
eqeqeq: 'error',
'jsdoc/require-param-type': 'off',
'jsdoc/require-property-type': 'off',
'jsdoc/require-returns-type': 'off',
'jsdoc/no-types': 'warn',
'prefer-arrow-callback': 'error'
},
settings: {
jsdoc: {
mode: 'typescript'
},
react: {
version: 'detect'
}
}
};
6 changes: 6 additions & 0 deletions context-menu/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.bundle.*
lib/
node_modules/
*.egg-info/
.ipynb_checkpoints
*.tsbuildinfo
103 changes: 103 additions & 0 deletions context-menu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Context Menu

> Create a new button in a context menu.
This is a basic example to show how to add a new entry to an existent context menu.

![context menu example](preview.gif)

In JupyterLab plugins can expose context menus to offer an easy way to execute commands and perform actions. In this example, you will learn how to add a new entry to the file browser context menu, and at the same time how to register a new file type.

> It is strongly recommended to read [commands](https://github.com/jupyterlab/extension-examples/tree/master/commands) example before diving into this one.
To implement this example you need to install the `@jupyterlab/filebrowser`, where you can find the interface `IFileBrowserFactory` necessary to require the file browser instance of JupyterLab.

> This is not necessary to create a context menu. But it is a common case to be extended.
First of all, you will start looking into the declaration of the extension:

<!-- prettier-ignore-start -->
```ts
// src/index.ts#L9-L14

const extension: JupyterFrontEndPlugin<void> = {
id: 'context-menu',
autoStart: true,
requires: [IFileBrowserFactory],
optional: [],
activate: (app: JupyterFrontEnd, factory: IFileBrowserFactory) => {
```
<!-- prettier-ignore-end -->
For this extension, you need to require `IFileBrowserFactory` to track the file browser item clicked by the user.
The example shows you how to create a new file type and add the entry to the context menu only to this file type. The first step is optional, you can also add your button to an existing file type (or all of them!).
To register a new file type, you need to call the `addFileType()` method of `docRegistry` property present in the `JupyterFrontEnd` object. This method requires an `IFileType` object with some properties to define your file type. The most important are:
- `name`: the new file type.
- `extension`: the list of extensions.
- `fileFormat`: the file content format (_base64_, _json_ or _text_).
- `contentType`: the file type (_directory_, _notebook_ or _file_).
- `mimeType`: the content mime type.
<!-- prettier-ignore-start -->
```ts
// src/index.ts#L15-L23

app.docRegistry.addFileType({
name: 'example',
icon: runIcon,
displayName: 'Example File',
extensions: ['.example'],
fileFormat: 'text',
contentType: 'file',
mimeTypes: ['text/plain']
});
```
<!-- prettier-ignore-end -->
The next step is to define the command that will be executed when clicking on the context menu entry. If you want to access the item information, you need to use the `IFileBrowserFactory` object to obtain the file browser selected item.
<!-- prettier-ignore-start -->
```ts
// src/index.ts#L25-L38

app.commands.addCommand('jlab-examples/context-menu:open', {
label: 'Example',
caption: "Example context menu button for file browser's items.",
icon: buildIcon,
execute: () => {
const file = factory.tracker.currentWidget.selectedItems().next();

showDialog({
title: file.name,
body: 'Path: ' + file.path,
buttons: [Dialog.okButton()]
}).catch(e => console.log(e));
}
});
```
<!-- prettier-ignore-end -->
Finally, you can add the command to a context menu using the `addItem()` method present in the `contextMenu` property. This method requires an `IItemOptions` object with the following properties:
- `command`: the command to execute.
- `selector`: the CSS classes of the element where you want to add the entry.
- `rank`: the position in the context menu
<!-- prettier-ignore-start -->
```ts
// src/index.ts#L40-L44

app.contextMenu.addItem({
command: 'jlab-examples/context-menu:open',
selector: '.jp-DirListing-item[data-file-type="example"]',
rank: 0
});
```
<!-- prettier-ignore-end -->
The `selector` can be any valid [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors). In this case, the first part is the CSS class that identifies the file browser items `.jp-DirListing-item` and the second part `[data-file-type="example"]` is a attribute value to be found on the item. You can omit the second part to add the button to every file type.
You can find some of the CSS classes that identify different widgets in JupyterLab in the [developer documentation](https://jupyterlab.readthedocs.io/en/stable/developer/css.html#commonly-used-css-selectors).
59 changes: 59 additions & 0 deletions context-menu/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"name": "@jupyterlab-examples/context-menu",
"version": "0.1.0",
"description": "A minimal JupyterLab example to develop a context-menu.",
"keywords": [
"jupyter",
"jupyterlab",
"jupyterlab-extension"
],
"homepage": "https://github.com/jupyterlab/extension-examples",
"bugs": {
"url": "https://github.com/jupyterlab/extension-examples/issues"
},
"license": "BSD-3-Clause",
"author": "Project Jupyter Contributors",
"files": [
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
"style": "style/index.css",
"repository": {
"type": "git",
"url": "https://github.com/jupyterlab/extension-examples.git"
},
"scripts": {
"build": "tsc",
"clean": "rimraf lib tsconfig.tsbuildinfo",
"link": "jupyter labextension link . --no-build",
"prepare": "jlpm run clean && jlpm run build",
"eslint": "eslint . --ext .ts,.tsx --fix",
"eslint:check": "eslint . --ext .ts,.tsx",
"watch": "tsc -w"
},
"dependencies": {
"@jupyterlab/application": "^2.1.2",
"@jupyterlab/apputils": "^2.1.1",
"@jupyterlab/filebrowser": "^2.1.2",
"@jupyterlab/ui-components": "^2.1.1"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.21.0",
"@typescript-eslint/parser": "^2.21.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-jsdoc": "^22.0.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^7.18.3",
"rimraf": "^3.0.0",
"typescript": "~3.7.5"
},
"sideEffects": [
"style/*.css"
],
"jupyterlab": {
"extension": true
}
}
Binary file added context-menu/preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions context-menu/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';
import { IFileBrowserFactory } from '@jupyterlab/filebrowser';
import { showDialog, Dialog } from '@jupyterlab/apputils';
import { buildIcon, runIcon } from '@jupyterlab/ui-components';

const extension: JupyterFrontEndPlugin<void> = {
id: 'context-menu',
autoStart: true,
requires: [IFileBrowserFactory],
optional: [],
activate: (app: JupyterFrontEnd, factory: IFileBrowserFactory) => {
app.docRegistry.addFileType({
name: 'example',
icon: runIcon,
displayName: 'Example File',
extensions: ['.example'],
fileFormat: 'text',
contentType: 'file',
mimeTypes: ['text/plain']
});

app.commands.addCommand('jlab-examples/context-menu:open', {
label: 'Example',
caption: "Example context menu button for file browser's items.",
icon: buildIcon,
execute: () => {
const file = factory.tracker.currentWidget.selectedItems().next();

showDialog({
title: file.name,
body: 'Path: ' + file.path,
buttons: [Dialog.okButton()]
}).catch(e => console.log(e));
}
});

app.contextMenu.addItem({
command: 'jlab-examples/context-menu:open',
selector: '.jp-DirListing-item[data-file-type="example"]',
rank: 0
});
}
};

export default extension;
File renamed without changes.
Loading

0 comments on commit 616ee92

Please sign in to comment.