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 Workspaces GUI #15946

Merged
merged 30 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4d6529e
Refactor workspaces to provide a scaffold for Workspaces UI
krassowski Mar 5, 2024
672544c
Remove workspace commands from top-level file menu
krassowski Mar 7, 2024
8fcd1f6
Implement workspaces sidebar and menu implementation
krassowski Feb 2, 2024
8b5812c
Add workspaces docs to a dedicated file, add GUI stub
krassowski Mar 7, 2024
95ac8b3
Add unit tests for `WorkspacesModel`
krassowski Mar 8, 2024
efec5c6
Implement validation of workspace names, cleanup
krassowski Mar 8, 2024
c9135f9
Add documentation snapshot which tests opening
krassowski Mar 8, 2024
7926120
`.jupyterlab-workspace` files do not need licence headers
krassowski Mar 9, 2024
4f90990
Merge remote-tracking branch 'upstream/main' into workspace-manager
krassowski Mar 9, 2024
da2711e
Fix tests, update snapshots
krassowski Mar 9, 2024
0de7c37
Fix sidebar test by fixing workspaces state mock implementation
krassowski Mar 11, 2024
5dc0a2e
Test workspaces menu
krassowski Mar 11, 2024
10a7d38
Lint: add missing brackets
krassowski Mar 13, 2024
bcf8dfc
Merge branch 'main' into workspace-manager
krassowski Mar 15, 2024
19f3ad8
Add workspace name in the "Delete" tooltip
krassowski Mar 19, 2024
2872d00
Adjust use of ellipsis (…) in workspace commands/menu
krassowski Mar 19, 2024
f15ed80
Add quotes to emphasize workspace name,
krassowski Mar 19, 2024
c257f6d
Add note that deleting all workspaces is irreversible
krassowski Mar 19, 2024
b934baa
Rename `InputDialogTextualBase` to `InputDialogTextBase`
krassowski Mar 19, 2024
6459bc0
Add a note about characters allowed in workspace names.
krassowski Mar 19, 2024
8134d1f
Add an example for workspace date/time format.
krassowski Mar 19, 2024
3e90ce4
Apply suggestions on wording in workspaces docs
krassowski Mar 19, 2024
3c867b4
Fix snapshot (previous update got flaky kernel from another test)
krassowski Mar 19, 2024
44da8ef
Merge remote-tracking branch 'upstream/main' into workspace-manager
krassowski Mar 21, 2024
098612e
Update Playwright Snapshots
github-actions[bot] Mar 21, 2024
bcc4b77
Update Playwright Snapshots
github-actions[bot] Mar 21, 2024
b602c1f
Revert spurious snapshot updates
krassowski Mar 21, 2024
4dc6cfd
Update the test workspace to account for the new "Recent Files" section
krassowski Mar 22, 2024
e7746e9
Fix flaky snapshot
krassowski Mar 22, 2024
fde83ee
Update one more snapshot after merge
krassowski Mar 22, 2024
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
8 changes: 8 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,11 @@ pkg:vega:
- any-glob-to-any-file:
- packages/vega5-extension/**/*
- packages/vega5-extension/*

pkg:workspaces:
- changed-files:
- any-glob-to-any-file:
- packages/workspaces/**/*
- packages/workspaces/*
- packages/workspaces-extension/**/*
- packages/workspaces-extension/*
3 changes: 2 additions & 1 deletion buildutils/src/ensure-repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ const SKIP_CSS: Dict<string[]> = {
'@jupyterlab/tooltip-extension',
'@jupyterlab/translation-extension',
'@jupyterlab/ui-components-extension',
'@jupyterlab/vega5-extension'
'@jupyterlab/vega5-extension',
'@jupyterlab/workspaces-extension'
],
'@jupyterlab/notebook': ['@jupyterlab/application'],
'@jupyterlab/rendermime-interfaces': ['@lumino/widgets'],
Expand Down
11 changes: 9 additions & 2 deletions dev_mode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@
"@jupyterlab/ui-components": "~4.2.0-alpha.0",
"@jupyterlab/ui-components-extension": "~4.2.0-alpha.0",
"@jupyterlab/vega5-extension": "~4.2.0-alpha.0",
"@jupyterlab/workspaces": "~4.2.0-alpha.0",
"@jupyterlab/workspaces-extension": "~4.2.0-alpha.0",
"@lezer/common": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@lumino/algorithm": "^2.0.0",
Expand Down Expand Up @@ -189,7 +191,8 @@
"@jupyterlab/tooltip-extension": "~4.2.0-alpha.0",
"@jupyterlab/translation-extension": "~4.2.0-alpha.0",
"@jupyterlab/ui-components-extension": "~4.2.0-alpha.0",
"@jupyterlab/vega5-extension": "~4.2.0-alpha.0"
"@jupyterlab/vega5-extension": "~4.2.0-alpha.0",
"@jupyterlab/workspaces-extension": "~4.2.0-alpha.0"
},
"devDependencies": {
"@jupyterlab/builder": "^4.2.0-alpha.0",
Expand Down Expand Up @@ -265,7 +268,8 @@
"@jupyterlab/toc-extension": "",
"@jupyterlab/tooltip-extension": "",
"@jupyterlab/translation-extension": "",
"@jupyterlab/ui-components-extension": ""
"@jupyterlab/ui-components-extension": "",
"@jupyterlab/workspaces-extension": ""
},
"mimeExtensions": {
"@jupyterlab/javascript-extension": "",
Expand Down Expand Up @@ -321,6 +325,7 @@
"@jupyterlab/tooltip",
"@jupyterlab/translation",
"@jupyterlab/ui-components",
"@jupyterlab/workspaces",
"@lezer/common",
"@lezer/highlight",
"@lumino/algorithm",
Expand Down Expand Up @@ -441,6 +446,8 @@
"@jupyterlab/ui-components": "../packages/ui-components",
"@jupyterlab/ui-components-extension": "../packages/ui-components-extension",
"@jupyterlab/vega5-extension": "../packages/vega5-extension",
"@jupyterlab/workspaces": "../packages/workspaces",
"@jupyterlab/workspaces-extension": "../packages/workspaces-extension",
"@jupyterlab/builder": "../builder",
"@jupyterlab/buildutils": "../buildutils",
"@jupyterlab/template": "../buildutils/template",
Expand Down
1 change: 1 addition & 0 deletions dev_mode/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ import '@jupyterlab/tooltip-extension/style/index.js';
import '@jupyterlab/translation-extension/style/index.js';
import '@jupyterlab/ui-components-extension/style/index.js';
import '@jupyterlab/vega5-extension/style/index.js';
import '@jupyterlab/workspaces-extension/style/index.js';
2 changes: 2 additions & 0 deletions docs/source/user/directories.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ the default values given by extensions, as well as the default overrides from
the :ref:`overrides.json <overridesjson>` file in the application's settings
directory.

.. _workspaces-directory:

JupyterLab Workspaces Directory
-------------------------------

Expand Down
1 change: 1 addition & 0 deletions docs/source/user/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ file_formats
debugger
toc
extensions
workspaces
jupyterhub
export
language
Expand Down
89 changes: 3 additions & 86 deletions docs/source/user/urls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ using ``#cell-id=<cell-id>`` Fragment Identification Syntax.
The ``cell-id`` fragment locator is not part of a formal Jupyter standard and subject to change.
To leave feedback, please comment in the discussion: `nbformat#317 <https://github.com/jupyter/nbformat/issues/317>`_.

.. _url-workspaces-ui:
.. _url-workspaces:

Managing Workspaces (UI)
------------------------
Managing Workspaces (URL)
-------------------------

JupyterLab sessions always reside in a workspace. Workspaces contain the state
of JupyterLab: the files that are currently open, the layout of the application
Expand Down Expand Up @@ -168,86 +168,3 @@ To reset the contents of the default workspace and load a notebook:
.. code-block:: none

http(s)://<server:port>/<lab-location>/lab/tree/path/to/notebook.ipynb?reset

.. _url-workspaces-cli:

Managing Workspaces (CLI)
-------------------------

JupyterLab provides a command-line interface for workspace ``import`` and
``export``:

.. code-block:: bash

$ # Exports the default JupyterLab workspace
$ jupyter lab workspaces export
{"data": {}, "metadata": {"id": "/lab"}}
$
$ # Exports the workspaces named `foo`
$ jupyter lab workspaces export foo
{"data": {}, "metadata": {"id": "/lab/workspaces/foo"}}
$
$ # Exports the workspace named `foo` into a file called `file_name.json`
$ jupyter lab workspaces export foo > file_name.json
$
$ # Imports the workspace file `file_name.json`.
$ jupyter lab workspaces import file_name.json
Saved workspace: <workspaces-directory>/labworkspacesfoo-54d5.jupyterlab-workspace

The ``export`` functionality is as friendly as possible: if a workspace does not
exist, it will still generate an empty workspace for export.

The ``import`` functionality validates the structure of the workspace file and
validates the ``id`` field in the workspace ``metadata`` to make sure its URL is
compatible with either the ``workspaces_url`` configuration or the ``page_url``
configuration to verify that it is a correctly named workspace or it is the
default workspace.


Workspace File Format
---------------------

A workspace file in a JSON file with a specific spec.


There are two top level keys requires, `data`, and `metadata`.

The `metadata` must be a mapping with an `id`
key that has the same value as the ID of the workspace. This should also be the relative URL path to access the workspace,
like `/lab/workspaces/foo`.

The `data` key maps to the initial state of the `IStateDB`. Many plugins look in the State DB for the configuration.
Also any plugins that register with the `ILayoutRestorer` will look up all keys in the State DB
that start with the `namespace` of their tracker before the first `:`. The values of these keys should have a `data`
attribute that maps.

For example, if your workspace looks like this:

.. code-block:: json

{
"data": {
"application-mimedocuments:package.json:JSON": {
"data": { "path": "package.json", "factory": "JSON" }
}
}
}

It will run the `docmanager:open` with the `{ "path": "package.json", "factory": "JSON" }` args, because the `application-mimedocuments` tracker is registered with the `docmanager:open` command, like this:


.. code-block:: typescript

const namespace = 'application-mimedocuments';
const tracker = new WidgetTracker<MimeDocument>({ namespace });
void restorer.restore(tracker, {
command: 'docmanager:open',
args: widget => ({
path: widget.context.path,
factory: Private.factoryNameProperty.get(widget)
}),
name: widget =>
`${widget.context.path}:${Private.factoryNameProperty.get(widget)}`
});

Note the part of the data key after the first `:` (`package.json:JSON`) is dropped and is irrelevant.
113 changes: 113 additions & 0 deletions docs/source/user/workspaces.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
.. Copyright (c) Jupyter Development Team.
.. Distributed under the terms of the Modified BSD License.

.. _workspaces:

Workspaces
==========

A JupyterLab Workspace defines the layout and state of the user interface such as the position of files, notebooks, sidebars, and open/closed state of the panels.
JasonWeill marked this conversation as resolved.
Show resolved Hide resolved

Workspaces can be managed in three ways:
- :ref:`via Graphical User Interface <workspaces-gui>`
- :ref:`via Command Line Interface <workspaces-cli>`
- :ref:`via URL schema and parameters <url-workspaces>`

.. _workspaces-gui:

Managing Workspaces (GUI)
-------------------------

A number of commands is available to manage workspaces from the main menu, sidebar, and command palette:
krassowski marked this conversation as resolved.
Show resolved Hide resolved
- `create-new`, `clone`, `rename`, `reset` and `delete` act on the workspaces stored by on the server in :ref:`the dedicated location <workspaces-directory>`.
- `save` `save as`, `import` and `export` can load and store the workspace to/from the file system (contained within the Jupyter root directory); `save` will save the workspace to the most recently saved file

In the sidebar the current workspace is indicated with check mark (✓). A different workspace can be opened by clicking on the corresponding sidebar item. Opening context menu over the workspace item in the sidebar will present actions available for management of that workspace:

.. image:: ../images/workspaces-sidebar.png
:align: center
:class: jp-screenshot
:alt: The context menu opened over workspaces sidebar

.. _workspaces-cli:

Managing Workspaces (CLI)
-------------------------

JupyterLab provides a command-line interface for workspace ``import`` and
krassowski marked this conversation as resolved.
Show resolved Hide resolved
``export``:

.. code-block:: bash

$ # Exports the default JupyterLab workspace
$ jupyter lab workspaces export
{"data": {}, "metadata": {"id": "/lab"}}
$
$ # Exports the workspaces named `foo`
$ jupyter lab workspaces export foo
{"data": {}, "metadata": {"id": "/lab/workspaces/foo"}}
$
$ # Exports the workspace named `foo` into a file called `file_name.json`
$ jupyter lab workspaces export foo > file_name.json
$
$ # Imports the workspace file `file_name.json`.
$ jupyter lab workspaces import file_name.json
Saved workspace: <workspaces-directory>/labworkspacesfoo-54d5.jupyterlab-workspace

The ``export`` functionality is as friendly as possible: if a workspace does not
exist, it will still generate an empty workspace for export.
krassowski marked this conversation as resolved.
Show resolved Hide resolved

The ``import`` functionality validates the structure of the workspace file and
validates the ``id`` field in the workspace ``metadata`` to make sure its URL is
compatible with either the ``workspaces_url`` configuration or the ``page_url``
configuration to verify that it is a correctly named workspace or it is the
default workspace.
krassowski marked this conversation as resolved.
Show resolved Hide resolved


Workspace File Format
---------------------

A workspace file in a JSON file with a specific spec.


There are two top level keys requires, `data`, and `metadata`.
krassowski marked this conversation as resolved.
Show resolved Hide resolved

The `metadata` must be a mapping with an `id`
key that has the same value as the ID of the workspace. This should also be the relative URL path to access the workspace,
like `/lab/workspaces/foo`. Additionally, `metadata` may contain `created` and `last_modified` fields with date and time of creation and most recent modification, respectively.

The `data` key maps to the initial state of the ``IStateDB``. Many plugins look in the State DB for the configuration.
Also any plugins that register with the ``ILayoutRestorer`` will look up all keys in the State DB
that start with the `namespace` of their tracker before the first ``:``. The values of these keys should have a `data`
attribute that maps.
krassowski marked this conversation as resolved.
Show resolved Hide resolved

For example, if your workspace looks like this:

.. code-block:: json

{
"data": {
"application-mimedocuments:package.json:JSON": {
"data": { "path": "package.json", "factory": "JSON" }
}
}
}

It will run the `docmanager:open` with the ``{ "path": "package.json", "factory": "JSON" }`` args, because the `application-mimedocuments` tracker is registered with the `docmanager:open` command, like this:


.. code-block:: typescript

const namespace = 'application-mimedocuments';
const tracker = new WidgetTracker<MimeDocument>({ namespace });
void restorer.restore(tracker, {
command: 'docmanager:open',
args: widget => ({
path: widget.context.path,
factory: Private.factoryNameProperty.get(widget)
}),
name: widget =>
`${widget.context.path}:${Private.factoryNameProperty.get(widget)}`
});

Note the part of the data key after the first ``:`` (``package.json:JSON``) is dropped and is irrelevant.
krassowski marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion packages/apputils-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"@jupyterlab/apputils": "^4.3.0-alpha.0",
"@jupyterlab/coreutils": "^6.2.0-alpha.0",
"@jupyterlab/docregistry": "^4.2.0-alpha.0",
"@jupyterlab/filebrowser": "^4.2.0-alpha.0",
"@jupyterlab/mainmenu": "^4.2.0-alpha.0",
"@jupyterlab/rendermime-interfaces": "^3.10.0-alpha.0",
"@jupyterlab/services": "^7.2.0-alpha.0",
Expand All @@ -51,6 +50,7 @@
"@jupyterlab/statusbar": "^4.2.0-alpha.0",
"@jupyterlab/translation": "^4.2.0-alpha.0",
"@jupyterlab/ui-components": "^4.2.0-alpha.0",
"@jupyterlab/workspaces": "^4.2.0-alpha.0",
"@lumino/algorithm": "^2.0.1",
"@lumino/commands": "^2.2.0",
"@lumino/coreutils": "^2.1.2",
Expand Down
24 changes: 0 additions & 24 deletions packages/apputils-extension/schema/workspaces.json

This file was deleted.

Loading
Loading