diff --git a/.gitignore b/.gitignore index 02d22007..7d0267bf 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,7 @@ junit.xml retrolab/static/* !retrolab/static/favicons retrolab/labextension +retrolab/schemas # playwright app/test-results diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1680989a..6b45e4fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,8 +24,8 @@ conda activate retrolab # Install package in development mode pip install -e . -# Link the RetroLab JupyterLab extension -jupyter labextension develop . --overwrite +# Link the RetroLab JupyterLab extension and RetroLab schemas +jlpm develop # Enable the server extension jupyter server extension enable retrolab diff --git a/app/index.js b/app/index.js index 176995c1..3452072a 100644 --- a/app/index.js +++ b/app/index.js @@ -124,10 +124,7 @@ async function main() { ), require('@jupyterlab/docprovider-extension'), require('@jupyterlab/filebrowser-extension').default.filter(({ id }) => - [ - '@jupyterlab/filebrowser-extension:factory', - '@jupyterlab/filebrowser-extension:download' - ].includes(id) + ['@jupyterlab/filebrowser-extension:factory'].includes(id) ), require('@jupyterlab/fileeditor-extension').default.filter(({ id }) => ['@jupyterlab/fileeditor-extension:plugin'].includes(id) diff --git a/app/webpack.config.js b/app/webpack.config.js index 0ee849f2..92ec9cc7 100644 --- a/app/webpack.config.js +++ b/app/webpack.config.js @@ -37,7 +37,8 @@ fs.copySync(cssImports, path.resolve(buildDir, 'extraStyle.js')); const extras = Build.ensureAssets({ packageNames: names, - output: buildDir + output: buildDir, + schemaOutput: path.resolve(__dirname, '..', 'retrolab') }); /** diff --git a/binder/postBuild b/binder/postBuild index 3413ce50..82203ae5 100644 --- a/binder/postBuild +++ b/binder/postBuild @@ -3,6 +3,6 @@ set -euo pipefail jlpm && jlpm run build python -m pip install -e . -jupyter labextension develop . --overwrite +jlpm run develop jupyter server extension enable retrolab -jupyter serverextension enable retrolab +jupyter serverextension enable retrolab \ No newline at end of file diff --git a/buildutils/src/develop.ts b/buildutils/src/develop.ts new file mode 100644 index 00000000..b464fea2 --- /dev/null +++ b/buildutils/src/develop.ts @@ -0,0 +1,51 @@ +/* ----------------------------------------------------------------------------- +| Copyright (c) Jupyter Development Team. +| Distributed under the terms of the Modified BSD License. +|----------------------------------------------------------------------------*/ + +import commander from 'commander'; + +import fs from 'fs-extra'; + +import path from 'path'; + +import process from 'process'; + +import { run } from '@jupyterlab/buildutils'; + +commander + .description('Setup the repository for develop mode') + .option('--overwrite', 'Force linking the RetroLab schemas') + .option('--source', 'The path to the retrolab package') + .action((options: any) => { + const { overwrite } = options; + const prefix = run( + 'python -c "import sys; print(sys.prefix)"', + { + stdio: 'pipe' + }, + true + ); + const source = path.resolve(options.source ?? process.cwd()); + const sourceDir = path.join(source, 'retrolab', 'schemas', '@retrolab'); + const destDir = path.join( + prefix, + 'share', + 'jupyter', + 'lab', + 'schemas', + '@retrolab' + ); + if (overwrite) { + try { + fs.unlinkSync(destDir); + console.log('Removed previous symlink:', destDir); + } catch (e) { + console.info('Skip unlinkink', destDir); + } + } + console.log('Symlinking:', sourceDir, destDir); + fs.symlinkSync(sourceDir, destDir, 'dir'); + }); + +commander.parse(process.argv); diff --git a/package.json b/package.json index d8c7a55a..b77bd7ec 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "clean": "lerna run clean", "eslint": "eslint . --ext .ts,.tsx --fix", "eslint:check": "eslint . --ext .ts,.tsx", + "develop": "jupyter labextension develop . --overwrite && node ./buildutils/lib/develop.js --overwrite", "install": "lerna bootstrap", "integrity": "node buildutils/lib/ensure-repo.js", "prettier": "prettier --write \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"", diff --git a/packages/application-extension/package.json b/packages/application-extension/package.json index 5c24aee9..ad68a7c9 100644 --- a/packages/application-extension/package.json +++ b/packages/application-extension/package.json @@ -65,7 +65,8 @@ "access": "public" }, "jupyterlab": { - "extension": true + "extension": true, + "schemaDir": "schema" }, "styleModule": "style/index.js" } diff --git a/packages/application-extension/schema/top.json b/packages/application-extension/schema/top.json new file mode 100644 index 00000000..4d0eeda8 --- /dev/null +++ b/packages/application-extension/schema/top.json @@ -0,0 +1,16 @@ +{ + "jupyter.lab.setting-icon": "retro-ui-components:retroSun", + "jupyter.lab.setting-icon-label": "RetroLab Top Area", + "title": "RetroLab Top Area", + "description": "RetroLab Top Area settings", + "properties": { + "visible": { + "type": "boolean", + "title": "Top Bar Visibility", + "description": "Whether to show the top bar or not", + "default": true + } + }, + "additionalProperties": false, + "type": "object" +} diff --git a/packages/application-extension/src/index.ts b/packages/application-extension/src/index.ts index cc9a02a7..b8424907 100644 --- a/packages/application-extension/src/index.ts +++ b/packages/application-extension/src/index.ts @@ -38,6 +38,7 @@ import { PromiseDelegate } from '@lumino/coreutils'; import { DisposableDelegate, DisposableSet } from '@lumino/disposable'; import { Widget } from '@lumino/widgets'; +import { ISettingRegistry } from '@jupyterlab/settingregistry'; /** * The default notebook factory. @@ -451,20 +452,25 @@ const title: JupyterFrontEndPlugin = { const topVisibility: JupyterFrontEndPlugin = { id: '@retrolab/application-extension:top', requires: [IRetroShell, ITranslator], - optional: [IMainMenu], + optional: [IMainMenu, ISettingRegistry], activate: ( app: JupyterFrontEnd, retroShell: IRetroShell, translator: ITranslator, - menu: IMainMenu | null + menu: IMainMenu | null, + settingRegistry: ISettingRegistry | null ) => { const trans = translator.load('retrolab'); const top = retroShell.top; + const pluginId = topVisibility.id; app.commands.addCommand(CommandIDs.toggleTop, { label: trans.__('Show Header'), execute: () => { top.setHidden(top.isVisible); + if (settingRegistry) { + void settingRegistry.set(pluginId, 'visible', top.isVisible); + } }, isToggled: () => top.isVisible }); @@ -473,6 +479,25 @@ const topVisibility: JupyterFrontEndPlugin = { menu.viewMenu.addGroup([{ command: CommandIDs.toggleTop }], 2); } + if (settingRegistry) { + const loadSettings = settingRegistry.load(pluginId); + const updateSettings = (settings: ISettingRegistry.ISettings): void => { + const visible = settings.get('visible').composite as boolean; + top.setHidden(!visible); + }; + + Promise.all([loadSettings, app.restored]) + .then(([settings]) => { + updateSettings(settings); + settings.changed.connect(settings => { + updateSettings(settings); + }); + }) + .catch((reason: Error) => { + console.error(reason.message); + }); + } + const onChanged = (): void => { if (app.format === 'desktop') { retroShell.expandTop(); diff --git a/pyproject.toml b/pyproject.toml index 9ba5bf14..e8f2bb5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["jupyter_packaging~=0.10", "jupyterlab>=3.2.0rc0,==3.*"] +requires = ["jupyter_packaging~=0.10", "jupyterlab~=3.2"] build-backend = "jupyter_packaging.build_api" [license] @@ -17,4 +17,4 @@ build_cmd = "build:prod" npm = ["jlpm"] [tool.check-manifest] -ignore = ["app/**", "binder/**", "buildutils/**", "packages/**", "*.json", "yarn.lock", "readthedocs.yml", ".bumpversion.cfg", ".*", "lint-staged.config.js", "logo.*", "retrolab/labextension/**", "retrolab/static/**", "retrolab/template/**"] +ignore = ["app/**", "binder/**", "buildutils/**", "packages/**", "*.json", "yarn.lock", "readthedocs.yml", ".bumpversion.cfg", ".*", "lint-staged.config.js", "logo.*", "retrolab/labextension/**", "retrolab/schemas/**", "retrolab/static/**", "retrolab/template/**"] diff --git a/setup.cfg b/setup.cfg index 3b3e2908..7325574e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,7 +28,7 @@ include_package_data = True packages = find: python_requires = >=3.6 install_requires = - jupyterlab>=3.2.0rc0,==3.* + jupyterlab~=3.2 jupyterlab_server~=2.3 jupyter_server~=1.4 nbclassic~=0.2 diff --git a/setup.py b/setup.py index 1a2458e6..883e04bf 100644 --- a/setup.py +++ b/setup.py @@ -18,11 +18,13 @@ ensured_targets = [ str(lab_extension_dest / "static" / "style.js"), str(main_bundle_dest / "bundle.js"), + str(HERE / NAME / "schemas/@retrolab/application-extension/package.json.orig"), ] data_files_spec = [ ("share/jupyter/labextensions/%s" % labext_name, str(lab_extension_dest), "**"), ("share/jupyter/labextensions/%s" % labext_name, str(HERE), "install.json"), + ("share/jupyter/lab/schemas", f"{NAME}/schemas", "@retrolab/**/*"), ( "etc/jupyter/jupyter_server_config.d", "jupyter-config/jupyter_server_config.d", @@ -39,13 +41,10 @@ from jupyter_packaging import wrap_installers, npm_builder, get_data_files # In develop mode, just run yarn - builder = npm_builder(build_cmd='build', npm='jlpm', force=True) + builder = npm_builder(build_cmd="build", npm="jlpm", force=True) cmdclass = wrap_installers(post_develop=builder, ensured_targets=ensured_targets) - setup_args = dict( - cmdclass=cmdclass, - data_files=get_data_files(data_files_spec) - ) + setup_args = dict(cmdclass=cmdclass, data_files=get_data_files(data_files_spec)) except ImportError: setup_args = dict()