@jupyterlab/apputils-extension 4.2.0-alpha.0 → 4.2.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/workspacesplugin.d.ts +1 -1
- package/lib/workspacesplugin.js +12 -152
- package/lib/workspacesplugin.js.map +1 -1
- package/package.json +14 -14
- package/src/workspacesplugin.ts +17 -187
- package/style/index.css +0 -1
- package/style/index.js +0 -1
- package/style/splash.css +1 -1
- package/schema/workspaces.json +0 -24
package/lib/workspacesplugin.js
CHANGED
|
@@ -1,127 +1,47 @@
|
|
|
1
1
|
// Copyright (c) Jupyter Development Team.
|
|
2
2
|
// Distributed under the terms of the Modified BSD License.
|
|
3
|
-
import { IRouter, JupyterFrontEnd } from '@jupyterlab/application';
|
|
4
|
-
import { Dialog, IWindowResolver, showDialog } from '@jupyterlab/apputils';
|
|
5
|
-
import { URLExt } from '@jupyterlab/coreutils';
|
|
6
3
|
import { ABCWidgetFactory, DocumentWidget } from '@jupyterlab/docregistry';
|
|
7
|
-
import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
|
|
8
4
|
import { IStateDB } from '@jupyterlab/statedb';
|
|
5
|
+
import { IWorkspaceCommands } from '@jupyterlab/workspaces';
|
|
9
6
|
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
10
7
|
import { Widget } from '@lumino/widgets';
|
|
11
|
-
var CommandIDs;
|
|
12
|
-
(function (CommandIDs) {
|
|
13
|
-
CommandIDs.saveWorkspace = 'workspace-ui:save';
|
|
14
|
-
CommandIDs.saveWorkspaceAs = 'workspace-ui:save-as';
|
|
15
|
-
})(CommandIDs || (CommandIDs = {}));
|
|
16
8
|
const WORKSPACE_NAME = 'jupyterlab-workspace';
|
|
17
9
|
const WORKSPACE_EXT = '.' + WORKSPACE_NAME;
|
|
18
10
|
const LAST_SAVE_ID = 'workspace-ui:lastSave';
|
|
19
11
|
const ICON_NAME = 'jp-JupyterIcon';
|
|
20
12
|
/**
|
|
21
|
-
* The workspace MIME renderer
|
|
13
|
+
* The workspace MIME renderer.
|
|
22
14
|
*/
|
|
23
15
|
export const workspacesPlugin = {
|
|
24
16
|
id: '@jupyterlab/apputils-extension:workspaces',
|
|
25
|
-
description: 'Add workspace file type
|
|
17
|
+
description: 'Add workspace file type.',
|
|
26
18
|
autoStart: true,
|
|
27
|
-
requires: [
|
|
28
|
-
|
|
29
|
-
IWindowResolver,
|
|
30
|
-
IStateDB,
|
|
31
|
-
ITranslator,
|
|
32
|
-
JupyterFrontEnd.IPaths
|
|
33
|
-
],
|
|
34
|
-
optional: [IRouter],
|
|
35
|
-
activate: (app, fileBrowser, resolver, state, translator, paths, router) => {
|
|
19
|
+
requires: [IStateDB, IWorkspaceCommands, ITranslator],
|
|
20
|
+
activate: (app, state, commands, translator) => {
|
|
36
21
|
// The workspace factory creates dummy widgets to load a new workspace.
|
|
37
22
|
const factory = new Private.WorkspaceFactory({
|
|
38
23
|
workspaces: app.serviceManager.workspaces,
|
|
39
|
-
router,
|
|
40
24
|
state,
|
|
41
25
|
translator,
|
|
42
|
-
|
|
26
|
+
open: async (id) => {
|
|
27
|
+
await app.commands.execute(commands.open, { workspace: id });
|
|
28
|
+
}
|
|
43
29
|
});
|
|
44
30
|
const trans = translator.load('jupyterlab');
|
|
45
31
|
app.docRegistry.addFileType({
|
|
46
32
|
name: WORKSPACE_NAME,
|
|
47
33
|
contentType: 'file',
|
|
48
34
|
fileFormat: 'text',
|
|
49
|
-
displayName: trans.__('JupyterLab
|
|
35
|
+
displayName: trans.__('JupyterLab Workspace File'),
|
|
50
36
|
extensions: [WORKSPACE_EXT],
|
|
51
37
|
mimeTypes: ['text/json'],
|
|
52
38
|
iconClass: ICON_NAME
|
|
53
39
|
});
|
|
54
40
|
app.docRegistry.addWidgetFactory(factory);
|
|
55
|
-
app.commands.addCommand(CommandIDs.saveWorkspaceAs, {
|
|
56
|
-
label: trans.__('Save Current Workspace As…'),
|
|
57
|
-
execute: async () => {
|
|
58
|
-
const data = app.serviceManager.workspaces.fetch(resolver.name);
|
|
59
|
-
await Private.saveAs(fileBrowser, app.serviceManager.contents, data, state, translator);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
app.commands.addCommand(CommandIDs.saveWorkspace, {
|
|
63
|
-
label: trans.__('Save Current Workspace'),
|
|
64
|
-
execute: async () => {
|
|
65
|
-
const { contents } = app.serviceManager;
|
|
66
|
-
const data = app.serviceManager.workspaces.fetch(resolver.name);
|
|
67
|
-
const lastSave = (await state.fetch(LAST_SAVE_ID));
|
|
68
|
-
if (lastSave === undefined) {
|
|
69
|
-
await Private.saveAs(fileBrowser, contents, data, state, translator);
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
await Private.save(lastSave, contents, data, state);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
41
|
}
|
|
77
42
|
};
|
|
78
43
|
var Private;
|
|
79
44
|
(function (Private) {
|
|
80
|
-
/**
|
|
81
|
-
* Save workspace to a user provided location
|
|
82
|
-
*/
|
|
83
|
-
async function save(userPath, contents, data, state) {
|
|
84
|
-
let name = userPath.split('/').pop();
|
|
85
|
-
// Add extension if not provided or remove extension from name if it was.
|
|
86
|
-
if (name !== undefined && name.includes('.')) {
|
|
87
|
-
name = name.split('.')[0];
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
userPath = userPath + WORKSPACE_EXT;
|
|
91
|
-
}
|
|
92
|
-
// Save last save location, for save button to work
|
|
93
|
-
await state.save(LAST_SAVE_ID, userPath);
|
|
94
|
-
const resolvedData = await data;
|
|
95
|
-
resolvedData.metadata.id = `${name}`;
|
|
96
|
-
await contents.save(userPath, {
|
|
97
|
-
type: 'file',
|
|
98
|
-
format: 'text',
|
|
99
|
-
content: JSON.stringify(resolvedData)
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
Private.save = save;
|
|
103
|
-
/**
|
|
104
|
-
* Ask user for location, and save workspace.
|
|
105
|
-
* Default location is the current directory in the file browser
|
|
106
|
-
*/
|
|
107
|
-
async function saveAs(browser, contents, data, state, translator) {
|
|
108
|
-
var _a;
|
|
109
|
-
translator = translator || nullTranslator;
|
|
110
|
-
const lastSave = await state.fetch(LAST_SAVE_ID);
|
|
111
|
-
let defaultName;
|
|
112
|
-
if (lastSave === undefined) {
|
|
113
|
-
defaultName = 'new-workspace';
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
defaultName = (_a = lastSave.split('/').pop()) === null || _a === void 0 ? void 0 : _a.split('.')[0];
|
|
117
|
-
}
|
|
118
|
-
const defaultPath = browser.model.path + '/' + defaultName + WORKSPACE_EXT;
|
|
119
|
-
const userPath = await getSavePath(defaultPath, translator);
|
|
120
|
-
if (userPath) {
|
|
121
|
-
await save(userPath, contents, data, state);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
Private.saveAs = saveAs;
|
|
125
45
|
/**
|
|
126
46
|
* This widget factory is used to handle double click on workspace
|
|
127
47
|
*/
|
|
@@ -140,14 +60,13 @@ var Private;
|
|
|
140
60
|
defaultFor: [WORKSPACE_NAME],
|
|
141
61
|
readOnly: true
|
|
142
62
|
});
|
|
143
|
-
this._application = options.paths.urls.app;
|
|
144
|
-
this._router = options.router;
|
|
145
63
|
this._state = options.state;
|
|
146
64
|
this._workspaces = options.workspaces;
|
|
65
|
+
this._open = options.open;
|
|
147
66
|
}
|
|
148
67
|
/**
|
|
149
68
|
* Loads the workspace into load, and jump to it
|
|
150
|
-
* @param context This is used
|
|
69
|
+
* @param context This is used to query the workspace content
|
|
151
70
|
*/
|
|
152
71
|
createNewWidget(context) {
|
|
153
72
|
// Save a file's contents as a workspace and navigate to that workspace.
|
|
@@ -161,17 +80,7 @@ var Private;
|
|
|
161
80
|
// Save last save location for the save command.
|
|
162
81
|
await this._state.save(LAST_SAVE_ID, path);
|
|
163
82
|
// Navigate to new workspace.
|
|
164
|
-
|
|
165
|
-
const url = URLExt.join(workspacesBase, id);
|
|
166
|
-
if (!url.startsWith(workspacesBase)) {
|
|
167
|
-
throw new Error('Can only be used for workspaces');
|
|
168
|
-
}
|
|
169
|
-
if (this._router) {
|
|
170
|
-
this._router.navigate(url, { hard: true });
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
document.location.href = url;
|
|
174
|
-
}
|
|
83
|
+
await this._open(id);
|
|
175
84
|
});
|
|
176
85
|
return dummyWidget(context);
|
|
177
86
|
}
|
|
@@ -187,54 +96,5 @@ var Private;
|
|
|
187
96
|
widget.content.dispose();
|
|
188
97
|
return widget;
|
|
189
98
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Ask user for a path to save to.
|
|
192
|
-
* @param defaultPath Path already present when the dialog is shown
|
|
193
|
-
*/
|
|
194
|
-
async function getSavePath(defaultPath, translator) {
|
|
195
|
-
translator = translator || nullTranslator;
|
|
196
|
-
const trans = translator.load('jupyterlab');
|
|
197
|
-
const saveBtn = Dialog.okButton({
|
|
198
|
-
label: trans.__('Save'),
|
|
199
|
-
ariaLabel: trans.__('Save Current Workspace')
|
|
200
|
-
});
|
|
201
|
-
const result = await showDialog({
|
|
202
|
-
title: trans.__('Save Current Workspace As…'),
|
|
203
|
-
body: new SaveWidget(defaultPath),
|
|
204
|
-
buttons: [Dialog.cancelButton(), saveBtn]
|
|
205
|
-
});
|
|
206
|
-
if (result.button.label === trans.__('Save')) {
|
|
207
|
-
return result.value;
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* A widget that gets a file path from a user.
|
|
215
|
-
*/
|
|
216
|
-
class SaveWidget extends Widget {
|
|
217
|
-
/**
|
|
218
|
-
* Gets a modal node for getting save location. Will have a default to the current opened directory
|
|
219
|
-
* @param path Default location
|
|
220
|
-
*/
|
|
221
|
-
constructor(path) {
|
|
222
|
-
super({ node: createSaveNode(path) });
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Gets the save path entered by the user
|
|
226
|
-
*/
|
|
227
|
-
getValue() {
|
|
228
|
-
return this.node.value;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Create the node for a save widget.
|
|
233
|
-
*/
|
|
234
|
-
function createSaveNode(path) {
|
|
235
|
-
const input = document.createElement('input');
|
|
236
|
-
input.value = path;
|
|
237
|
-
return input;
|
|
238
|
-
}
|
|
239
99
|
})(Private || (Private = {}));
|
|
240
100
|
//# sourceMappingURL=workspacesplugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspacesplugin.js","sourceRoot":"","sources":["../src/workspacesplugin.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,2DAA2D;
|
|
1
|
+
{"version":3,"file":"workspacesplugin.js","sourceRoot":"","sources":["../src/workspacesplugin.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlab/apputils-extension",
|
|
3
|
-
"version": "4.2.0-alpha.
|
|
3
|
+
"version": "4.2.0-alpha.2",
|
|
4
4
|
"description": "JupyterLab - Application Utilities Extension",
|
|
5
5
|
"homepage": "https://github.com/jupyterlab/jupyterlab",
|
|
6
6
|
"bugs": {
|
|
@@ -38,19 +38,19 @@
|
|
|
38
38
|
"watch": "tsc -b --watch"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@jupyterlab/application": "^4.2.0-alpha.
|
|
42
|
-
"@jupyterlab/apputils": "^4.3.0-alpha.
|
|
43
|
-
"@jupyterlab/coreutils": "^6.2.0-alpha.
|
|
44
|
-
"@jupyterlab/docregistry": "^4.2.0-alpha.
|
|
45
|
-
"@jupyterlab/
|
|
46
|
-
"@jupyterlab/
|
|
47
|
-
"@jupyterlab/
|
|
48
|
-
"@jupyterlab/
|
|
49
|
-
"@jupyterlab/
|
|
50
|
-
"@jupyterlab/
|
|
51
|
-
"@jupyterlab/
|
|
52
|
-
"@jupyterlab/
|
|
53
|
-
"@jupyterlab/
|
|
41
|
+
"@jupyterlab/application": "^4.2.0-alpha.2",
|
|
42
|
+
"@jupyterlab/apputils": "^4.3.0-alpha.2",
|
|
43
|
+
"@jupyterlab/coreutils": "^6.2.0-alpha.2",
|
|
44
|
+
"@jupyterlab/docregistry": "^4.2.0-alpha.2",
|
|
45
|
+
"@jupyterlab/mainmenu": "^4.2.0-alpha.2",
|
|
46
|
+
"@jupyterlab/rendermime-interfaces": "^3.10.0-alpha.2",
|
|
47
|
+
"@jupyterlab/services": "^7.2.0-alpha.2",
|
|
48
|
+
"@jupyterlab/settingregistry": "^4.2.0-alpha.2",
|
|
49
|
+
"@jupyterlab/statedb": "^4.2.0-alpha.2",
|
|
50
|
+
"@jupyterlab/statusbar": "^4.2.0-alpha.2",
|
|
51
|
+
"@jupyterlab/translation": "^4.2.0-alpha.2",
|
|
52
|
+
"@jupyterlab/ui-components": "^4.2.0-alpha.2",
|
|
53
|
+
"@jupyterlab/workspaces": "^4.2.0-alpha.2",
|
|
54
54
|
"@lumino/algorithm": "^2.0.1",
|
|
55
55
|
"@lumino/commands": "^2.2.0",
|
|
56
56
|
"@lumino/coreutils": "^2.1.2",
|
package/src/workspacesplugin.ts
CHANGED
|
@@ -2,66 +2,48 @@
|
|
|
2
2
|
// Distributed under the terms of the Modified BSD License.
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
IRouter,
|
|
6
5
|
JupyterFrontEnd,
|
|
7
6
|
JupyterFrontEndPlugin
|
|
8
7
|
} from '@jupyterlab/application';
|
|
9
|
-
import { Dialog, IWindowResolver, showDialog } from '@jupyterlab/apputils';
|
|
10
|
-
import { URLExt } from '@jupyterlab/coreutils';
|
|
11
8
|
import {
|
|
12
9
|
ABCWidgetFactory,
|
|
13
10
|
DocumentRegistry,
|
|
14
11
|
DocumentWidget,
|
|
15
12
|
IDocumentWidget
|
|
16
13
|
} from '@jupyterlab/docregistry';
|
|
17
|
-
import {
|
|
18
|
-
import { Contents, Workspace, WorkspaceManager } from '@jupyterlab/services';
|
|
14
|
+
import { Workspace, WorkspaceManager } from '@jupyterlab/services';
|
|
19
15
|
import { IStateDB } from '@jupyterlab/statedb';
|
|
16
|
+
import { IWorkspaceCommands } from '@jupyterlab/workspaces';
|
|
20
17
|
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
21
18
|
import { Widget } from '@lumino/widgets';
|
|
22
19
|
|
|
23
|
-
namespace CommandIDs {
|
|
24
|
-
export const saveWorkspace = 'workspace-ui:save';
|
|
25
|
-
|
|
26
|
-
export const saveWorkspaceAs = 'workspace-ui:save-as';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
20
|
const WORKSPACE_NAME = 'jupyterlab-workspace';
|
|
30
21
|
const WORKSPACE_EXT = '.' + WORKSPACE_NAME;
|
|
31
22
|
const LAST_SAVE_ID = 'workspace-ui:lastSave';
|
|
32
23
|
const ICON_NAME = 'jp-JupyterIcon';
|
|
33
24
|
|
|
34
25
|
/**
|
|
35
|
-
* The workspace MIME renderer
|
|
26
|
+
* The workspace MIME renderer.
|
|
36
27
|
*/
|
|
37
28
|
export const workspacesPlugin: JupyterFrontEndPlugin<void> = {
|
|
38
29
|
id: '@jupyterlab/apputils-extension:workspaces',
|
|
39
|
-
description: 'Add workspace file type
|
|
30
|
+
description: 'Add workspace file type.',
|
|
40
31
|
autoStart: true,
|
|
41
|
-
requires: [
|
|
42
|
-
IDefaultFileBrowser,
|
|
43
|
-
IWindowResolver,
|
|
44
|
-
IStateDB,
|
|
45
|
-
ITranslator,
|
|
46
|
-
JupyterFrontEnd.IPaths
|
|
47
|
-
],
|
|
48
|
-
optional: [IRouter],
|
|
32
|
+
requires: [IStateDB, IWorkspaceCommands, ITranslator],
|
|
49
33
|
activate: (
|
|
50
34
|
app: JupyterFrontEnd,
|
|
51
|
-
fileBrowser: IDefaultFileBrowser,
|
|
52
|
-
resolver: IWindowResolver,
|
|
53
35
|
state: IStateDB,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
router: IRouter | null
|
|
36
|
+
commands: IWorkspaceCommands,
|
|
37
|
+
translator: ITranslator
|
|
57
38
|
): void => {
|
|
58
39
|
// The workspace factory creates dummy widgets to load a new workspace.
|
|
59
40
|
const factory = new Private.WorkspaceFactory({
|
|
60
41
|
workspaces: app.serviceManager.workspaces,
|
|
61
|
-
router,
|
|
62
42
|
state,
|
|
63
43
|
translator,
|
|
64
|
-
|
|
44
|
+
open: async (id: string) => {
|
|
45
|
+
await app.commands.execute(commands.open, { workspace: id });
|
|
46
|
+
}
|
|
65
47
|
});
|
|
66
48
|
const trans = translator.load('jupyterlab');
|
|
67
49
|
|
|
@@ -69,102 +51,16 @@ export const workspacesPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
69
51
|
name: WORKSPACE_NAME,
|
|
70
52
|
contentType: 'file',
|
|
71
53
|
fileFormat: 'text',
|
|
72
|
-
displayName: trans.__('JupyterLab
|
|
54
|
+
displayName: trans.__('JupyterLab Workspace File'),
|
|
73
55
|
extensions: [WORKSPACE_EXT],
|
|
74
56
|
mimeTypes: ['text/json'],
|
|
75
57
|
iconClass: ICON_NAME
|
|
76
58
|
});
|
|
77
59
|
app.docRegistry.addWidgetFactory(factory);
|
|
78
|
-
app.commands.addCommand(CommandIDs.saveWorkspaceAs, {
|
|
79
|
-
label: trans.__('Save Current Workspace As…'),
|
|
80
|
-
execute: async () => {
|
|
81
|
-
const data = app.serviceManager.workspaces.fetch(resolver.name);
|
|
82
|
-
await Private.saveAs(
|
|
83
|
-
fileBrowser,
|
|
84
|
-
app.serviceManager.contents,
|
|
85
|
-
data,
|
|
86
|
-
state,
|
|
87
|
-
translator
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
app.commands.addCommand(CommandIDs.saveWorkspace, {
|
|
93
|
-
label: trans.__('Save Current Workspace'),
|
|
94
|
-
execute: async () => {
|
|
95
|
-
const { contents } = app.serviceManager;
|
|
96
|
-
const data = app.serviceManager.workspaces.fetch(resolver.name);
|
|
97
|
-
const lastSave = (await state.fetch(LAST_SAVE_ID)) as string;
|
|
98
|
-
if (lastSave === undefined) {
|
|
99
|
-
await Private.saveAs(fileBrowser, contents, data, state, translator);
|
|
100
|
-
} else {
|
|
101
|
-
await Private.save(lastSave, contents, data, state);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
60
|
}
|
|
106
61
|
};
|
|
107
62
|
|
|
108
63
|
namespace Private {
|
|
109
|
-
/**
|
|
110
|
-
* Save workspace to a user provided location
|
|
111
|
-
*/
|
|
112
|
-
export async function save(
|
|
113
|
-
userPath: string,
|
|
114
|
-
contents: Contents.IManager,
|
|
115
|
-
data: Promise<Workspace.IWorkspace>,
|
|
116
|
-
state: IStateDB
|
|
117
|
-
): Promise<void> {
|
|
118
|
-
let name = userPath.split('/').pop();
|
|
119
|
-
|
|
120
|
-
// Add extension if not provided or remove extension from name if it was.
|
|
121
|
-
if (name !== undefined && name.includes('.')) {
|
|
122
|
-
name = name.split('.')[0];
|
|
123
|
-
} else {
|
|
124
|
-
userPath = userPath + WORKSPACE_EXT;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Save last save location, for save button to work
|
|
128
|
-
await state.save(LAST_SAVE_ID, userPath);
|
|
129
|
-
|
|
130
|
-
const resolvedData = await data;
|
|
131
|
-
resolvedData.metadata.id = `${name}`;
|
|
132
|
-
await contents.save(userPath, {
|
|
133
|
-
type: 'file',
|
|
134
|
-
format: 'text',
|
|
135
|
-
content: JSON.stringify(resolvedData)
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Ask user for location, and save workspace.
|
|
141
|
-
* Default location is the current directory in the file browser
|
|
142
|
-
*/
|
|
143
|
-
export async function saveAs(
|
|
144
|
-
browser: IDefaultFileBrowser,
|
|
145
|
-
contents: Contents.IManager,
|
|
146
|
-
data: Promise<Workspace.IWorkspace>,
|
|
147
|
-
state: IStateDB,
|
|
148
|
-
translator?: ITranslator
|
|
149
|
-
): Promise<void> {
|
|
150
|
-
translator = translator || nullTranslator;
|
|
151
|
-
const lastSave = await state.fetch(LAST_SAVE_ID);
|
|
152
|
-
|
|
153
|
-
let defaultName;
|
|
154
|
-
if (lastSave === undefined) {
|
|
155
|
-
defaultName = 'new-workspace';
|
|
156
|
-
} else {
|
|
157
|
-
defaultName = (lastSave as string).split('/').pop()?.split('.')[0];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const defaultPath = browser.model.path + '/' + defaultName + WORKSPACE_EXT;
|
|
161
|
-
const userPath = await getSavePath(defaultPath, translator);
|
|
162
|
-
|
|
163
|
-
if (userPath) {
|
|
164
|
-
await save(userPath, contents, data, state);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
64
|
/**
|
|
169
65
|
* This widget factory is used to handle double click on workspace
|
|
170
66
|
*/
|
|
@@ -183,15 +79,14 @@ namespace Private {
|
|
|
183
79
|
defaultFor: [WORKSPACE_NAME],
|
|
184
80
|
readOnly: true
|
|
185
81
|
});
|
|
186
|
-
this._application = options.paths.urls.app;
|
|
187
|
-
this._router = options.router;
|
|
188
82
|
this._state = options.state;
|
|
189
83
|
this._workspaces = options.workspaces;
|
|
84
|
+
this._open = options.open;
|
|
190
85
|
}
|
|
191
86
|
|
|
192
87
|
/**
|
|
193
88
|
* Loads the workspace into load, and jump to it
|
|
194
|
-
* @param context This is used
|
|
89
|
+
* @param context This is used to query the workspace content
|
|
195
90
|
*/
|
|
196
91
|
protected createNewWidget(
|
|
197
92
|
context: DocumentRegistry.Context
|
|
@@ -201,6 +96,7 @@ namespace Private {
|
|
|
201
96
|
const file = context.model;
|
|
202
97
|
const workspace = file.toJSON() as unknown as Workspace.IWorkspace;
|
|
203
98
|
const path = context.path;
|
|
99
|
+
|
|
204
100
|
const id = workspace.metadata.id;
|
|
205
101
|
|
|
206
102
|
// Save the file contents as a workspace.
|
|
@@ -210,22 +106,12 @@ namespace Private {
|
|
|
210
106
|
await this._state.save(LAST_SAVE_ID, path);
|
|
211
107
|
|
|
212
108
|
// Navigate to new workspace.
|
|
213
|
-
|
|
214
|
-
const url = URLExt.join(workspacesBase, id);
|
|
215
|
-
if (!url.startsWith(workspacesBase)) {
|
|
216
|
-
throw new Error('Can only be used for workspaces');
|
|
217
|
-
}
|
|
218
|
-
if (this._router) {
|
|
219
|
-
this._router.navigate(url, { hard: true });
|
|
220
|
-
} else {
|
|
221
|
-
document.location.href = url;
|
|
222
|
-
}
|
|
109
|
+
await this._open(id);
|
|
223
110
|
});
|
|
224
111
|
return dummyWidget(context);
|
|
225
112
|
}
|
|
226
113
|
|
|
227
|
-
private
|
|
228
|
-
private _router: IRouter | null;
|
|
114
|
+
private _open: (id: string) => Promise<void>;
|
|
229
115
|
private _state: IStateDB;
|
|
230
116
|
private _workspaces: WorkspaceManager;
|
|
231
117
|
}
|
|
@@ -238,11 +124,10 @@ namespace Private {
|
|
|
238
124
|
* Instantiation options for a `WorkspaceFactory`
|
|
239
125
|
*/
|
|
240
126
|
export interface IOptions {
|
|
241
|
-
paths: JupyterFrontEnd.IPaths;
|
|
242
|
-
router: IRouter | null;
|
|
243
127
|
state: IStateDB;
|
|
244
128
|
translator: ITranslator;
|
|
245
129
|
workspaces: WorkspaceManager;
|
|
130
|
+
open: (id: string) => Promise<void>;
|
|
246
131
|
}
|
|
247
132
|
}
|
|
248
133
|
|
|
@@ -256,59 +141,4 @@ namespace Private {
|
|
|
256
141
|
widget.content.dispose();
|
|
257
142
|
return widget;
|
|
258
143
|
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Ask user for a path to save to.
|
|
262
|
-
* @param defaultPath Path already present when the dialog is shown
|
|
263
|
-
*/
|
|
264
|
-
async function getSavePath(
|
|
265
|
-
defaultPath: string,
|
|
266
|
-
translator?: ITranslator
|
|
267
|
-
): Promise<string | null> {
|
|
268
|
-
translator = translator || nullTranslator;
|
|
269
|
-
const trans = translator.load('jupyterlab');
|
|
270
|
-
const saveBtn = Dialog.okButton({
|
|
271
|
-
label: trans.__('Save'),
|
|
272
|
-
ariaLabel: trans.__('Save Current Workspace')
|
|
273
|
-
});
|
|
274
|
-
const result = await showDialog({
|
|
275
|
-
title: trans.__('Save Current Workspace As…'),
|
|
276
|
-
body: new SaveWidget(defaultPath),
|
|
277
|
-
buttons: [Dialog.cancelButton(), saveBtn]
|
|
278
|
-
});
|
|
279
|
-
if (result.button.label === trans.__('Save')) {
|
|
280
|
-
return result.value;
|
|
281
|
-
} else {
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* A widget that gets a file path from a user.
|
|
288
|
-
*/
|
|
289
|
-
class SaveWidget extends Widget {
|
|
290
|
-
/**
|
|
291
|
-
* Gets a modal node for getting save location. Will have a default to the current opened directory
|
|
292
|
-
* @param path Default location
|
|
293
|
-
*/
|
|
294
|
-
constructor(path: string) {
|
|
295
|
-
super({ node: createSaveNode(path) });
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Gets the save path entered by the user
|
|
300
|
-
*/
|
|
301
|
-
getValue(): string {
|
|
302
|
-
return (this.node as HTMLInputElement).value;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Create the node for a save widget.
|
|
308
|
-
*/
|
|
309
|
-
function createSaveNode(path: string): HTMLElement {
|
|
310
|
-
const input = document.createElement('input');
|
|
311
|
-
input.value = path;
|
|
312
|
-
return input;
|
|
313
|
-
}
|
|
314
144
|
}
|
package/style/index.css
CHANGED
|
@@ -10,6 +10,5 @@
|
|
|
10
10
|
@import url('~@jupyterlab/apputils/style/index.css');
|
|
11
11
|
@import url('~@jupyterlab/docregistry/style/index.css');
|
|
12
12
|
@import url('~@jupyterlab/application/style/index.css');
|
|
13
|
-
@import url('~@jupyterlab/filebrowser/style/index.css');
|
|
14
13
|
@import url('~@jupyterlab/mainmenu/style/index.css');
|
|
15
14
|
@import url('./base.css');
|
package/style/index.js
CHANGED
|
@@ -10,7 +10,6 @@ import '@jupyterlab/statusbar/style/index.js';
|
|
|
10
10
|
import '@jupyterlab/apputils/style/index.js';
|
|
11
11
|
import '@jupyterlab/docregistry/style/index.js';
|
|
12
12
|
import '@jupyterlab/application/style/index.js';
|
|
13
|
-
import '@jupyterlab/filebrowser/style/index.js';
|
|
14
13
|
import '@jupyterlab/mainmenu/style/index.js';
|
|
15
14
|
|
|
16
15
|
import './base.css';
|
package/style/splash.css
CHANGED
package/schema/workspaces.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"title": "Workspaces",
|
|
3
|
-
"description": "Workspaces settings.",
|
|
4
|
-
"jupyter.lab.menus": {
|
|
5
|
-
"main": [
|
|
6
|
-
{
|
|
7
|
-
"id": "jp-mainmenu-file",
|
|
8
|
-
"items": [
|
|
9
|
-
{
|
|
10
|
-
"command": "workspace-ui:save-as",
|
|
11
|
-
"rank": 40
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"command": "workspace-ui:save",
|
|
15
|
-
"rank": 40
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
"additionalProperties": false,
|
|
22
|
-
"properties": {},
|
|
23
|
-
"type": "object"
|
|
24
|
-
}
|