diff --git a/.travis.yml b/.travis.yml index 09fbd47..b54d6dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ python: - "3.6" install: - - pip install flake8 jupyterlab~=1.2 + - pip install flake8 "jupyterlab>=2,<3" script: - pwd diff --git a/README.md b/README.md index 8c4bbe9..d96572b 100644 --- a/README.md +++ b/README.md @@ -113,3 +113,8 @@ Jupyter Lab: jupyter labextension link Tagged releases of this repository are automatically published to Pypi and NPM by Travis. + +To test that the binder and repo buttons work when developing locally set some placeholder environment variables, e.g.: +``` +BINDER_LAUNCH_HOST=http://localhost BINDER_REPO_URL=http://localhost BINDER_PERSISTENT_REQUEST=v2/gh/repo BINDER_REF_URL=http://localhost jupyter-lab --debug +``` diff --git a/binder/postBuild b/binder/postBuild index aad2e0b..2f1294a 100644 --- a/binder/postBuild +++ b/binder/postBuild @@ -4,6 +4,13 @@ set -eux env | sort pwd +# jupyter-offlinenotebook is automatically installed by repo2docker. +# Uninstall to avoid conflicts +jupyter labextension uninstall --no-build jupyter-offlinenotebook + +# Upgrade jupyterlab if necessary +conda install jupyterlab=2 + # repo2docker copies this repo into $HOME which means jupyter labextension # picks up hidden dot files and runs into problems so install from a # different directory diff --git a/jupyter_offlinenotebook/static/jslib/index.ts b/jupyter_offlinenotebook/static/jslib/index.ts index 8aee82b..dd12ed9 100644 --- a/jupyter_offlinenotebook/static/jslib/index.ts +++ b/jupyter_offlinenotebook/static/jslib/index.ts @@ -1,11 +1,11 @@ import { IDisposable, DisposableDelegate -} from '@phosphor/disposable'; +} from '@lumino/disposable'; import { Widget -} from '@phosphor/widgets'; +} from '@lumino/widgets'; import { PageConfig @@ -35,7 +35,13 @@ import { import * as offline from "./offlinenotebook"; import $ from "jquery"; -import { JSONValue } from '@phosphor/coreutils'; +import { PartialJSONValue } from '@lumino/coreutils'; + + +/** + * The CSS class for a Toolbar icon. + */ +const CSS_ICON_CLASS = 'jp-OfflineNotebookToolbarIcon'; /** * The plugin registration information. @@ -66,7 +72,7 @@ export let buttons: Array<[string, ToolbarButton]> = []; buttons.push(['downloadVisible', new ToolbarButton({ className: 'downloadVisible', - iconClassName: 'fa fa-download', + iconClass: 'fas fa-download ' + CSS_ICON_CLASS, onClick: () => { downloadNotebookFromBrowser(panel); }, @@ -77,7 +83,7 @@ export if (offline.repoid()) { buttons.push(['saveToBrowser', new ToolbarButton({ className: 'saveToBrowser', - iconClassName: 'fa fa-cloud-download', + iconClass: 'fas fa-cloud-download-alt ' + CSS_ICON_CLASS, onClick: () => { localstoreSaveNotebook(panel); }, @@ -85,7 +91,7 @@ export })]); buttons.push(['loadFromBrowser', new ToolbarButton({ className: 'loadFromBrowser', - iconClassName: 'fa fa-cloud-upload', + iconClass: 'fas fa-cloud-upload-alt ' + CSS_ICON_CLASS, onClick: () => { localstoreLoadNotebook(panel); }, @@ -98,14 +104,14 @@ export } if (offline.binderRefUrl()) { let repoIcons: StringStringMap = { - 'GitHub': 'fa fa-github', - 'GitLab': 'fa fa-gitlab', - 'Git': 'fa fa-git' + 'GitHub': 'fab fa-github', + 'GitLab': 'fab fa-gitlab', + 'Git': 'fab fa-git' } buttons.push(['openRepo', new ToolbarButton({ className: 'openRepo', - iconClassName: repoIcons[offline.repoLabel()] || 'fa-external-link', + iconClass: (repoIcons[offline.repoLabel()] || 'fas fa-external-link-alt') + ' ' + CSS_ICON_CLASS, onClick: offline.openBinderRepo, tooltip: 'Visit Binder repository', label: offline.repoLabel() @@ -114,7 +120,7 @@ export if (offline.binderPersistentUrl()) { buttons.push(['linkToBinder', new ToolbarButton({ className: 'linkToBinder', - iconClassName: 'fa fa-link', + iconClass: 'fas fa-link ' + CSS_ICON_CLASS, onClick: () => { showBinderLink(panel); }, @@ -145,7 +151,12 @@ function formatRepoPathforDialog(path: string): string { function localstoreSaveNotebook(panel: NotebookPanel) { var path = panel.context.path; - var nb = panel.content.model.toJSON() + var nb = panel.content.model?.toJSON(); + if (!nb) { + var e = 'Content model is null'; + showErrorMessage('Local storage error', e); + throw (e); + } var repopathDisplay = formatRepoPathforDialog(path); offline.saveNotebook(path, nb, function (key: string) { @@ -176,7 +187,7 @@ function localstoreLoadNotebook(panel: NotebookPanel) { var repopathDisplay = formatRepoPathforDialog(path); var key = 'repoid:' + offline.repoid() + ' path:' + path; offline.loadNotebook(path, - (nb: JSONValue) => { + (nb: PartialJSONValue) => { if (nb) { console.log('offline-notebook found ' + key); return showDialog({ @@ -210,7 +221,12 @@ function localstoreLoadNotebook(panel: NotebookPanel) { function downloadNotebookFromBrowser(panel: NotebookPanel) { var name = panel.context.path.replace(/.*\//, ''); - var nb = panel.content.model.toJSON() + var nb = panel.content.model?.toJSON(); + if (!nb) { + var e = 'Content model is null'; + showErrorMessage('Local storage error', e); + throw (e); + } offline.downloadNotebookFromBrowser(name, nb); } @@ -248,7 +264,7 @@ function createCopyShareURLNode(binderUrl: string): HTMLElement { }) button.append( $('', { - 'class': 'fa fa-clipboard' + 'class': 'fas fa-clipboard' })); body.append(button); // Unwrap JQuery object diff --git a/jupyter_offlinenotebook/static/jslib/offlinenotebook.d.ts b/jupyter_offlinenotebook/static/jslib/offlinenotebook.d.ts index aae62fa..2f2482f 100644 --- a/jupyter_offlinenotebook/static/jslib/offlinenotebook.d.ts +++ b/jupyter_offlinenotebook/static/jslib/offlinenotebook.d.ts @@ -1,9 +1,9 @@ -import { JSONValue } from "@phosphor/coreutils"; +import { PartialJSONValue } from "@lumino/coreutils"; export function initialise(data: JSON): null; -export function saveNotebook(path: string, nb: JSONValue, success: CallableFunction, error: CallableFunction) +export function saveNotebook(path: string, nb: PartialJSONValue, success: CallableFunction, error: CallableFunction) export function loadNotebook(path: string, success: CallableFunction, error: CallableFunction) -export function downloadNotebookFromBrowser(name: string, nb: JSONValue): null; +export function downloadNotebookFromBrowser(name: string, nb: PartialJSONValue): null; export function openBinderRepo(): null; export function repoid(): string; diff --git a/jupyter_offlinenotebook/static/style/index.css b/jupyter_offlinenotebook/static/style/index.css index e69de29..a6cf7c4 100644 --- a/jupyter_offlinenotebook/static/style/index.css +++ b/jupyter_offlinenotebook/static/style/index.css @@ -0,0 +1,7 @@ +/* Toolbar FontAwesome icons + * Need to override 'color: unset !important': + * https://github.com/jupyterlab/jupyterlab/blob/v2.0.1/packages/ui-components/style/base.css#L70-L73 + */ +.jp-OfflineNotebookToolbarIcon { + color: var(--md-grey-700); +} diff --git a/package.json b/package.json index 0aa666c..dbf88c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jupyter-offlinenotebook", - "version": "0.0.11", + "version": "0.1.0", "description": "JupyterLab offline-notebook extension.", "keywords": [ "jupyter", @@ -32,17 +32,17 @@ "watch": "tsc -w" }, "dependencies": { - "@jupyterlab/application": "^1.2.1", - "@jupyterlab/apputils": "^1.2.1", - "@jupyterlab/docregistry": "^1.2.1", - "@jupyterlab/notebook": "^1.2.2", - "@phosphor/disposable": "^1.3.1", + "@jupyterlab/application": "^2.0.2", + "@jupyterlab/apputils": "^2.0.2", + "@jupyterlab/docregistry": "^2.0.2", + "@jupyterlab/notebook": "^2.0.2", + "@lumino/disposable": "^1.3.5", "@types/jquery": "^3", "jquery": "^3" }, "devDependencies": { "rimraf": "~3.0.0", - "typescript": "~3.7.2" + "typescript": "~3.7.3" }, "sideEffects": [ "jupyter_offlinenotebook/static/style/*.css"