@jupytergis/base 0.13.2 → 0.14.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/commands/BaseCommandIDs.d.ts +14 -13
- package/lib/commands/BaseCommandIDs.js +14 -14
- package/lib/commands/index.js +528 -130
- package/lib/commands/operationCommands.d.ts +22 -0
- package/lib/commands/operationCommands.js +305 -0
- package/lib/constants.js +11 -9
- package/lib/dialogs/ProcessingFormDialog.d.ts +1 -1
- package/lib/dialogs/ProcessingFormDialog.js +2 -2
- package/lib/dialogs/layerBrowserDialog.d.ts +2 -0
- package/lib/dialogs/layerBrowserDialog.js +12 -5
- package/lib/dialogs/layerCreationFormDialog.d.ts +7 -0
- package/lib/dialogs/layerCreationFormDialog.js +10 -2
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.d.ts +2 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.js +21 -19
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.d.ts +3 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.js +13 -5
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +6 -4
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +7 -11
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +7 -10
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +7 -8
- package/lib/formbuilder/creationform.d.ts +8 -8
- package/lib/formbuilder/creationform.js +130 -85
- package/lib/formbuilder/editform.d.ts +1 -7
- package/lib/formbuilder/editform.js +64 -52
- package/lib/formbuilder/formselectors.d.ts +5 -4
- package/lib/formbuilder/index.d.ts +1 -1
- package/lib/formbuilder/index.js +1 -1
- package/lib/formbuilder/objectform/SchemaForm.d.ts +36 -0
- package/lib/formbuilder/objectform/SchemaForm.js +77 -0
- package/lib/formbuilder/objectform/StoryEditorForm.d.ts +3 -9
- package/lib/formbuilder/objectform/StoryEditorForm.js +20 -14
- package/lib/formbuilder/objectform/components/LayerSelect.js +3 -8
- package/lib/formbuilder/objectform/components/SegmentFormSymbology.js +23 -10
- package/lib/formbuilder/objectform/components/SourcePropertiesField.d.ts +7 -0
- package/lib/formbuilder/objectform/components/SourcePropertiesField.js +29 -0
- package/lib/formbuilder/objectform/components/StorySegmentReset.js +1 -1
- package/lib/formbuilder/objectform/fileselectorwidget.js +1 -1
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.d.ts +3 -12
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.js +87 -55
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.d.ts +3 -8
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.js +36 -10
- package/lib/formbuilder/objectform/layer/layerform.d.ts +7 -9
- package/lib/formbuilder/objectform/layer/layerform.js +33 -20
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +3 -5
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +73 -29
- package/lib/formbuilder/objectform/layer/vectorlayerform.d.ts +3 -14
- package/lib/formbuilder/objectform/layer/vectorlayerform.js +36 -29
- package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +3 -10
- package/lib/formbuilder/objectform/layer/webGlLayerForm.js +37 -13
- package/lib/formbuilder/objectform/process/dissolveProcessForm.d.ts +8 -18
- package/lib/formbuilder/objectform/process/dissolveProcessForm.js +68 -56
- package/lib/formbuilder/objectform/processingForm.d.ts +12 -0
- package/lib/formbuilder/objectform/processingForm.js +33 -0
- package/lib/formbuilder/objectform/schemaUtils.d.ts +16 -0
- package/lib/formbuilder/objectform/schemaUtils.js +59 -0
- package/lib/formbuilder/objectform/source/geojsonsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/geojsonsource.js +94 -53
- package/lib/formbuilder/objectform/source/geotiffsource.d.ts +3 -20
- package/lib/formbuilder/objectform/source/geotiffsource.js +73 -74
- package/lib/formbuilder/objectform/source/pathbasedsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/pathbasedsource.js +76 -75
- package/lib/formbuilder/objectform/source/sourceform.d.ts +7 -8
- package/lib/formbuilder/objectform/source/sourceform.js +28 -11
- package/lib/formbuilder/objectform/source/tilesourceform.d.ts +3 -7
- package/lib/formbuilder/objectform/source/tilesourceform.js +63 -53
- package/lib/formbuilder/objectform/useSchemaFormState.d.ts +48 -0
- package/lib/formbuilder/objectform/useSchemaFormState.js +35 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/keybindings.json +10 -10
- package/lib/mainview/mainView.d.ts +11 -7
- package/lib/mainview/mainView.js +63 -36
- package/lib/mainview/mainviewmodel.js +2 -2
- package/lib/menus.js +8 -8
- package/lib/panelview/components/layers.js +5 -2
- package/lib/panelview/objectproperties.js +2 -2
- package/lib/panelview/rightpanel.js +17 -2
- package/lib/panelview/story-maps/SpectaPanel.d.ts +15 -0
- package/lib/panelview/story-maps/SpectaPanel.js +35 -0
- package/lib/panelview/story-maps/StoryViewerPanel.d.ts +24 -9
- package/lib/panelview/story-maps/StoryViewerPanel.js +22 -268
- package/lib/panelview/story-maps/{PreviewModeSwitch.js → components/PreviewModeSwitch.js} +1 -1
- package/lib/panelview/story-maps/components/SpectaDesktopView.d.ts +21 -0
- package/lib/panelview/story-maps/components/SpectaDesktopView.js +49 -0
- package/lib/panelview/story-maps/components/SpectaMobileView.d.ts +17 -0
- package/lib/panelview/story-maps/{MobileSpectaPanel.js → components/SpectaMobileView.js} +8 -22
- package/lib/panelview/story-maps/{StoryNavBar.d.ts → components/StoryNavBar.d.ts} +1 -1
- package/lib/panelview/story-maps/{StoryNavBar.js → components/StoryNavBar.js} +2 -4
- package/lib/panelview/story-maps/hooks/useStoryMap.d.ts +39 -0
- package/lib/panelview/story-maps/hooks/useStoryMap.js +252 -0
- package/lib/processing/index.d.ts +2 -2
- package/lib/processing/index.js +62 -35
- package/lib/processing/processingCommands.d.ts +1 -1
- package/lib/processing/processingCommands.js +26 -6
- package/lib/shared/components/Collapsible.d.ts +6 -0
- package/lib/shared/components/Collapsible.js +26 -0
- package/lib/statusbar/SpectaPresentationProgressBar.d.ts +7 -0
- package/lib/statusbar/SpectaPresentationProgressBar.js +40 -0
- package/lib/toolbar/widget.js +4 -2
- package/lib/tools.d.ts +6 -0
- package/lib/tools.js +9 -0
- package/lib/types.d.ts +29 -2
- package/lib/widget.js +14 -2
- package/package.json +2 -4
- package/style/base.css +23 -1
- package/style/dialog.css +5 -0
- package/style/leftPanel.css +14 -37
- package/style/shared/button.css +0 -10
- package/style/shared/switch.css +8 -7
- package/style/spectaProgressBar.css +144 -0
- package/style/storyPanel.css +33 -0
- package/style/symbologyDialog.css +2 -2
- package/lib/formbuilder/objectform/baseform.d.ts +0 -91
- package/lib/formbuilder/objectform/baseform.js +0 -231
- package/lib/panelview/story-maps/MobileSpectaPanel.d.ts +0 -7
- /package/lib/panelview/story-maps/{PreviewModeSwitch.d.ts → components/PreviewModeSwitch.d.ts} +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { UUID } from '@lumino/coreutils';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState, } from 'react';
|
|
3
|
+
/** Inline style for specta presentation (bg and text color from story). */
|
|
4
|
+
export function getSpectaPresentationStyle(story) {
|
|
5
|
+
const bgColor = story === null || story === void 0 ? void 0 : story.presentationBgColor;
|
|
6
|
+
const textColor = story === null || story === void 0 ? void 0 : story.presentationTextColor;
|
|
7
|
+
const style = {};
|
|
8
|
+
if (bgColor) {
|
|
9
|
+
style['--jgis-specta-bg-color'] = bgColor;
|
|
10
|
+
style.backgroundColor = bgColor;
|
|
11
|
+
}
|
|
12
|
+
if (textColor) {
|
|
13
|
+
style['--jgis-specta-text-color'] = textColor;
|
|
14
|
+
style.color = textColor;
|
|
15
|
+
}
|
|
16
|
+
return style;
|
|
17
|
+
}
|
|
18
|
+
export function useStoryMap({ model, overrideLayerEntriesRef, removeLayer, addLayer, panelRef, isSpecta, }) {
|
|
19
|
+
const [currentIndex, setCurrentIndex] = useState(() => { var _a; return (_a = model.getCurrentSegmentIndex()) !== null && _a !== void 0 ? _a : 0; });
|
|
20
|
+
const [storyData, setStoryData] = useState(() => { var _a; return (_a = model.getSelectedStory().story) !== null && _a !== void 0 ? _a : null; });
|
|
21
|
+
const storySegments = useMemo(() => {
|
|
22
|
+
if (!(storyData === null || storyData === void 0 ? void 0 : storyData.storySegments)) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
return storyData.storySegments
|
|
26
|
+
.map(segmentId => model.getLayer(segmentId))
|
|
27
|
+
.filter((layer) => layer !== undefined);
|
|
28
|
+
}, [storyData, model]);
|
|
29
|
+
const segmentCount = storySegments.length;
|
|
30
|
+
const storySegmentIds = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments;
|
|
31
|
+
const currentStorySegment = useMemo(() => storySegments[currentIndex], [storySegments, currentIndex]);
|
|
32
|
+
const activeSlide = useMemo(() => currentStorySegment === null || currentStorySegment === void 0 ? void 0 : currentStorySegment.parameters, [currentStorySegment]);
|
|
33
|
+
const layerName = useMemo(() => { var _a; return (_a = currentStorySegment === null || currentStorySegment === void 0 ? void 0 : currentStorySegment.name) !== null && _a !== void 0 ? _a : ''; }, [currentStorySegment]);
|
|
34
|
+
const currentStorySegmentId = useMemo(() => storySegmentIds === null || storySegmentIds === void 0 ? void 0 : storySegmentIds[currentIndex], [storySegmentIds, currentIndex]);
|
|
35
|
+
const hasPrev = currentIndex > 0;
|
|
36
|
+
const hasNext = currentIndex < segmentCount - 1;
|
|
37
|
+
const clearOverrideLayers = useCallback(() => {
|
|
38
|
+
const entries = overrideLayerEntriesRef.current;
|
|
39
|
+
if (!entries) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
entries.forEach(({ layerId, action }) => {
|
|
43
|
+
if (action === 'remove') {
|
|
44
|
+
removeLayer === null || removeLayer === void 0 ? void 0 : removeLayer(layerId);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const layerOrSource = model.getLayerOrSource(layerId);
|
|
48
|
+
if (layerOrSource) {
|
|
49
|
+
model.triggerLayerUpdate(layerId, layerOrSource);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
entries.length = 0;
|
|
54
|
+
}, [model, overrideLayerEntriesRef, removeLayer]);
|
|
55
|
+
const zoomToCurrentLayer = useCallback(() => {
|
|
56
|
+
if (currentStorySegmentId) {
|
|
57
|
+
model.centerOnPosition(currentStorySegmentId);
|
|
58
|
+
}
|
|
59
|
+
}, [model, currentStorySegmentId]);
|
|
60
|
+
const setIndex = useCallback((index) => {
|
|
61
|
+
model.setCurrentSegmentIndex(index);
|
|
62
|
+
}, [model]);
|
|
63
|
+
const handlePrev = useCallback(() => {
|
|
64
|
+
if (hasPrev) {
|
|
65
|
+
model.setCurrentSegmentIndex(currentIndex - 1);
|
|
66
|
+
}
|
|
67
|
+
}, [model, currentIndex, hasPrev]);
|
|
68
|
+
const handleNext = useCallback(() => {
|
|
69
|
+
if (hasNext) {
|
|
70
|
+
model.setCurrentSegmentIndex(currentIndex + 1);
|
|
71
|
+
}
|
|
72
|
+
}, [model, currentIndex, hasNext]);
|
|
73
|
+
const setSelectedLayerByIndex = useCallback((index) => {
|
|
74
|
+
var _a;
|
|
75
|
+
const storySegmentId = (_a = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) === null || _a === void 0 ? void 0 : _a[index];
|
|
76
|
+
if (storySegmentId) {
|
|
77
|
+
model.selected = {
|
|
78
|
+
[storySegmentId]: {
|
|
79
|
+
type: 'layer',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}, [storyData, model]);
|
|
84
|
+
const overrideSymbology = useCallback((index) => {
|
|
85
|
+
var _a;
|
|
86
|
+
if (index < 0 || !storySegments[index]) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const segment = storySegments[index];
|
|
90
|
+
const layerOverrides = (_a = segment.parameters) === null || _a === void 0 ? void 0 : _a.layerOverride;
|
|
91
|
+
if (!Array.isArray(layerOverrides)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
layerOverrides.forEach(override => {
|
|
95
|
+
var _a, _b, _c, _d;
|
|
96
|
+
const { color, opacity, sourceProperties, symbologyState, targetLayer: targetLayerId, visible, } = override;
|
|
97
|
+
if (!targetLayerId) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
(_a = overrideLayerEntriesRef.current) === null || _a === void 0 ? void 0 : _a.push({
|
|
101
|
+
layerId: targetLayerId,
|
|
102
|
+
action: 'restore',
|
|
103
|
+
});
|
|
104
|
+
const targetLayer = model.getLayer(targetLayerId);
|
|
105
|
+
if (targetLayer === null || targetLayer === void 0 ? void 0 : targetLayer.parameters) {
|
|
106
|
+
if (symbologyState !== undefined) {
|
|
107
|
+
targetLayer.parameters.symbologyState = symbologyState;
|
|
108
|
+
}
|
|
109
|
+
if (color !== undefined) {
|
|
110
|
+
targetLayer.parameters.color = color;
|
|
111
|
+
}
|
|
112
|
+
if (opacity !== undefined) {
|
|
113
|
+
targetLayer.parameters.opacity = opacity;
|
|
114
|
+
}
|
|
115
|
+
if (visible !== undefined) {
|
|
116
|
+
targetLayer.visible = visible;
|
|
117
|
+
}
|
|
118
|
+
if (sourceProperties !== undefined &&
|
|
119
|
+
Object.keys(sourceProperties).length > 0) {
|
|
120
|
+
const sourceId = (_b = targetLayer.parameters) === null || _b === void 0 ? void 0 : _b.source;
|
|
121
|
+
if (sourceId) {
|
|
122
|
+
const source = model.getSource(sourceId);
|
|
123
|
+
if (!source) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (source === null || source === void 0 ? void 0 : source.parameters) {
|
|
127
|
+
source.parameters = Object.assign(Object.assign({}, source.parameters), sourceProperties);
|
|
128
|
+
}
|
|
129
|
+
(_c = overrideLayerEntriesRef.current) === null || _c === void 0 ? void 0 : _c.push({
|
|
130
|
+
layerId: sourceId,
|
|
131
|
+
action: 'restore',
|
|
132
|
+
});
|
|
133
|
+
model.triggerLayerUpdate(sourceId, source);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if ((symbologyState === null || symbologyState === void 0 ? void 0 : symbologyState.renderType) === 'Heatmap') {
|
|
137
|
+
targetLayer.type = 'HeatmapLayer';
|
|
138
|
+
if (addLayer) {
|
|
139
|
+
const newId = UUID.uuid4();
|
|
140
|
+
addLayer(newId, targetLayer, 100);
|
|
141
|
+
(_d = overrideLayerEntriesRef.current) === null || _d === void 0 ? void 0 : _d.push({
|
|
142
|
+
layerId: newId,
|
|
143
|
+
action: 'remove',
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
model.triggerLayerUpdate(targetLayerId, targetLayer);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}, [addLayer, model, storySegments, overrideLayerEntriesRef]);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
const onIndexChanged = (_, index) => {
|
|
155
|
+
setCurrentIndex(Math.max(0, index !== null && index !== void 0 ? index : 0));
|
|
156
|
+
};
|
|
157
|
+
model.currentSegmentIndexChanged.connect(onIndexChanged);
|
|
158
|
+
return () => {
|
|
159
|
+
model.currentSegmentIndexChanged.disconnect(onIndexChanged);
|
|
160
|
+
};
|
|
161
|
+
}, [model]);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
const updateStory = () => {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
clearOverrideLayers();
|
|
166
|
+
setStoryData((_a = model.getSelectedStory().story) !== null && _a !== void 0 ? _a : null);
|
|
167
|
+
setCurrentIndex((_b = model.getCurrentSegmentIndex()) !== null && _b !== void 0 ? _b : 0);
|
|
168
|
+
};
|
|
169
|
+
updateStory();
|
|
170
|
+
model.sharedModel.storyMapsChanged.connect(updateStory);
|
|
171
|
+
return () => {
|
|
172
|
+
model.sharedModel.storyMapsChanged.disconnect(updateStory);
|
|
173
|
+
};
|
|
174
|
+
}, [model, clearOverrideLayers]);
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
return () => {
|
|
177
|
+
var _a;
|
|
178
|
+
clearOverrideLayers();
|
|
179
|
+
(_a = storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) === null || _a === void 0 ? void 0 : _a.forEach(segmentId => {
|
|
180
|
+
var _a;
|
|
181
|
+
const segment = model.getLayer(segmentId);
|
|
182
|
+
const overrides = (_a = segment === null || segment === void 0 ? void 0 : segment.parameters) === null || _a === void 0 ? void 0 : _a.layerOverride;
|
|
183
|
+
if (Array.isArray(overrides)) {
|
|
184
|
+
overrides.forEach((override) => {
|
|
185
|
+
const targetLayerId = override.targetLayer;
|
|
186
|
+
if (targetLayerId) {
|
|
187
|
+
const targetLayer = model.getLayer(targetLayerId);
|
|
188
|
+
targetLayer &&
|
|
189
|
+
model.triggerLayerUpdate(targetLayerId, targetLayer);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
}, []);
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
if (currentStorySegmentId) {
|
|
198
|
+
zoomToCurrentLayer();
|
|
199
|
+
}
|
|
200
|
+
}, [currentStorySegmentId, zoomToCurrentLayer]);
|
|
201
|
+
// Set selected layer and apply symbology when segment changes; remove previous segment's override layers first.
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (!(storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) || currentIndex < 0) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
clearOverrideLayers();
|
|
207
|
+
setSelectedLayerByIndex(currentIndex);
|
|
208
|
+
overrideSymbology(currentIndex);
|
|
209
|
+
}, [
|
|
210
|
+
storyData,
|
|
211
|
+
currentIndex,
|
|
212
|
+
setSelectedLayerByIndex,
|
|
213
|
+
clearOverrideLayers,
|
|
214
|
+
overrideSymbology,
|
|
215
|
+
]);
|
|
216
|
+
// Set selected layer on initial render and when story data changes
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
if ((storyData === null || storyData === void 0 ? void 0 : storyData.storySegments) && currentIndex >= 0) {
|
|
219
|
+
setSelectedLayerByIndex(currentIndex);
|
|
220
|
+
}
|
|
221
|
+
}, [storyData, currentIndex, setSelectedLayerByIndex]);
|
|
222
|
+
// Apply story presentation colors (specta) to panel root
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
if (!isSpecta || !(panelRef === null || panelRef === void 0 ? void 0 : panelRef.current)) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const container = panelRef.current;
|
|
228
|
+
const style = getSpectaPresentationStyle(storyData);
|
|
229
|
+
Object.entries(style).forEach(([key, value]) => {
|
|
230
|
+
if (value !== null) {
|
|
231
|
+
container.style.setProperty(key, String(value));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}, [storyData, isSpecta, panelRef]);
|
|
235
|
+
return {
|
|
236
|
+
storyData,
|
|
237
|
+
storySegments,
|
|
238
|
+
currentIndex,
|
|
239
|
+
clearOverrideLayers,
|
|
240
|
+
setIndex,
|
|
241
|
+
handlePrev,
|
|
242
|
+
handleNext,
|
|
243
|
+
hasPrev,
|
|
244
|
+
hasNext,
|
|
245
|
+
setSelectedLayerByIndex,
|
|
246
|
+
currentStorySegment,
|
|
247
|
+
activeSlide,
|
|
248
|
+
layerName,
|
|
249
|
+
currentStorySegmentId,
|
|
250
|
+
zoomToCurrentLayer,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
@@ -17,9 +17,9 @@ export type GdalFunctions = 'ogr2ogr' | 'gdal_rasterize' | 'gdalwarp' | 'gdal_tr
|
|
|
17
17
|
/**
|
|
18
18
|
* Generalized processing function for Buffer & Dissolve
|
|
19
19
|
*/
|
|
20
|
-
export declare function
|
|
20
|
+
export declare function processLayer(tracker: JupyterGISTracker, formSchemaRegistry: IJGISFormSchemaRegistry, processingType: ProcessingType, processingOptions: {
|
|
21
21
|
sqlQueryFn: (layerName: string, param: any) => string;
|
|
22
22
|
gdalFunction: GdalFunctions;
|
|
23
23
|
options: (sqlQuery: string) => string[];
|
|
24
|
-
}, app: JupyterFrontEnd): Promise<void>;
|
|
24
|
+
}, app: JupyterFrontEnd, filePath?: string, processingInputs?: Record<string, any>): Promise<void>;
|
|
25
25
|
export declare function executeSQLProcessing(model: IJupyterGISModel, geojsonString: string, gdalFunction: GdalFunctions, options: string[], layerNamePrefix: string, processingType: ProcessingType, embedOutputLayer: boolean, tracker: JupyterGISTracker, app: JupyterFrontEnd): Promise<void>;
|
package/lib/processing/index.js
CHANGED
|
@@ -52,48 +52,75 @@ export async function getLayerGeoJSON(layer, sources, model) {
|
|
|
52
52
|
/**
|
|
53
53
|
* Generalized processing function for Buffer & Dissolve
|
|
54
54
|
*/
|
|
55
|
-
export async function
|
|
56
|
-
var _a, _b, _c;
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
export async function processLayer(tracker, formSchemaRegistry, processingType, processingOptions, app, filePath, processingInputs) {
|
|
56
|
+
var _a, _b, _c, _d;
|
|
57
|
+
// Resolve widget
|
|
58
|
+
const widget = filePath
|
|
59
|
+
? tracker.find(w => w.model.filePath === filePath)
|
|
60
|
+
: tracker.currentWidget;
|
|
61
|
+
if (!widget) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const model = widget.model;
|
|
65
|
+
const sources = (_a = model.sharedModel.sources) !== null && _a !== void 0 ? _a : {};
|
|
66
|
+
const layers = (_b = model.sharedModel.layers) !== null && _b !== void 0 ? _b : {};
|
|
67
|
+
// Resolve layer
|
|
68
|
+
let selected = null;
|
|
69
|
+
if (processingInputs === null || processingInputs === void 0 ? void 0 : processingInputs.inputLayer) {
|
|
70
|
+
selected = layers[processingInputs.inputLayer];
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
selected = getSingleSelectedLayer(tracker);
|
|
74
|
+
}
|
|
75
|
+
if (!selected) {
|
|
59
76
|
return;
|
|
60
77
|
}
|
|
61
|
-
const model = tracker.currentWidget.model;
|
|
62
|
-
const sources = (_a = model === null || model === void 0 ? void 0 : model.sharedModel.sources) !== null && _a !== void 0 ? _a : {};
|
|
63
78
|
const geojsonString = await getLayerGeoJSON(selected, sources, model);
|
|
64
79
|
if (!geojsonString) {
|
|
65
80
|
return;
|
|
66
81
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
model,
|
|
75
|
-
sourceData: {
|
|
76
|
-
inputLayer: selectedLayerId,
|
|
77
|
-
outputLayerName: selected.name,
|
|
78
|
-
},
|
|
79
|
-
formContext: 'create',
|
|
80
|
-
processingType,
|
|
81
|
-
syncData: (props) => {
|
|
82
|
-
resolve(props);
|
|
83
|
-
dialog.dispose();
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
dialog.launch();
|
|
87
|
-
});
|
|
88
|
-
if (!formValues) {
|
|
89
|
-
return;
|
|
82
|
+
// Resolve params
|
|
83
|
+
let processParam;
|
|
84
|
+
let embedOutputLayer = true;
|
|
85
|
+
let outputLayerName = selected.name;
|
|
86
|
+
if (processingInputs) {
|
|
87
|
+
processParam = processingInputs;
|
|
88
|
+
outputLayerName = `${processingType} Layer`;
|
|
90
89
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
else {
|
|
91
|
+
const schema = Object.assign({}, formSchemaRegistry.getSchemas().get(processingType));
|
|
92
|
+
const selectedLayerId = Object.keys(((_d = (_c = model.sharedModel.awareness.getLocalState()) === null || _c === void 0 ? void 0 : _c.selected) === null || _d === void 0 ? void 0 : _d.value) || {})[0];
|
|
93
|
+
// Open ProcessingFormDialog
|
|
94
|
+
const formValues = await new Promise(resolve => {
|
|
95
|
+
const dialog = new ProcessingFormDialog({
|
|
96
|
+
title: processingType.charAt(0).toUpperCase() + processingType.slice(1),
|
|
97
|
+
schema,
|
|
98
|
+
model,
|
|
99
|
+
sourceData: {
|
|
100
|
+
inputLayer: selectedLayerId,
|
|
101
|
+
outputLayerName: selected.name,
|
|
102
|
+
},
|
|
103
|
+
formContext: 'create',
|
|
104
|
+
processingType,
|
|
105
|
+
syncData: (props) => {
|
|
106
|
+
resolve(props);
|
|
107
|
+
dialog.dispose();
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
dialog.launch();
|
|
111
|
+
});
|
|
112
|
+
if (!formValues) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (!processingList.includes(processingType)) {
|
|
116
|
+
console.error(`Unsupported processing type: ${processingType}`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
processParam = processingFormToParam(formValues, processingType);
|
|
120
|
+
embedOutputLayer = formValues.embedOutputLayer;
|
|
121
|
+
outputLayerName = formValues.outputLayerName;
|
|
94
122
|
}
|
|
95
|
-
|
|
96
|
-
const embedOutputLayer = formValues.embedOutputLayer;
|
|
123
|
+
// GDAL pre-processing
|
|
97
124
|
const fileBlob = new Blob([geojsonString], {
|
|
98
125
|
type: 'application/geo+json',
|
|
99
126
|
});
|
|
@@ -106,7 +133,7 @@ export async function processSelectedLayer(tracker, formSchemaRegistry, processi
|
|
|
106
133
|
const layerName = dataset.info.layers[0].name;
|
|
107
134
|
const sqlQuery = processingOptions.sqlQueryFn(layerName, processParam);
|
|
108
135
|
const fullOptions = processingOptions.options(sqlQuery);
|
|
109
|
-
await executeSQLProcessing(model, geojsonString, processingOptions.gdalFunction, fullOptions,
|
|
136
|
+
await executeSQLProcessing(model, geojsonString, processingOptions.gdalFunction, fullOptions, outputLayerName, processingType, embedOutputLayer, tracker, app);
|
|
110
137
|
}
|
|
111
138
|
export async function executeSQLProcessing(model, geojsonString, gdalFunction, options, layerNamePrefix, processingType, embedOutputLayer, tracker, app) {
|
|
112
139
|
var _a;
|
|
@@ -3,4 +3,4 @@ import { JupyterFrontEnd } from '@jupyterlab/application';
|
|
|
3
3
|
import { CommandRegistry } from '@lumino/commands';
|
|
4
4
|
import { JupyterGISTracker } from '../types';
|
|
5
5
|
export declare function replaceInSql(sql: string, keyToVal: IDict<string>, layerName: string): string;
|
|
6
|
-
export declare function addProcessingCommands(app: JupyterFrontEnd, commands: CommandRegistry, tracker: JupyterGISTracker, trans: any, formSchemaRegistry: IJGISFormSchemaRegistry): void;
|
|
6
|
+
export declare function addProcessingCommands(app: JupyterFrontEnd, commands: CommandRegistry, tracker: JupyterGISTracker, trans: any, formSchemaRegistry: IJGISFormSchemaRegistry, processingSchemas: Record<string, any>): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProcessingMerge, ProcessingLogicType, } from '@jupytergis/schema';
|
|
2
|
-
import { selectedLayerIsOfType,
|
|
2
|
+
import { selectedLayerIsOfType, processLayer } from './index';
|
|
3
3
|
export function replaceInSql(sql, keyToVal, layerName) {
|
|
4
4
|
const replaceTemplateString = (args) => args.template.replace(RegExp(`{${args.variableName}}`, 'g'), args.value);
|
|
5
5
|
let out = replaceTemplateString({
|
|
@@ -16,14 +16,34 @@ export function replaceInSql(sql, keyToVal, layerName) {
|
|
|
16
16
|
}
|
|
17
17
|
return out;
|
|
18
18
|
}
|
|
19
|
-
export function addProcessingCommands(app, commands, tracker, trans, formSchemaRegistry) {
|
|
19
|
+
export function addProcessingCommands(app, commands, tracker, trans, formSchemaRegistry, processingSchemas) {
|
|
20
20
|
for (const processingElement of ProcessingMerge) {
|
|
21
|
+
const schemaKey = Object.keys(processingSchemas).find(k => k.toLowerCase() === processingElement.name.toLowerCase());
|
|
22
|
+
if (!schemaKey) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
21
25
|
if (processingElement.type === ProcessingLogicType.vector) {
|
|
22
|
-
commands.addCommand(processingElement.name
|
|
26
|
+
commands.addCommand(`jupytergis:${processingElement.name}`, {
|
|
23
27
|
label: trans.__(processingElement.label),
|
|
28
|
+
describedBy: {
|
|
29
|
+
args: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
filePath: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'Path to the .jGIS file',
|
|
35
|
+
},
|
|
36
|
+
layerId: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'Layer ID to process',
|
|
39
|
+
},
|
|
40
|
+
params: processingSchemas[schemaKey],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
24
44
|
isEnabled: () => selectedLayerIsOfType(['VectorLayer'], tracker),
|
|
25
|
-
execute: async () => {
|
|
26
|
-
await
|
|
45
|
+
execute: async (args) => {
|
|
46
|
+
await processLayer(tracker, formSchemaRegistry, processingElement.description, {
|
|
27
47
|
sqlQueryFn: (layerName, keyToVal) => replaceInSql(processingElement.operations.sql, keyToVal, layerName),
|
|
28
48
|
gdalFunction: processingElement.operations.gdalFunction,
|
|
29
49
|
options: (sqlQuery) => [
|
|
@@ -35,7 +55,7 @@ export function addProcessingCommands(app, commands, tracker, trans, formSchemaR
|
|
|
35
55
|
sqlQuery,
|
|
36
56
|
'output.geojson',
|
|
37
57
|
],
|
|
38
|
-
}, app);
|
|
58
|
+
}, app, args === null || args === void 0 ? void 0 : args.filePath, args === null || args === void 0 ? void 0 : args.processingInputs);
|
|
39
59
|
},
|
|
40
60
|
});
|
|
41
61
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Collapsible as CollapsiblePrimitive } from 'radix-ui';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
declare function Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>): React.JSX.Element;
|
|
4
|
+
declare function CollapsibleTrigger({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>): React.JSX.Element;
|
|
5
|
+
declare function CollapsibleContent({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>): React.JSX.Element;
|
|
6
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { Collapsible as CollapsiblePrimitive } from 'radix-ui';
|
|
13
|
+
import * as React from 'react';
|
|
14
|
+
function Collapsible(_a) {
|
|
15
|
+
var props = __rest(_a, []);
|
|
16
|
+
return React.createElement(CollapsiblePrimitive.Root, Object.assign({ "data-slot": "collapsible" }, props));
|
|
17
|
+
}
|
|
18
|
+
function CollapsibleTrigger(_a) {
|
|
19
|
+
var props = __rest(_a, []);
|
|
20
|
+
return (React.createElement(CollapsiblePrimitive.CollapsibleTrigger, Object.assign({ "data-slot": "collapsible-trigger" }, props)));
|
|
21
|
+
}
|
|
22
|
+
function CollapsibleContent(_a) {
|
|
23
|
+
var props = __rest(_a, []);
|
|
24
|
+
return (React.createElement(CollapsiblePrimitive.CollapsibleContent, Object.assign({ "data-slot": "collapsible-content" }, props)));
|
|
25
|
+
}
|
|
26
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
interface ISpectaPresentationProgressBarProps {
|
|
4
|
+
model: IJupyterGISModel;
|
|
5
|
+
}
|
|
6
|
+
declare function SpectaPresentationProgressBar({ model, }: ISpectaPresentationProgressBarProps): React.JSX.Element;
|
|
7
|
+
export default SpectaPresentationProgressBar;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
function SpectaPresentationProgressBar({ model, }) {
|
|
3
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4
|
+
const segmentCount = (_c = (_b = (_a = model.getSelectedStory().story) === null || _a === void 0 ? void 0 : _a.storySegments) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0;
|
|
5
|
+
const [currentIndex, setCurrentIndex] = useState(() => { var _a; return Math.max(0, (_a = model.getCurrentSegmentIndex()) !== null && _a !== void 0 ? _a : 0); });
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const onIndexChanged = (_, index) => {
|
|
8
|
+
setCurrentIndex(Math.max(0, index !== null && index !== void 0 ? index : 0));
|
|
9
|
+
};
|
|
10
|
+
model.currentSegmentIndexChanged.connect(onIndexChanged);
|
|
11
|
+
return () => {
|
|
12
|
+
model.currentSegmentIndexChanged.disconnect(onIndexChanged);
|
|
13
|
+
};
|
|
14
|
+
}, [model]);
|
|
15
|
+
const safeCount = Math.max(0, segmentCount);
|
|
16
|
+
const clampedIndex = safeCount > 0 ? Math.min(currentIndex, safeCount - 1) : 0;
|
|
17
|
+
const prevIndexRef = useRef(clampedIndex);
|
|
18
|
+
const [direction, setDirection] = useState(null);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const prev = prevIndexRef.current;
|
|
21
|
+
if (clampedIndex !== prev) {
|
|
22
|
+
setDirection(clampedIndex > prev ? 'next' : 'prev');
|
|
23
|
+
prevIndexRef.current = clampedIndex;
|
|
24
|
+
}
|
|
25
|
+
}, [clampedIndex]);
|
|
26
|
+
const { story } = model.getSelectedStory();
|
|
27
|
+
const segmentIds = (_d = story === null || story === void 0 ? void 0 : story.storySegments) !== null && _d !== void 0 ? _d : [];
|
|
28
|
+
const currentSegmentId = segmentIds[clampedIndex];
|
|
29
|
+
const currentSegment = currentSegmentId
|
|
30
|
+
? model.getLayer(currentSegmentId)
|
|
31
|
+
: undefined;
|
|
32
|
+
const segmentParams = currentSegment === null || currentSegment === void 0 ? void 0 : currentSegment.parameters;
|
|
33
|
+
const transitionTime = (_f = (_e = segmentParams === null || segmentParams === void 0 ? void 0 : segmentParams.transition) === null || _e === void 0 ? void 0 : _e.time) !== null && _f !== void 0 ? _f : 0.3;
|
|
34
|
+
return (React.createElement("div", { className: "jgis-specta-progress", "data-direction": direction !== null && direction !== void 0 ? direction : undefined, style: {
|
|
35
|
+
'--jgis-specta-transition-duration': `${transitionTime}s`,
|
|
36
|
+
} },
|
|
37
|
+
React.createElement("div", { className: "jgis-specta-progress-bar" }, Array.from({ length: safeCount }, (_, i) => safeCount - 1 - i).map(segmentIndex => (React.createElement("div", { key: segmentIndex, className: "jgis-specta-bar-segment", "data-filled": segmentIndex <= clampedIndex ? '' : undefined, style: { '--segment-index': segmentIndex } },
|
|
38
|
+
React.createElement("button", { type: "button", className: "jgis-specta-progress-input", onClick: () => model.setCurrentSegmentIndex(segmentIndex), "aria-label": `Segment ${segmentIndex + 1} of ${safeCount}`, "aria-pressed": segmentIndex === clampedIndex })))))));
|
|
39
|
+
}
|
|
40
|
+
export default SpectaPresentationProgressBar;
|
package/lib/toolbar/widget.js
CHANGED
|
@@ -59,7 +59,7 @@ export class ToolbarWidget extends ReactiveToolbar {
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
this._model = options.model;
|
|
62
|
-
this.
|
|
62
|
+
this.node.classList.add('jGIS-toolbar-widget', 'data-jgis-keybinding');
|
|
63
63
|
// Listen for settings changes
|
|
64
64
|
this._model.settingsChanged.connect(this._onSettingsChanged, this);
|
|
65
65
|
// Listen for options change because it's the dependable signal
|
|
@@ -144,7 +144,9 @@ export class ToolbarWidget extends ReactiveToolbar {
|
|
|
144
144
|
});
|
|
145
145
|
this.addItem('Toggle console', toggleConsoleButton);
|
|
146
146
|
toggleConsoleButton.node.dataset.testid = 'toggle-console-button';
|
|
147
|
-
|
|
147
|
+
const spacer = ReactiveToolbar.createSpacerItem();
|
|
148
|
+
spacer.node.tabIndex = -1;
|
|
149
|
+
this.addItem('spacer', spacer);
|
|
148
150
|
// Users
|
|
149
151
|
const iconRenderer = createUserIconRenderer(this._model);
|
|
150
152
|
this.addItem('users', ReactWidget.create(React.createElement(UsersItem, { model: this._model, iconRenderer: iconRenderer })));
|
package/lib/tools.d.ts
CHANGED
|
@@ -135,4 +135,10 @@ export declare function getGeoJSONDataFromLayerSource(source: IJGISSource, model
|
|
|
135
135
|
* code when using it.
|
|
136
136
|
*/
|
|
137
137
|
export declare const objectEntries: <T extends Record<PropertyKey, unknown>>(obj: T) => Array<{ [K in keyof T]: [K, T[K]]; }[keyof T]>;
|
|
138
|
+
/**
|
|
139
|
+
* Extract the layerOverride array index from an RJSF idSchema (e.g. from $id like "root_layerOverride_0_sourceProperties").
|
|
140
|
+
*/
|
|
141
|
+
export declare function extractLayerOverrideIndex(idSchema: {
|
|
142
|
+
$id?: string;
|
|
143
|
+
}): number | undefined;
|
|
138
144
|
export {};
|
package/lib/tools.js
CHANGED
|
@@ -815,3 +815,12 @@ export async function getGeoJSONDataFromLayerSource(source, model) {
|
|
|
815
815
|
* code when using it.
|
|
816
816
|
*/
|
|
817
817
|
export const objectEntries = Object.entries;
|
|
818
|
+
/**
|
|
819
|
+
* Extract the layerOverride array index from an RJSF idSchema (e.g. from $id like "root_layerOverride_0_sourceProperties").
|
|
820
|
+
*/
|
|
821
|
+
export function extractLayerOverrideIndex(idSchema) {
|
|
822
|
+
var _a;
|
|
823
|
+
const id = (_a = idSchema === null || idSchema === void 0 ? void 0 : idSchema.$id) !== null && _a !== void 0 ? _a : '';
|
|
824
|
+
const match = id.match(/layerOverride_(\d+)/);
|
|
825
|
+
return match ? parseInt(match[1], 10) : undefined;
|
|
826
|
+
}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { IDict, IJupyterGISWidget } from '@jupytergis/schema';
|
|
2
|
-
import { WidgetTracker } from '@jupyterlab/apputils';
|
|
1
|
+
import { IDict, IJGISFormSchemaRegistry, IJupyterGISModel, IJupyterGISWidget } from '@jupytergis/schema';
|
|
2
|
+
import { Dialog, WidgetTracker } from '@jupyterlab/apputils';
|
|
3
|
+
import { Signal } from '@lumino/signaling';
|
|
4
|
+
import { RJSFSchema } from '@rjsf/utils';
|
|
3
5
|
import { Map } from 'ol';
|
|
4
6
|
export { IDict };
|
|
5
7
|
export type ValueOf<T> = T[keyof T];
|
|
@@ -28,3 +30,28 @@ declare global {
|
|
|
28
30
|
declare const classificationModes: readonly ["quantile", "equal interval", "jenks", "pretty", "logarithmic", "continuous"];
|
|
29
31
|
export type ClassificationMode = (typeof classificationModes)[number];
|
|
30
32
|
export declare const SYMBOLOGY_VALID_LAYER_TYPES: string[];
|
|
33
|
+
/** Form context passed to SchemaForm and custom fields. */
|
|
34
|
+
export interface IJupyterGISFormContext<TFormData = IDict | undefined> {
|
|
35
|
+
model: IJupyterGISModel;
|
|
36
|
+
formData: TFormData;
|
|
37
|
+
formSchemaRegistry?: IJGISFormSchemaRegistry;
|
|
38
|
+
}
|
|
39
|
+
/** Optional form state (schema, extraErrors). */
|
|
40
|
+
export interface IBaseFormStates {
|
|
41
|
+
schema?: RJSFSchema;
|
|
42
|
+
extraErrors?: any;
|
|
43
|
+
}
|
|
44
|
+
/** Base props for object forms (layer, source, processing, story editor). */
|
|
45
|
+
export interface IBaseFormProps {
|
|
46
|
+
formContext: 'update' | 'create';
|
|
47
|
+
sourceData: IDict | undefined;
|
|
48
|
+
filePath?: string;
|
|
49
|
+
model: IJupyterGISModel;
|
|
50
|
+
syncData: (properties: IDict) => void;
|
|
51
|
+
schema?: IDict;
|
|
52
|
+
ok?: Signal<Dialog<any>, number>;
|
|
53
|
+
cancel?: () => void;
|
|
54
|
+
formChangedSignal?: Signal<any, IDict<any>>;
|
|
55
|
+
formErrorSignal?: Signal<Dialog<any>, boolean>;
|
|
56
|
+
formSchemaRegistry?: IJGISFormSchemaRegistry;
|
|
57
|
+
}
|
package/lib/widget.js
CHANGED
|
@@ -70,10 +70,13 @@ export class JupyterGISPanel extends SplitPanel {
|
|
|
70
70
|
super({ orientation: 'vertical', spacing: 0 });
|
|
71
71
|
this._consoleOpened = false;
|
|
72
72
|
this._state = state;
|
|
73
|
-
this._initModel({ model, commandRegistry });
|
|
74
|
-
this._initView(formSchemaRegistry, annotationModel);
|
|
75
73
|
this._consoleOption = Object.assign({ commandRegistry }, consoleOption);
|
|
76
74
|
this._consoleTracker = consoleTracker;
|
|
75
|
+
const readyPromise = model.sharedModel.initialSyncReady;
|
|
76
|
+
readyPromise.then(() => {
|
|
77
|
+
this._initModel({ model, commandRegistry });
|
|
78
|
+
this._initView(formSchemaRegistry, annotationModel);
|
|
79
|
+
});
|
|
77
80
|
}
|
|
78
81
|
_initModel(options) {
|
|
79
82
|
this._view = new ObservableMap();
|
|
@@ -94,9 +97,15 @@ export class JupyterGISPanel extends SplitPanel {
|
|
|
94
97
|
SplitPanel.setStretch(this._jupyterGISMainViewPanel, 1);
|
|
95
98
|
}
|
|
96
99
|
get jupyterGISMainViewPanel() {
|
|
100
|
+
if (!this._jupyterGISMainViewPanel) {
|
|
101
|
+
console.warn('JupyterGISPanel not ready (initialSyncReady not resolved)');
|
|
102
|
+
}
|
|
97
103
|
return this._jupyterGISMainViewPanel;
|
|
98
104
|
}
|
|
99
105
|
get viewChanged() {
|
|
106
|
+
if (!this._view) {
|
|
107
|
+
console.warn('JupyterGISPanel not ready (initialSyncReady not resolved)');
|
|
108
|
+
}
|
|
100
109
|
return this._view.changed;
|
|
101
110
|
}
|
|
102
111
|
/**
|
|
@@ -114,6 +123,9 @@ export class JupyterGISPanel extends SplitPanel {
|
|
|
114
123
|
super.dispose();
|
|
115
124
|
}
|
|
116
125
|
get currentViewModel() {
|
|
126
|
+
if (!this._mainViewModel) {
|
|
127
|
+
console.warn('JupyterGISPanel not ready (initialSyncReady not resolved)');
|
|
128
|
+
}
|
|
117
129
|
return this._mainViewModel;
|
|
118
130
|
}
|
|
119
131
|
get consolePanel() {
|