@jupytergis/jupytergis-lab 0.3.0 → 0.4.0
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/index.js +10 -5
- package/lib/notebookrenderer.d.ts +18 -6
- package/lib/notebookrenderer.js +100 -20
- package/package.json +9 -9
- package/style/base.css +16 -1
package/lib/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { IMainMenu } from '@jupyterlab/mainmenu';
|
|
|
6
6
|
import { IStateDB } from '@jupyterlab/statedb';
|
|
7
7
|
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
8
8
|
import { Menu } from '@lumino/widgets';
|
|
9
|
-
import {
|
|
9
|
+
import { notebookRendererPlugin } from './notebookrenderer';
|
|
10
10
|
const NAME_SPACE = 'jupytergis';
|
|
11
11
|
const plugin = {
|
|
12
12
|
id: 'jupytergis:lab:main-menu',
|
|
@@ -157,6 +157,10 @@ const plugin = {
|
|
|
157
157
|
command: CommandIDs.newImageLayer,
|
|
158
158
|
args: { from: 'contextMenu' }
|
|
159
159
|
});
|
|
160
|
+
newLayerSubMenu.addItem({
|
|
161
|
+
command: CommandIDs.newHeatmapLayer,
|
|
162
|
+
args: { from: 'contextMenu' }
|
|
163
|
+
});
|
|
160
164
|
if (mainMenu) {
|
|
161
165
|
populateMenus(mainMenu, isEnabled);
|
|
162
166
|
}
|
|
@@ -177,7 +181,8 @@ const controlPanel = {
|
|
|
177
181
|
const leftControlPanel = new LeftPanelWidget({
|
|
178
182
|
model: controlModel,
|
|
179
183
|
tracker,
|
|
180
|
-
state
|
|
184
|
+
state,
|
|
185
|
+
commands: app.commands
|
|
181
186
|
});
|
|
182
187
|
leftControlPanel.id = 'jupytergis::leftControlPanel';
|
|
183
188
|
leftControlPanel.title.caption = 'JupyterGIS Control Panel';
|
|
@@ -218,10 +223,10 @@ function populateMenus(mainMenu, isEnabled) {
|
|
|
218
223
|
*/
|
|
219
224
|
function buildGroupsMenu(contextMenu, tracker) {
|
|
220
225
|
var _a, _b, _c, _d;
|
|
221
|
-
if (!((_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.
|
|
226
|
+
if (!((_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model)) {
|
|
222
227
|
return;
|
|
223
228
|
}
|
|
224
|
-
const model = (_b = tracker.currentWidget) === null || _b === void 0 ? void 0 : _b.
|
|
229
|
+
const model = (_b = tracker.currentWidget) === null || _b === void 0 ? void 0 : _b.model;
|
|
225
230
|
const submenu = (_d = (_c = contextMenu.menu.items.find(item => {
|
|
226
231
|
var _a;
|
|
227
232
|
return item.type === 'submenu' &&
|
|
@@ -267,4 +272,4 @@ function buildGroupsMenu(contextMenu, tracker) {
|
|
|
267
272
|
command: CommandIDs.moveLayerToNewGroup
|
|
268
273
|
});
|
|
269
274
|
}
|
|
270
|
-
export default [plugin, controlPanel,
|
|
275
|
+
export default [plugin, controlPanel, notebookRendererPlugin];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JupyterGISOutputWidget, JupyterGISTracker } from '@jupytergis/base';
|
|
2
|
+
import { IJGISExternalCommandRegistry, JupyterGISModel } from '@jupytergis/schema';
|
|
2
3
|
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
4
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
3
5
|
import { Panel } from '@lumino/widgets';
|
|
4
6
|
import { JupyterYModel } from 'yjs-widgets';
|
|
5
7
|
export interface ICommMetadata {
|
|
@@ -14,10 +16,20 @@ export declare class YJupyterGISModel extends JupyterYModel {
|
|
|
14
16
|
jupyterGISModel: JupyterGISModel;
|
|
15
17
|
}
|
|
16
18
|
export declare class YJupyterGISLuminoWidget extends Panel {
|
|
17
|
-
constructor(options:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
constructor(options: IOptions);
|
|
20
|
+
get jgisWidget(): JupyterGISOutputWidget;
|
|
21
|
+
/**
|
|
22
|
+
* Build the widget and add it to the panel.
|
|
23
|
+
* @param options
|
|
24
|
+
*/
|
|
25
|
+
private _buildWidget;
|
|
21
26
|
private _jgisWidget;
|
|
22
27
|
}
|
|
23
|
-
|
|
28
|
+
interface IOptions {
|
|
29
|
+
commands: CommandRegistry;
|
|
30
|
+
model: JupyterGISModel;
|
|
31
|
+
externalCommands?: IJGISExternalCommandRegistry;
|
|
32
|
+
tracker?: JupyterGISTracker;
|
|
33
|
+
}
|
|
34
|
+
export declare const notebookRendererPlugin: JupyterFrontEndPlugin<void>;
|
|
35
|
+
export {};
|
package/lib/notebookrenderer.js
CHANGED
|
@@ -1,44 +1,114 @@
|
|
|
1
1
|
import { ICollaborativeDrive } from '@jupyter/collaborative-drive';
|
|
2
|
-
import { JupyterGISPanel } from '@jupytergis/base';
|
|
3
|
-
import { JupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import { JupyterGISOutputWidget, JupyterGISPanel, ToolbarWidget } from '@jupytergis/base';
|
|
3
|
+
import { IJGISExternalCommandRegistryToken, IJupyterGISDocTracker, JupyterGISModel } from '@jupytergis/schema';
|
|
4
|
+
import { showErrorMessage } from '@jupyterlab/apputils';
|
|
5
|
+
import { ConsolePanel } from '@jupyterlab/console';
|
|
6
|
+
import { PathExt } from '@jupyterlab/coreutils';
|
|
7
|
+
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
4
8
|
import { MessageLoop } from '@lumino/messaging';
|
|
5
9
|
import { Panel, Widget } from '@lumino/widgets';
|
|
6
|
-
import { IJupyterYWidgetManager, JupyterYModel } from 'yjs-widgets';
|
|
10
|
+
import { IJupyterYWidgetManager, JupyterYDoc, JupyterYModel } from 'yjs-widgets';
|
|
7
11
|
export const CLASS_NAME = 'jupytergis-notebook-widget';
|
|
8
12
|
export class YJupyterGISModel extends JupyterYModel {
|
|
9
13
|
}
|
|
10
14
|
export class YJupyterGISLuminoWidget extends Panel {
|
|
11
15
|
constructor(options) {
|
|
12
16
|
super();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Build the widget and add it to the panel.
|
|
19
|
+
* @param options
|
|
20
|
+
*/
|
|
21
|
+
this._buildWidget = (options) => {
|
|
22
|
+
const { commands, model, externalCommands, tracker } = options;
|
|
23
|
+
const content = new JupyterGISPanel({ model, commandRegistry: commands });
|
|
24
|
+
let toolbar = undefined;
|
|
25
|
+
if (model.filePath) {
|
|
26
|
+
toolbar = new ToolbarWidget({
|
|
27
|
+
commands,
|
|
28
|
+
model,
|
|
29
|
+
externalCommands: (externalCommands === null || externalCommands === void 0 ? void 0 : externalCommands.getCommands()) || []
|
|
30
|
+
});
|
|
16
31
|
}
|
|
32
|
+
this._jgisWidget = new JupyterGISOutputWidget({
|
|
33
|
+
model,
|
|
34
|
+
content,
|
|
35
|
+
toolbar
|
|
36
|
+
});
|
|
37
|
+
this.addWidget(this._jgisWidget);
|
|
38
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.add(this._jgisWidget);
|
|
17
39
|
};
|
|
40
|
+
const { model } = options;
|
|
18
41
|
this.addClass(CLASS_NAME);
|
|
19
|
-
this.
|
|
20
|
-
|
|
42
|
+
this._buildWidget(options);
|
|
43
|
+
// If the filepath was not set when building the widget, the toolbar is not built.
|
|
44
|
+
// The widget has to be built again to include the toolbar.
|
|
45
|
+
const onchange = (_, args) => {
|
|
46
|
+
if (args.stateChange) {
|
|
47
|
+
args.stateChange.forEach((change) => {
|
|
48
|
+
var _a;
|
|
49
|
+
if (change.name === 'path') {
|
|
50
|
+
(_a = this.layout) === null || _a === void 0 ? void 0 : _a.removeWidget(this._jgisWidget);
|
|
51
|
+
this._jgisWidget.dispose();
|
|
52
|
+
this._buildWidget(options);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
model.sharedModel.changed.connect(onchange);
|
|
58
|
+
}
|
|
59
|
+
get jgisWidget() {
|
|
60
|
+
return this._jgisWidget;
|
|
21
61
|
}
|
|
22
62
|
}
|
|
23
|
-
export const
|
|
63
|
+
export const notebookRendererPlugin = {
|
|
24
64
|
id: 'jupytergis:yjswidget-plugin',
|
|
25
65
|
autoStart: true,
|
|
26
|
-
optional: [
|
|
27
|
-
|
|
66
|
+
optional: [
|
|
67
|
+
IJGISExternalCommandRegistryToken,
|
|
68
|
+
IJupyterGISDocTracker,
|
|
69
|
+
IJupyterYWidgetManager,
|
|
70
|
+
ICollaborativeDrive
|
|
71
|
+
],
|
|
72
|
+
activate: (app, externalCommandRegistry, jgisTracker, yWidgetManager, drive) => {
|
|
28
73
|
if (!yWidgetManager) {
|
|
29
74
|
console.error('Missing IJupyterYWidgetManager token!');
|
|
30
75
|
return;
|
|
31
76
|
}
|
|
32
|
-
if (!drive) {
|
|
33
|
-
console.error('Cannot setup JupyterGIS Python API without a collaborative drive');
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
77
|
class YJupyterGISModelFactory extends YJupyterGISModel {
|
|
37
|
-
|
|
78
|
+
async initialize(commMetadata) {
|
|
38
79
|
const { path, format, contentType } = commMetadata;
|
|
39
80
|
const fileFormat = format;
|
|
81
|
+
if (!drive) {
|
|
82
|
+
showErrorMessage('Error using the JupyterGIS Python API', 'You cannot use the JupyterGIS Python API without a collaborative drive. You need to install a package providing collaboration features (e.g. jupyter-collaboration).');
|
|
83
|
+
throw new Error('Failed to create the YDoc without a collaborative drive');
|
|
84
|
+
}
|
|
85
|
+
// The path of the project is relative to the path of the notebook
|
|
86
|
+
let currentWidgetPath = '';
|
|
87
|
+
const currentWidget = app.shell.currentWidget;
|
|
88
|
+
if (currentWidget instanceof NotebookPanel ||
|
|
89
|
+
currentWidget instanceof ConsolePanel) {
|
|
90
|
+
currentWidgetPath = currentWidget.sessionContext.path;
|
|
91
|
+
}
|
|
92
|
+
let localPath = '';
|
|
93
|
+
if (path) {
|
|
94
|
+
localPath = PathExt.join(PathExt.dirname(currentWidgetPath), path);
|
|
95
|
+
// If the file does not exist yet, create it
|
|
96
|
+
try {
|
|
97
|
+
await app.serviceManager.contents.get(localPath);
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
await app.serviceManager.contents.save(localPath, {
|
|
101
|
+
content: btoa('{}'),
|
|
102
|
+
format: 'base64'
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// If the user did not provide a path, do not create
|
|
108
|
+
localPath = PathExt.join(PathExt.dirname(currentWidgetPath), 'unsaved_project');
|
|
109
|
+
}
|
|
40
110
|
const sharedModel = drive.sharedModelFactory.createNew({
|
|
41
|
-
path,
|
|
111
|
+
path: localPath,
|
|
42
112
|
format: fileFormat,
|
|
43
113
|
contentType,
|
|
44
114
|
collaborative: true
|
|
@@ -46,7 +116,10 @@ export const notebookRenderePlugin = {
|
|
|
46
116
|
this.jupyterGISModel = new JupyterGISModel({
|
|
47
117
|
sharedModel: sharedModel
|
|
48
118
|
});
|
|
49
|
-
|
|
119
|
+
this.jupyterGISModel.contentsManager = app.serviceManager.contents;
|
|
120
|
+
this.jupyterGISModel.filePath = localPath;
|
|
121
|
+
this.ydoc = this.jupyterGISModel.sharedModel.ydoc;
|
|
122
|
+
this.sharedModel = new JupyterYDoc(commMetadata, this.ydoc);
|
|
50
123
|
}
|
|
51
124
|
}
|
|
52
125
|
class YJupyterGISWidget {
|
|
@@ -54,13 +127,20 @@ export const notebookRenderePlugin = {
|
|
|
54
127
|
this.yModel = yModel;
|
|
55
128
|
this.node = node;
|
|
56
129
|
const widget = new YJupyterGISLuminoWidget({
|
|
57
|
-
|
|
130
|
+
commands: app.commands,
|
|
131
|
+
model: yModel.jupyterGISModel,
|
|
132
|
+
externalCommands: externalCommandRegistry,
|
|
133
|
+
tracker: jgisTracker
|
|
58
134
|
});
|
|
59
|
-
|
|
135
|
+
this._jgisWidget = widget.jgisWidget;
|
|
60
136
|
MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
|
|
61
137
|
node.appendChild(widget.node);
|
|
62
138
|
MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
|
|
63
139
|
}
|
|
140
|
+
dispose() {
|
|
141
|
+
// Dispose of the widget.
|
|
142
|
+
this._jgisWidget.dispose();
|
|
143
|
+
}
|
|
64
144
|
}
|
|
65
145
|
yWidgetManager.registerWidget('@jupytergis:widget', YJupyterGISModelFactory, YJupyterGISWidget);
|
|
66
146
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupytergis/jupytergis-lab",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "JupyterGIS Lab extension.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -53,23 +53,23 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@jupyter/collaborative-drive": "^3.0.0",
|
|
56
|
-
"@jupytergis/base": "^0.
|
|
57
|
-
"@jupytergis/
|
|
58
|
-
"@jupytergis/schema": "^0.3.0",
|
|
56
|
+
"@jupytergis/base": "^0.4.0",
|
|
57
|
+
"@jupytergis/schema": "^0.4.0",
|
|
59
58
|
"@jupyterlab/application": "^4.3.0",
|
|
60
59
|
"@jupyterlab/apputils": "^4.3.0",
|
|
60
|
+
"@jupyterlab/completer": "^4.3.0",
|
|
61
|
+
"@jupyterlab/console": "^4.3.0",
|
|
61
62
|
"@jupyterlab/coreutils": "^6.3.0",
|
|
62
|
-
"@jupyterlab/docregistry": "^4.3.0",
|
|
63
|
-
"@jupyterlab/filebrowser": "^4.3.0",
|
|
64
|
-
"@jupyterlab/launcher": "^4.3.0",
|
|
65
63
|
"@jupyterlab/mainmenu": "^4.3.0",
|
|
64
|
+
"@jupyterlab/notebook": "^4.3.0",
|
|
66
65
|
"@jupyterlab/services": "^7.3.0",
|
|
66
|
+
"@jupyterlab/statedb": "^4.3.0",
|
|
67
67
|
"@jupyterlab/translation": "^4.3.0",
|
|
68
|
-
"@
|
|
68
|
+
"@lumino/commands": "^2.0.0",
|
|
69
69
|
"@lumino/messaging": "^2.0.0",
|
|
70
70
|
"@lumino/widgets": "^2.0.0",
|
|
71
71
|
"react": "^18.0.1",
|
|
72
|
-
"yjs-widgets": "^0.
|
|
72
|
+
"yjs-widgets": "^0.4"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@jupyterlab/builder": "^4.3.0",
|
package/style/base.css
CHANGED
|
@@ -212,10 +212,16 @@ div.jGIS-toolbar-widget > div.jp-Toolbar-item:last-child {
|
|
|
212
212
|
border: solid 1.5px red;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
.jGIS-Mainview-Container {
|
|
216
|
+
display: flex;
|
|
217
|
+
flex-direction: column;
|
|
218
|
+
height: 100%;
|
|
219
|
+
}
|
|
220
|
+
|
|
215
221
|
.jGIS-Mainview {
|
|
216
222
|
width: 100%;
|
|
217
|
-
height: calc(100% - 16px);
|
|
218
223
|
box-sizing: border-box;
|
|
224
|
+
flex: 1;
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
.jGIS-Popup-Wrapper {
|
|
@@ -523,6 +529,7 @@ div.jGIS-toolbar-widget > div.jp-Toolbar-item:last-child {
|
|
|
523
529
|
order: 1;
|
|
524
530
|
margin-top: 2px;
|
|
525
531
|
margin-bottom: 2px;
|
|
532
|
+
text-transform: capitalize;
|
|
526
533
|
}
|
|
527
534
|
|
|
528
535
|
.jGIS-property-panel
|
|
@@ -731,3 +738,11 @@ div.jGIS-toolbar-widget > div.jp-Toolbar-item:last-child {
|
|
|
731
738
|
.jgis-identify-grid-body:last-of-type strong:last-of-type {
|
|
732
739
|
padding-bottom: 8px;
|
|
733
740
|
}
|
|
741
|
+
|
|
742
|
+
/* Style the file path text */
|
|
743
|
+
.file-container {
|
|
744
|
+
display: flex;
|
|
745
|
+
align-items: center;
|
|
746
|
+
margin-bottom: 16px;
|
|
747
|
+
gap: 10px;
|
|
748
|
+
}
|