@jupytergis/jupytergis-lab 0.1.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/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2023, JupyterGIS contributors
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # jupytergis_lab
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
+ declare const _default: JupyterFrontEndPlugin<void>[];
3
+ export default _default;
package/lib/index.js ADDED
@@ -0,0 +1,308 @@
1
+ import { CommandIDs, ControlPanelModel, LeftPanelWidget, RightPanelWidget, addCommands, createDefaultLayerRegistry } from '@jupytergis/base';
2
+ import { IJGISFormSchemaRegistryToken, IJGISLayerBrowserRegistryToken, IJupyterGISDocTracker } from '@jupytergis/schema';
3
+ import { ILayoutRestorer } from '@jupyterlab/application';
4
+ import { ICompletionProviderManager } from '@jupyterlab/completer';
5
+ import { IMainMenu } from '@jupyterlab/mainmenu';
6
+ import { IStateDB } from '@jupyterlab/statedb';
7
+ import { ITranslator, nullTranslator } from '@jupyterlab/translation';
8
+ import { Menu } from '@lumino/widgets';
9
+ import { notebookRenderePlugin } from './notebookrenderer';
10
+ const NAME_SPACE = 'jupytergis';
11
+ const plugin = {
12
+ id: 'jupytergis:lab:main-menu',
13
+ autoStart: true,
14
+ requires: [
15
+ IJupyterGISDocTracker,
16
+ IJGISFormSchemaRegistryToken,
17
+ IJGISLayerBrowserRegistryToken,
18
+ IStateDB
19
+ ],
20
+ optional: [IMainMenu, ITranslator, ICompletionProviderManager],
21
+ activate: (app, tracker, formSchemaRegistry, layerBrowserRegistry, state, mainMenu, translator, completionProviderManager) => {
22
+ console.log('jupytergis:lab:main-menu is activated!');
23
+ translator = translator !== null && translator !== void 0 ? translator : nullTranslator;
24
+ const isEnabled = () => {
25
+ return (tracker.currentWidget !== null &&
26
+ tracker.currentWidget === app.shell.currentWidget);
27
+ };
28
+ createDefaultLayerRegistry(layerBrowserRegistry);
29
+ addCommands(app, tracker, translator, formSchemaRegistry, layerBrowserRegistry, state, completionProviderManager);
30
+ // SOURCES context menu
31
+ const newSourceSubMenu = new Menu({ commands: app.commands });
32
+ newSourceSubMenu.title.label = translator
33
+ .load('jupyterlab')
34
+ .__('Add Source');
35
+ newSourceSubMenu.id = 'jp-gis-contextmenu-addSource';
36
+ app.contextMenu.addItem({
37
+ type: 'submenu',
38
+ selector: '.jp-gis-sourcePanel',
39
+ rank: 3,
40
+ submenu: newSourceSubMenu
41
+ });
42
+ newSourceSubMenu.addItem({
43
+ command: CommandIDs.newRasterSource,
44
+ args: { from: 'contextMenu' }
45
+ });
46
+ newSourceSubMenu.addItem({
47
+ command: CommandIDs.newVectorSource,
48
+ args: { from: 'contextMenu' }
49
+ });
50
+ newSourceSubMenu.addItem({
51
+ command: CommandIDs.newGeoJSONSource,
52
+ args: { from: 'contextMenu' }
53
+ });
54
+ newSourceSubMenu.addItem({
55
+ command: CommandIDs.newRasterDemSource,
56
+ args: { from: 'contextMenu' }
57
+ });
58
+ newSourceSubMenu.addItem({
59
+ command: CommandIDs.newImageSource,
60
+ args: { from: 'contextMenu' }
61
+ });
62
+ app.contextMenu.addItem({
63
+ type: 'separator',
64
+ selector: '.jp-gis-sourcePanel',
65
+ rank: 2
66
+ });
67
+ app.contextMenu.addItem({
68
+ selector: '.jp-gis-source.jp-gis-sourceUnused',
69
+ rank: 1,
70
+ command: CommandIDs.removeSource
71
+ });
72
+ app.commands.addKeyBinding({
73
+ command: CommandIDs.removeSource,
74
+ keys: ['Delete'],
75
+ selector: '.jp-gis-source.jp-gis-sourceUnused'
76
+ });
77
+ app.contextMenu.addItem({
78
+ selector: '.jp-gis-source',
79
+ rank: 1,
80
+ command: CommandIDs.renameSource
81
+ });
82
+ app.commands.addKeyBinding({
83
+ command: CommandIDs.renameSource,
84
+ keys: ['F2'],
85
+ selector: '.jp-gis-sourceItem'
86
+ });
87
+ // LAYERS and LAYER GROUPS context menu
88
+ app.contextMenu.addItem({
89
+ command: CommandIDs.symbology,
90
+ selector: '.jp-gis-layerItem',
91
+ rank: 1
92
+ });
93
+ // Separator
94
+ app.contextMenu.addItem({
95
+ type: 'separator',
96
+ selector: '.jp-gis-layerPanel',
97
+ rank: 1
98
+ });
99
+ app.contextMenu.addItem({
100
+ command: CommandIDs.removeLayer,
101
+ selector: '.jp-gis-layerItem',
102
+ rank: 2
103
+ });
104
+ app.commands.addKeyBinding({
105
+ command: CommandIDs.removeLayer,
106
+ keys: ['Delete'],
107
+ selector: '.jp-gis-layerItem'
108
+ });
109
+ app.contextMenu.addItem({
110
+ command: CommandIDs.renameLayer,
111
+ selector: '.jp-gis-layerItem',
112
+ rank: 2
113
+ });
114
+ app.commands.addKeyBinding({
115
+ command: CommandIDs.renameLayer,
116
+ keys: ['F2'],
117
+ selector: '.jp-gis-layerItem'
118
+ });
119
+ const moveLayerSubmenu = new Menu({ commands: app.commands });
120
+ moveLayerSubmenu.title.label = translator
121
+ .load('jupyterlab')
122
+ .__('Move Selected Layers to Group');
123
+ moveLayerSubmenu.id = 'jp-gis-contextmenu-movelayer';
124
+ app.contextMenu.addItem({
125
+ type: 'submenu',
126
+ selector: '.jp-gis-layerItem',
127
+ rank: 2,
128
+ submenu: moveLayerSubmenu
129
+ });
130
+ app.contextMenu.opened.connect(() => buildGroupsMenu(app.contextMenu, tracker));
131
+ app.contextMenu.addItem({
132
+ command: CommandIDs.removeGroup,
133
+ selector: '.jp-gis-layerGroupHeader',
134
+ rank: 2
135
+ });
136
+ app.commands.addKeyBinding({
137
+ command: CommandIDs.removeGroup,
138
+ keys: ['Delete'],
139
+ selector: '.jp-gis-layerGroupHeader'
140
+ });
141
+ app.contextMenu.addItem({
142
+ command: CommandIDs.renameGroup,
143
+ selector: '.jp-gis-layerGroupHeader',
144
+ rank: 2
145
+ });
146
+ app.commands.addKeyBinding({
147
+ command: CommandIDs.renameGroup,
148
+ keys: ['F2'],
149
+ selector: '.jp-gis-layerGroupHeader'
150
+ });
151
+ // Separator
152
+ app.contextMenu.addItem({
153
+ type: 'separator',
154
+ selector: '.jp-gis-layerPanel',
155
+ rank: 2
156
+ });
157
+ const newLayerSubMenu = new Menu({ commands: app.commands });
158
+ newLayerSubMenu.title.label = translator.load('jupyterlab').__('Add Layer');
159
+ newLayerSubMenu.id = 'jp-gis-contextmenu-addLayer';
160
+ app.contextMenu.addItem({
161
+ type: 'submenu',
162
+ selector: '.jp-gis-layerPanel',
163
+ rank: 3,
164
+ submenu: newLayerSubMenu
165
+ });
166
+ newLayerSubMenu.addItem({
167
+ command: CommandIDs.newRasterLayer,
168
+ args: { from: 'contextMenu' }
169
+ });
170
+ newLayerSubMenu.addItem({
171
+ command: CommandIDs.newVectorLayer,
172
+ args: { from: 'contextMenu' }
173
+ });
174
+ newLayerSubMenu.addItem({
175
+ command: CommandIDs.newHillshadeLayer,
176
+ args: { from: 'contextMenu' }
177
+ });
178
+ newLayerSubMenu.addItem({
179
+ command: CommandIDs.newImageLayer,
180
+ args: { from: 'contextMenu' }
181
+ });
182
+ if (mainMenu) {
183
+ populateMenus(mainMenu, isEnabled);
184
+ }
185
+ // Keybindings for the console
186
+ app.commands.addKeyBinding({
187
+ command: CommandIDs.executeConsole,
188
+ keys: ['Shift Enter'],
189
+ selector: ".jpgis-console .jp-CodeConsole[data-jp-interaction-mode='notebook'] .jp-CodeConsole-promptCell"
190
+ });
191
+ app.commands.addKeyBinding({
192
+ command: CommandIDs.invokeCompleter,
193
+ keys: ['Tab'],
194
+ selector: '.jpgis-console .jp-CodeConsole-promptCell .jp-mod-completer-enabled'
195
+ });
196
+ app.commands.addKeyBinding({
197
+ command: CommandIDs.selectCompleter,
198
+ keys: ['Enter'],
199
+ selector: '.jpgis-console .jp-ConsolePanel .jp-mod-completer-active'
200
+ });
201
+ }
202
+ };
203
+ const controlPanel = {
204
+ id: 'jupytergis:lab:controlpanel',
205
+ autoStart: true,
206
+ requires: [
207
+ ILayoutRestorer,
208
+ IJupyterGISDocTracker,
209
+ IJGISFormSchemaRegistryToken,
210
+ IStateDB
211
+ ],
212
+ activate: (app, restorer, tracker, formSchemaRegistry, state) => {
213
+ const controlModel = new ControlPanelModel({ tracker });
214
+ const leftControlPanel = new LeftPanelWidget({
215
+ model: controlModel,
216
+ tracker,
217
+ state
218
+ });
219
+ leftControlPanel.id = 'jupytergis::leftControlPanel';
220
+ leftControlPanel.title.caption = 'JupyterGIS Control Panel';
221
+ // TODO Need an icon
222
+ // leftControlPanel.title.icon = jcLightIcon;
223
+ const rightControlPanel = new RightPanelWidget({
224
+ model: controlModel,
225
+ tracker,
226
+ formSchemaRegistry
227
+ });
228
+ rightControlPanel.id = 'jupytergis::rightControlPanel';
229
+ rightControlPanel.title.caption = 'JupyterGIS Control Panel';
230
+ // TODO Need an icon
231
+ // rightControlPanel.title.icon = jcLightIcon;
232
+ if (restorer) {
233
+ restorer.add(leftControlPanel, NAME_SPACE);
234
+ restorer.add(rightControlPanel, NAME_SPACE);
235
+ }
236
+ app.shell.add(leftControlPanel, 'left', { rank: 2000 });
237
+ app.shell.add(rightControlPanel, 'right', { rank: 2000 });
238
+ }
239
+ };
240
+ /**
241
+ * Populates the application menus for the notebook.
242
+ */
243
+ function populateMenus(mainMenu, isEnabled) {
244
+ // Add undo/redo hooks to the edit menu.
245
+ mainMenu.editMenu.undoers.redo.add({
246
+ id: CommandIDs.redo,
247
+ isEnabled
248
+ });
249
+ mainMenu.editMenu.undoers.undo.add({
250
+ id: CommandIDs.undo,
251
+ isEnabled
252
+ });
253
+ }
254
+ /**
255
+ * Populate submenu with current group names
256
+ */
257
+ function buildGroupsMenu(contextMenu, tracker) {
258
+ var _a, _b, _c, _d;
259
+ if (!((_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context.model)) {
260
+ return;
261
+ }
262
+ const model = (_b = tracker.currentWidget) === null || _b === void 0 ? void 0 : _b.context.model;
263
+ const submenu = (_d = (_c = contextMenu.menu.items.find(item => {
264
+ var _a;
265
+ return item.type === 'submenu' &&
266
+ ((_a = item.submenu) === null || _a === void 0 ? void 0 : _a.id) === 'jp-gis-contextmenu-movelayer';
267
+ })) === null || _c === void 0 ? void 0 : _c.submenu) !== null && _d !== void 0 ? _d : null;
268
+ // Bail early if the submenu isn't found
269
+ if (!submenu) {
270
+ return;
271
+ }
272
+ submenu.clearItems();
273
+ // need a list of group name
274
+ const layerTree = model.getLayerTree();
275
+ const groupNames = getLayerGroupNames(layerTree);
276
+ function getLayerGroupNames(layerTree) {
277
+ const result = [];
278
+ for (const item of layerTree) {
279
+ // Skip if the item is a layer id
280
+ if (typeof item === 'string') {
281
+ continue;
282
+ }
283
+ // Process group items
284
+ if (item.layers) {
285
+ result.push(item.name);
286
+ // Recursively process the layers of the current item
287
+ const nestedResults = getLayerGroupNames(item.layers);
288
+ // Append the results of the recursive call to the main result array
289
+ result.push(...nestedResults);
290
+ }
291
+ }
292
+ return result;
293
+ }
294
+ submenu.addItem({
295
+ command: CommandIDs.moveLayersToGroup,
296
+ args: { label: '' }
297
+ });
298
+ groupNames.forEach(name => {
299
+ submenu.addItem({
300
+ command: CommandIDs.moveLayersToGroup,
301
+ args: { label: name }
302
+ });
303
+ });
304
+ submenu.addItem({
305
+ command: CommandIDs.moveLayerToNewGroup
306
+ });
307
+ }
308
+ export default [plugin, controlPanel, notebookRenderePlugin];
@@ -0,0 +1,23 @@
1
+ import { JupyterGISModel } from '@jupytergis/schema';
2
+ import { JupyterFrontEndPlugin } from '@jupyterlab/application';
3
+ import { Panel } from '@lumino/widgets';
4
+ import { JupyterYModel } from 'yjs-widgets';
5
+ export interface ICommMetadata {
6
+ create_ydoc: boolean;
7
+ path: string;
8
+ format: string;
9
+ contentType: string;
10
+ ymodel_name: string;
11
+ }
12
+ export declare const CLASS_NAME = "jupytergis-notebook-widget";
13
+ export declare class YJupyterGISModel extends JupyterYModel {
14
+ jupyterGISModel: JupyterGISModel;
15
+ }
16
+ export declare class YJupyterGISLuminoWidget extends Panel {
17
+ constructor(options: {
18
+ model: JupyterGISModel;
19
+ });
20
+ onResize: () => void;
21
+ private _jgisWidget;
22
+ }
23
+ export declare const notebookRenderePlugin: JupyterFrontEndPlugin<void>;
@@ -0,0 +1,88 @@
1
+ import { WebSocketProvider } from '@jupyter/docprovider';
2
+ import { JupyterGISPanel } from '@jupytergis/base';
3
+ import { JupyterGISModel } from '@jupytergis/schema';
4
+ import { URLExt } from '@jupyterlab/coreutils';
5
+ import { ServerConnection } from '@jupyterlab/services';
6
+ import { ITranslator, nullTranslator } from '@jupyterlab/translation';
7
+ import { MessageLoop } from '@lumino/messaging';
8
+ import { Panel, Widget } from '@lumino/widgets';
9
+ import { IJupyterYWidgetManager, JupyterYModel } from 'yjs-widgets';
10
+ const Y_DOCUMENT_PROVIDER_URL = 'api/collaboration/room';
11
+ export const CLASS_NAME = 'jupytergis-notebook-widget';
12
+ export class YJupyterGISModel extends JupyterYModel {
13
+ }
14
+ export class YJupyterGISLuminoWidget extends Panel {
15
+ constructor(options) {
16
+ super();
17
+ this.onResize = () => {
18
+ if (this._jgisWidget) {
19
+ MessageLoop.sendMessage(this._jgisWidget, Widget.ResizeMessage.UnknownSize);
20
+ }
21
+ };
22
+ this.addClass(CLASS_NAME);
23
+ this._jgisWidget = new JupyterGISPanel(options);
24
+ this.addWidget(this._jgisWidget);
25
+ }
26
+ }
27
+ export const notebookRenderePlugin = {
28
+ id: 'jupytergis:yjswidget-plugin',
29
+ autoStart: true,
30
+ optional: [IJupyterYWidgetManager, ITranslator],
31
+ activate: (app, yWidgetManager, translator) => {
32
+ if (!yWidgetManager) {
33
+ console.error('Missing IJupyterYWidgetManager token!');
34
+ return;
35
+ }
36
+ const labTranslator = translator !== null && translator !== void 0 ? translator : nullTranslator;
37
+ class YJupyterGISModelFactory extends YJupyterGISModel {
38
+ ydocFactory(commMetadata) {
39
+ const { path, format, contentType } = commMetadata;
40
+ this.jupyterGISModel = new JupyterGISModel({});
41
+ const user = app.serviceManager.user;
42
+ if (path && format && contentType) {
43
+ const server = ServerConnection.makeSettings();
44
+ const serverUrl = URLExt.join(server.wsUrl, Y_DOCUMENT_PROVIDER_URL);
45
+ const ywsProvider = new WebSocketProvider({
46
+ url: serverUrl,
47
+ path,
48
+ format,
49
+ contentType,
50
+ model: this.jupyterGISModel.sharedModel,
51
+ user,
52
+ translator: labTranslator.load('jupyterlab')
53
+ });
54
+ this.jupyterGISModel.disposed.connect(() => {
55
+ ywsProvider.dispose();
56
+ });
57
+ }
58
+ else {
59
+ const awareness = this.jupyterGISModel.sharedModel.awareness;
60
+ const _onUserChanged = (user) => {
61
+ awareness.setLocalStateField('user', user.identity);
62
+ };
63
+ user.ready
64
+ .then(() => {
65
+ _onUserChanged(user);
66
+ })
67
+ .catch(e => console.error(e));
68
+ user.userChanged.connect(_onUserChanged, this);
69
+ }
70
+ return this.jupyterGISModel.sharedModel.ydoc;
71
+ }
72
+ }
73
+ class YJupyterGISWidget {
74
+ constructor(yModel, node) {
75
+ this.yModel = yModel;
76
+ this.node = node;
77
+ const widget = new YJupyterGISLuminoWidget({
78
+ model: yModel.jupyterGISModel
79
+ });
80
+ // Widget.attach(widget, node);
81
+ MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
82
+ node.appendChild(widget.node);
83
+ MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
84
+ }
85
+ }
86
+ yWidgetManager.registerWidget('@jupytergis:widget', YJupyterGISModelFactory, YJupyterGISWidget);
87
+ }
88
+ };
package/package.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "name": "@jupytergis/jupytergis-lab",
3
+ "version": "0.1.1",
4
+ "description": "JupyterGIS Lab extension.",
5
+ "keywords": [
6
+ "jupyter",
7
+ "jupyterlab",
8
+ "jupyterlab-extension"
9
+ ],
10
+ "homepage": "https://github.com/geojupyter/jupytergis",
11
+ "bugs": {
12
+ "url": "https://github.com/geojupyter/jupytergis/issues"
13
+ },
14
+ "license": "BSD-3-Clause",
15
+ "author": "JupyterGIS contributors",
16
+ "files": [
17
+ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
18
+ "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
19
+ ],
20
+ "main": "lib/index.js",
21
+ "types": "lib/index.d.ts",
22
+ "style": "style/index.css",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/geojupyter/jupytergis.git"
26
+ },
27
+ "scripts": {
28
+ "build": "jlpm build:lib && jlpm build:labextension:dev",
29
+ "build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
30
+ "build:labextension": "jupyter labextension build .",
31
+ "build:labextension:dev": "jupyter labextension build --development True .",
32
+ "build:lib": "tsc --sourceMap",
33
+ "build:lib:prod": "tsc",
34
+ "build:dev": "jlpm run build",
35
+ "clean": "jlpm clean:lib",
36
+ "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
37
+ "clean:lintcache": "rimraf .eslintcache .stylelintcache",
38
+ "clean:labextension": "rimraf jupytergis_lab/labextension jupytergis_lab/_version.py",
39
+ "clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
40
+ "eslint": "jlpm eslint:check --fix",
41
+ "eslint:check": "eslint . --cache --ext .ts,.tsx",
42
+ "install:extension": "jlpm build",
43
+ "lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
44
+ "lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
45
+ "prettier": "jlpm prettier:base --write",
46
+ "prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
47
+ "prettier:check": "jlpm prettier:base --check",
48
+ "stylelint": "jlpm stylelint:check --fix",
49
+ "stylelint:check": "stylelint --cache \"style/**/*.css\"",
50
+ "watch": "run-p watch:src watch:labextension",
51
+ "watch:src": "tsc -w --sourceMap",
52
+ "watch:labextension": "jupyter labextension watch ."
53
+ },
54
+ "dependencies": {
55
+ "@jupyter/docprovider": "^2.0.0",
56
+ "@jupytergis/base": "^0.1.1",
57
+ "@jupytergis/jupytergis-core": "^0.1.1",
58
+ "@jupytergis/schema": "^0.1.1",
59
+ "@jupyterlab/application": "^4.0.0",
60
+ "@jupyterlab/apputils": "^4.0.0",
61
+ "@jupyterlab/coreutils": "^6.0.0",
62
+ "@jupyterlab/docregistry": "^4.0.0",
63
+ "@jupyterlab/filebrowser": "^4.0.0",
64
+ "@jupyterlab/launcher": "^4.0.0",
65
+ "@jupyterlab/mainmenu": "^4.0.0",
66
+ "@jupyterlab/services": "^7.0.0",
67
+ "@jupyterlab/translation": "^4.0.0",
68
+ "@jupyterlab/ui-components": "^4.0.0",
69
+ "@lumino/messaging": "^2.0.0",
70
+ "@lumino/widgets": "^2.0.0",
71
+ "react": "^18.0.1",
72
+ "yjs-widgets": "^0.3.5"
73
+ },
74
+ "devDependencies": {
75
+ "@jupyterlab/builder": "^4.0.0",
76
+ "css-loader": "^6.7.1",
77
+ "mkdirp": "^1.0.3",
78
+ "npm-run-all": "^4.1.5",
79
+ "rimraf": "^3.0.2",
80
+ "typescript": "^5",
81
+ "yjs": "^13.5.0"
82
+ },
83
+ "sideEffects": [
84
+ "style/*.css",
85
+ "style/index.js"
86
+ ],
87
+ "styleModule": "style/index.js",
88
+ "publishConfig": {
89
+ "access": "public"
90
+ },
91
+ "jupyterlab": {
92
+ "discovery": {
93
+ "server": {
94
+ "managers": [
95
+ "pip"
96
+ ],
97
+ "base": {
98
+ "name": "jupytergis_lab"
99
+ }
100
+ }
101
+ },
102
+ "extension": true,
103
+ "outputDir": "jupytergis_lab/labextension",
104
+ "sharedPackages": {
105
+ "@jupytergis/base": {
106
+ "singleton": true,
107
+ "bundled": false
108
+ },
109
+ "@jupytergis/schema": {
110
+ "singleton": true,
111
+ "bundled": false
112
+ },
113
+ "@jupytergis/jupytergis-core": {
114
+ "singleton": true,
115
+ "bundled": false
116
+ },
117
+ "@jupyter/docprovider": {
118
+ "singleton": true,
119
+ "bundled": false
120
+ },
121
+ "yjs-widgets": {
122
+ "singleton": true,
123
+ "bundled": false
124
+ }
125
+ }
126
+ }
127
+ }
package/style/base.css ADDED
@@ -0,0 +1,377 @@
1
+ @import url('~@deathbeds/jupyterlab-rjsf/style/index.css');
2
+ @import url('~@jupytergis/base/style/index.css');
3
+
4
+ .jGIS-Spinner {
5
+ position: absolute;
6
+ display: flex;
7
+ justify-content: center;
8
+ align-items: center;
9
+ z-index: 10;
10
+ left: 0;
11
+ top: 0;
12
+ width: 100%;
13
+ height: 100%;
14
+ outline: none;
15
+ background: #00000075;
16
+ }
17
+
18
+ .jGIS-SpinnerContent {
19
+ border: solid #f376269e;
20
+ margin: 50px auto;
21
+ text-indent: -9999em;
22
+ width: 6em;
23
+ height: 6em;
24
+ border-radius: 50%;
25
+ position: relative;
26
+ animation:
27
+ load3 1s infinite linear,
28
+ fadeIn 1s;
29
+ }
30
+
31
+ .jGIS-SpinnerContent:before {
32
+ width: 50%;
33
+ height: 50%;
34
+ background: #f3762605;
35
+ border-radius: 100% 0 100% 0;
36
+ box-shadow: inset 6px 5px 0 1px #f37626;
37
+ position: absolute;
38
+ top: 0;
39
+ left: 0;
40
+ content: '';
41
+ }
42
+
43
+ .jGIS-SpinnerContent:after {
44
+ width: 75%;
45
+ height: 75%;
46
+ border-radius: 50%;
47
+ content: '';
48
+ margin: auto;
49
+ position: absolute;
50
+ top: 0;
51
+ left: 0;
52
+ bottom: 0;
53
+ right: 0;
54
+ }
55
+
56
+ .jGIS-camera-client {
57
+ width: 15px;
58
+ height: 15px;
59
+ position: absolute;
60
+ z-index: 10;
61
+ background-color: var(--jp-private-notebook-active-color);
62
+ border-radius: 50%;
63
+ display: flex;
64
+ justify-content: center;
65
+ align-items: center;
66
+ }
67
+
68
+ .jGIS-control-panel {
69
+ color: var(--jp-ui-font-color1);
70
+ background: var(--jp-layout-color1);
71
+ height: 100%;
72
+ }
73
+
74
+ .jGIS-control-panel * {
75
+ font-family: var(--jp-ui-font-family);
76
+ }
77
+
78
+ .jGIS-control-panel-title {
79
+ border-bottom: solid var(--jp-border-width) var(--jp-border-color1);
80
+ box-shadow: var(--jp-toolbar-box-shadow);
81
+ display: flex;
82
+ flex-direction: row;
83
+ align-items: center;
84
+ min-height: 24px;
85
+ height: var(--jp-debugger-header-height);
86
+ background-color: var(--jp-layout-color2);
87
+ }
88
+
89
+ .jGIS-control-panel-title h2 {
90
+ text-transform: uppercase;
91
+ font-weight: 600;
92
+ font-size: var(--jp-ui-font-size0);
93
+ color: var(--jp-ui-font-color1);
94
+ padding-left: 8px;
95
+ padding-right: 4px;
96
+ }
97
+
98
+ .jGIS-sidepanel-widget {
99
+ height: 100%;
100
+ }
101
+
102
+ .jGIS-sidebar-treepanel {
103
+ display: flex;
104
+ flex-direction: column;
105
+ min-height: 50px;
106
+ padding-top: 3px;
107
+ }
108
+
109
+ .jGIS-sidebar-propertiespanel {
110
+ display: flex;
111
+ flex-direction: column;
112
+ min-height: 50px;
113
+ padding-top: 3px;
114
+ }
115
+
116
+ .jGIS-treeview-wrapper {
117
+ overflow: auto;
118
+ height: 100%;
119
+ }
120
+
121
+ .jGIS-treeview-wrapper > div {
122
+ padding: 0 !important;
123
+ }
124
+ /* TODO: More robust selector */
125
+ .jGIS-treeview-wrapper div[style*='align-items: center;']:first-of-type {
126
+ flex-grow: 1;
127
+ }
128
+
129
+ .jGIS-control-panel-tree {
130
+ flex-grow: 1;
131
+ }
132
+
133
+ .jGIS-sidebar-propertiespanel > div {
134
+ overflow: auto;
135
+ }
136
+
137
+ .jGIS-property-outer {
138
+ padding: 10px;
139
+ flex-grow: 1;
140
+ overflow: auto;
141
+ }
142
+
143
+ .jGIS-property-buttons {
144
+ display: flex;
145
+ justify-content: end;
146
+ padding: 10px;
147
+ }
148
+
149
+ .jGIS-property-panel {
150
+ display: flex;
151
+ flex-flow: column;
152
+ height: 100%;
153
+ overflow: hidden;
154
+ }
155
+
156
+ .jGIS-hidden-field {
157
+ display: none;
158
+ }
159
+
160
+ div.field.field-array > label + span {
161
+ display: none;
162
+ }
163
+
164
+ .jGIS-layer-CreationFormDialog .jp-Dialog-content {
165
+ width: 60%;
166
+ }
167
+
168
+ .jGIS-layer-CreationFormDialog form {
169
+ padding: 10px;
170
+ }
171
+
172
+ /* TODO Upstream this to jupyterlab jrfs */
173
+ .jp-SchemaForm .control-label,
174
+ .jp-SchemaForm legend {
175
+ position: inherit;
176
+ text-transform: capitalize;
177
+ }
178
+
179
+ div.jGIS-toolbar-widget > div.jp-Toolbar-item:last-child {
180
+ flex-grow: 1;
181
+ }
182
+
183
+ .jGIS-toolbar-usertoolbar {
184
+ flex-grow: 1;
185
+ display: flex;
186
+ flex-direction: row-reverse;
187
+ }
188
+ .jGIS-toolbar-react-widget {
189
+ display: flex;
190
+ flex-direction: row;
191
+ align-items: center;
192
+ flex-grow: 1;
193
+ }
194
+
195
+ .jGIS-Toolbar-Separator {
196
+ width: var(--jp-border-width);
197
+ background-color: var(--jp-border-color1);
198
+ padding-left: 0px !important;
199
+ padding-right: 0px !important;
200
+ }
201
+
202
+ .jGIS-toolbar-usertoolbar .jp-MenuBar-anonymousIcon,
203
+ .jGIS-toolbar-usertoolbar .jp-MenuBar-imageIcon {
204
+ position: unset !important;
205
+ margin-right: 2px;
206
+ height: 22px;
207
+ box-sizing: border-box;
208
+ }
209
+
210
+ .jGIS-toolbar-usertoolbar .jp-MenuBar-anonymousIcon.selected,
211
+ .jGIS-toolbar-usertoolbar .jp-MenuBar-imageIcon.selected {
212
+ border: solid 1.5px red;
213
+ }
214
+
215
+ .jGIS-Mainview {
216
+ width: 100%;
217
+ height: 100%;
218
+ box-sizing: border-box;
219
+ }
220
+
221
+ .jGIS-Annotation-Wrapper {
222
+ position: absolute;
223
+ opacity: 1;
224
+ transition: opacity 0.1s linear 0.15s;
225
+ }
226
+
227
+ .jGIS-Annotation {
228
+ z-index: 1;
229
+ margin-left: 1px;
230
+ margin-top: 1px;
231
+ padding: 1em;
232
+ color: #fff;
233
+ background: var(--jp-layout-color1);
234
+ border-radius: 0.5em;
235
+ font-size: 12px;
236
+ line-height: 1.2;
237
+ transition: opacity 0.5s;
238
+ }
239
+
240
+ .jGIS-FloatingAnnotation {
241
+ position: absolute;
242
+ width: 250px;
243
+ box-shadow: var(--jp-elevation-z6);
244
+ }
245
+
246
+ .jGIS-Annotations {
247
+ overflow: auto;
248
+ }
249
+
250
+ .jGIS-Annotations-Separator {
251
+ border-color: var(--jp-layout-color4);
252
+ border-style: solid;
253
+ border-width: 1px;
254
+ }
255
+
256
+ .jGIS-Annotation-Handler {
257
+ position: absolute;
258
+ top: -5px;
259
+ left: -5px;
260
+ width: 8px;
261
+ height: 8px;
262
+ border: 1px solid #ffffffc2;
263
+ border-radius: 50%;
264
+ background: rgb(0 0 0 / 63%);
265
+ cursor: pointer;
266
+ transition-property: width, height, left, top;
267
+ transition-duration: 0.2s;
268
+ z-index: 1000;
269
+ }
270
+
271
+ .jGIS-Annotation-Handler:hover {
272
+ top: -9px;
273
+ left: -9px;
274
+ width: 16px;
275
+ height: 16px;
276
+ }
277
+
278
+ .jGIS-Annotation-Message {
279
+ display: flex;
280
+ margin-top: 10px;
281
+ gap: 5px;
282
+ align-items: center;
283
+ justify-content: center;
284
+ }
285
+
286
+ .jGIS-Annotation-Message .jGIS-Annotation-User-Icon {
287
+ border-radius: 100%;
288
+ width: 24px;
289
+ height: 24px;
290
+ display: flex;
291
+ align-items: center;
292
+ vertical-align: middle;
293
+ color: var(--jp-ui-font-color1);
294
+ }
295
+
296
+ .jGIS-Annotation-Message textarea {
297
+ border-radius: var(--jp-border-radius);
298
+ background: var(--jp-layout-color2);
299
+ color: var(--jp-ui-font-color2);
300
+ flex-grow: 1;
301
+ resize: none;
302
+ }
303
+
304
+ .jGIS-Annotation-Message-Content {
305
+ background: var(--jp-layout-color2);
306
+ color: var(--jp-ui-font-color2);
307
+ border-radius: var(--jp-border-radius);
308
+ flex-grow: 1;
309
+ }
310
+
311
+ .jGIS-Annotation-Topbar {
312
+ display: flex;
313
+ flex-direction: row-reverse;
314
+ }
315
+
316
+ .jGIS-Annotation-TopBarIcon {
317
+ margin: 3px;
318
+ width: 20px;
319
+ height: 20px;
320
+ cursor: pointer;
321
+ }
322
+
323
+ .jGIS-Annotation-TopBarIcon > svg {
324
+ width: 20px;
325
+ height: 20px;
326
+ }
327
+
328
+ .jGIS-Annotation-Submit > svg {
329
+ width: 30px;
330
+ height: 30px;
331
+ }
332
+
333
+ .jGIS-Annotation-Submit g {
334
+ fill: #f6f7f8 !important;
335
+ }
336
+
337
+ .jGIS-Annotation-Submit:hover {
338
+ opacity: 70%;
339
+ cursor: pointer;
340
+ }
341
+
342
+ .jGIS-Annotation-Submit {
343
+ background-color: var(--jp-brand-color1);
344
+ border-radius: 100%;
345
+ width: 30px;
346
+ height: 30px;
347
+ }
348
+
349
+ /* Hack to remove the malformed form button */
350
+ .object-property-expand {
351
+ display: none;
352
+ }
353
+
354
+ .highlight {
355
+ background-color: var(--jp-layout-color2) !important;
356
+ }
357
+ .jupytergis-notebook-widget {
358
+ height: 600px;
359
+ width: 100%;
360
+ }
361
+ .jupytergis-notebook-widget > div {
362
+ height: 100%;
363
+ width: 100%;
364
+ }
365
+
366
+ .jp-SchemaForm .control-label,
367
+ .jp-SchemaForm legend {
368
+ width: 100%;
369
+ }
370
+
371
+ .jpgis-console {
372
+ border-top: var(--jp-border-width) solid var(--jp-toolbar-border-color);
373
+ }
374
+
375
+ .jpgis-console .jp-CodeConsole-banner {
376
+ display: none;
377
+ }
@@ -0,0 +1 @@
1
+ @import url('base.css');
package/style/index.js ADDED
@@ -0,0 +1 @@
1
+ import "./base.css";