@jupytergis/jupytergis-lab 0.3.0 → 0.4.1

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 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 { notebookRenderePlugin } from './notebookrenderer';
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.context.model)) {
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.context.model;
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, notebookRenderePlugin];
275
+ export default [plugin, controlPanel, notebookRendererPlugin];
@@ -1,5 +1,7 @@
1
- import { JupyterGISModel } from '@jupytergis/schema';
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
- model: JupyterGISModel;
19
- });
20
- onResize: () => void;
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
- export declare const notebookRenderePlugin: JupyterFrontEndPlugin<void>;
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 {};
@@ -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
- this.onResize = () => {
14
- if (this._jgisWidget) {
15
- MessageLoop.sendMessage(this._jgisWidget, Widget.ResizeMessage.UnknownSize);
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._jgisWidget = new JupyterGISPanel(options);
20
- this.addWidget(this._jgisWidget);
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 notebookRenderePlugin = {
63
+ export const notebookRendererPlugin = {
24
64
  id: 'jupytergis:yjswidget-plugin',
25
65
  autoStart: true,
26
- optional: [IJupyterYWidgetManager, ICollaborativeDrive],
27
- activate: (app, yWidgetManager, drive) => {
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
- ydocFactory(commMetadata) {
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
- return this.jupyterGISModel.sharedModel.ydoc;
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
- model: yModel.jupyterGISModel
130
+ commands: app.commands,
131
+ model: yModel.jupyterGISModel,
132
+ externalCommands: externalCommandRegistry,
133
+ tracker: jgisTracker
58
134
  });
59
- // Widget.attach(widget, node);
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.0",
3
+ "version": "0.4.1",
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.3.0",
57
- "@jupytergis/jupytergis-core": "^0.3.0",
58
- "@jupytergis/schema": "^0.3.0",
56
+ "@jupytergis/base": "^0.4.1",
57
+ "@jupytergis/schema": "^0.4.1",
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
- "@jupyterlab/ui-components": "^4.3.0",
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.3.5"
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
+ }