@geode/opengeodeweb-front 10.29.1 → 10.30.0-rc.10
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/app/components/ClippingPlaneCard.vue +112 -0
- package/app/components/ClippingPlanes.vue +238 -0
- package/app/components/Launcher.vue +1 -1
- package/app/components/ObjectSelector.vue +26 -76
- package/app/components/ToolPanel.vue +3 -2
- package/app/components/ViewToolbar.vue +12 -0
- package/app/components/Viewer/ObjectTree/Base/TreeRow.vue +58 -20
- package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +42 -40
- package/app/composables/clipping_planes_widget.js +262 -0
- package/app/composables/hover_highlight.js +6 -0
- package/app/composables/project_manager.js +14 -11
- package/app/composables/use_overlapping_picker.js +15 -2
- package/app/stores/app.js +56 -11
- package/app/stores/back.js +10 -27
- package/app/stores/cloud.js +7 -1
- package/app/stores/data.js +32 -1
- package/app/stores/data_style.js +11 -0
- package/app/stores/hybrid_viewer.js +13 -5
- package/app/stores/infra.js +2 -7
- package/app/stores/viewer.js +9 -27
- package/app/utils/clipping_planes.js +110 -0
- package/app/utils/extension.js +30 -3
- package/app/utils/import_workflow.js +9 -12
- package/app/utils/log.js +18 -0
- package/app/utils/stores.js +32 -0
- package/internal/stores/hybrid_viewer.js +8 -63
- package/internal/stores/hybrid_viewer_brightness.js +62 -0
- package/internal/utils/api_fetch.js +27 -53
- package/internal/utils/upload_file.js +36 -29
- package/internal/utils/viewer_call.js +7 -2
- package/nuxt.config.js +2 -1
- package/package.json +4 -3
- package/server/api/local/{project_folder_path.post.js → app/project_folder_path.post.js} +1 -1
- package/server/api/local/{run_back.post.js → app/run_back.post.js} +1 -1
- package/server/api/local/{run_viewer.post.js → app/run_viewer.post.js} +1 -1
- package/server/api/{microservice → local}/extensions/upload.put.js +16 -37
- package/server/api/microservice/app/set_app_base_url.post.js +25 -0
- package/server/api/microservice/app/set_back_base_url.post.js +22 -0
- package/server/api/microservice/app/set_viewer_base_url.post.js +22 -0
- package/server/api/microservice/extensions/download.post.js +32 -0
- package/server/api/microservice/extensions/kill.post.js +3 -3
- package/server/api/microservice/extensions/run.post.js +5 -4
- package/server/api/serverless/{run_cloud.js → run_cloud.post.js} +1 -1
- package/{app/utils/config.js → server/utils/app_config.js} +28 -3
- package/{app/utils/local → server/utils}/path.js +1 -1
- package/{app/utils/local → server/utils}/scripts.js +5 -2
- package/server/utils/server_config.js +32 -0
- package/shared/scripts.js +56 -0
- package/shared/utils/fetch_raw.js +61 -0
- package/shared/utils/fetch_schema.js +46 -0
- package/shared/utils/file.js +16 -0
- package/shared/utils/response_handlers/load.js +74 -0
- package/tests/integration/setup.js +3 -3
- package/tests/integration/stores/data_style/mesh/cells.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/mesh/edges.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/mesh/index.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/mesh/points.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/mesh/polygons.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/mesh/polyhedra.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/blocks.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/corners.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/edges.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/index.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/lines.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/points.nuxt.test.js +1 -1
- package/tests/integration/stores/data_style/model/surfaces.nuxt.test.js +1 -1
- package/tests/integration/stores/viewer.nuxt.test.js +1 -1
- package/tests/unit/composables/project_manager.nuxt.test.js +14 -2
- package/tests/unit/composables/upload_file.nuxt.test.js +2 -2
- package/tests/unit/stores/back.nuxt.test.js +1 -1
- package/tests/unit/stores/cloud.nuxt.test.js +22 -20
- package/tests/unit/stores/data.nuxt.test.js +35 -0
- package/tests/unit/stores/infra.nuxt.test.js +13 -6
- package/tests/unit/stores/viewer.nuxt.test.js +1 -1
- package/tests/unit/utils/validate_schema.nuxt.test.js +1 -1
- package/tests/vitest.config.js +7 -5
- /package/server/api/local/{kill.post.js → app/kill.post.js} +0 -0
- /package/{app/utils/local → server/utils}/cleanup.js +0 -0
- /package/{app/utils/local → server/utils}/microservices.js +0 -0
- /package/{app → server}/utils/server.js +0 -0
- /package/{app/utils/local → shared}/app_mode.js +0 -0
- /package/{app → shared}/utils/validate_schema.js +0 -0
|
@@ -179,46 +179,48 @@ function expandAll() {
|
|
|
179
179
|
</template>
|
|
180
180
|
|
|
181
181
|
<template #append="{ item }">
|
|
182
|
-
<v-
|
|
183
|
-
v-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
v-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
v-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
182
|
+
<template v-if="item.geode_object_type !== 'HorizonStack3D'">
|
|
183
|
+
<v-btn
|
|
184
|
+
v-if="item.viewer_type"
|
|
185
|
+
icon="mdi-target"
|
|
186
|
+
size="medium"
|
|
187
|
+
variant="text"
|
|
188
|
+
v-tooltip="'Focus camera on object'"
|
|
189
|
+
@click.stop="hybridViewerStore.focusCameraOnObject(item.id)"
|
|
190
|
+
/>
|
|
191
|
+
<v-btn
|
|
192
|
+
v-if="isModel(item)"
|
|
193
|
+
icon="mdi-magnify-expand"
|
|
194
|
+
size="medium"
|
|
195
|
+
class="ml-2"
|
|
196
|
+
variant="text"
|
|
197
|
+
v-tooltip="'Model\'s mesh components'"
|
|
198
|
+
@click.stop="
|
|
199
|
+
treeviewStore.displayAdditionalTree(
|
|
200
|
+
item.id,
|
|
201
|
+
item.title,
|
|
202
|
+
item.geode_object_type,
|
|
203
|
+
'model_components',
|
|
204
|
+
)
|
|
205
|
+
"
|
|
206
|
+
/>
|
|
207
|
+
<v-btn
|
|
208
|
+
v-if="isModel(item) && hasCollectionsMap[item.id]"
|
|
209
|
+
icon="mdi-format-list-group"
|
|
210
|
+
size="medium"
|
|
211
|
+
class="ml-2"
|
|
212
|
+
variant="text"
|
|
213
|
+
v-tooltip="'Model\'s collections'"
|
|
214
|
+
@click.stop="
|
|
215
|
+
treeviewStore.displayAdditionalTree(
|
|
216
|
+
item.id,
|
|
217
|
+
item.title,
|
|
218
|
+
item.geode_object_type,
|
|
219
|
+
'model_collections',
|
|
220
|
+
)
|
|
221
|
+
"
|
|
222
|
+
/>
|
|
223
|
+
</template>
|
|
222
224
|
</template>
|
|
223
225
|
</CommonTreeView>
|
|
224
226
|
</div>
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AXIS_SCALE,
|
|
3
|
+
CHANGE_THRESHOLD,
|
|
4
|
+
PLANE_COLORS,
|
|
5
|
+
SIZE_RATIO,
|
|
6
|
+
computeSceneBoundsInfo,
|
|
7
|
+
getPlaneStyle,
|
|
8
|
+
hasPlaneChanged,
|
|
9
|
+
} from "@ogw_front/utils/clipping_planes";
|
|
10
|
+
import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
|
|
11
|
+
import { newInstance as vtkImplicitPlaneWidget } from "@kitware/vtk.js/Widgets/Widgets3D/ImplicitPlaneWidget";
|
|
12
|
+
import { newInstance as vtkWidgetManager } from "@kitware/vtk.js/Widgets/Core/WidgetManager";
|
|
13
|
+
|
|
14
|
+
// oxlint-disable-next-line max-params max-lines-per-function
|
|
15
|
+
function useClippingPlanesWidget({
|
|
16
|
+
planes,
|
|
17
|
+
targetAllVisible,
|
|
18
|
+
selectedDatasetIds,
|
|
19
|
+
allItems,
|
|
20
|
+
hybridViewerStore,
|
|
21
|
+
debouncedApply,
|
|
22
|
+
}) {
|
|
23
|
+
let localRenderWindow = undefined;
|
|
24
|
+
let widgetManager = undefined;
|
|
25
|
+
let widgetEntries = [];
|
|
26
|
+
let fromWidget = false;
|
|
27
|
+
let maxDistance = 0;
|
|
28
|
+
let isLimitingCameraZoom = false;
|
|
29
|
+
|
|
30
|
+
function resolveActiveActors() {
|
|
31
|
+
const targetIds = targetAllVisible.value
|
|
32
|
+
? allItems.value.map((item) => item.id)
|
|
33
|
+
: selectedDatasetIds.value;
|
|
34
|
+
const targeted = targetIds
|
|
35
|
+
.map((id) => {
|
|
36
|
+
const item = hybridViewerStore.hybridDb[id];
|
|
37
|
+
return item ? item.actor : undefined;
|
|
38
|
+
})
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
if (targeted.length > 0) {
|
|
41
|
+
return targeted;
|
|
42
|
+
}
|
|
43
|
+
return Object.values(hybridViewerStore.hybridDb)
|
|
44
|
+
.map((entry) => entry && entry.actor)
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getSceneBoundsInfo() {
|
|
49
|
+
return computeSceneBoundsInfo(resolveActiveActors());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getSceneCenter() {
|
|
53
|
+
return getSceneBoundsInfo().center;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createWidgetEntry(planeWidget, widgetHandle, planeIndex) {
|
|
57
|
+
const widgetState = planeWidget.getWidgetState();
|
|
58
|
+
const plane = planes.value[planeIndex];
|
|
59
|
+
if (plane.origin) {
|
|
60
|
+
widgetState.setOrigin(plane.origin);
|
|
61
|
+
}
|
|
62
|
+
widgetState.setNormal(plane.normal);
|
|
63
|
+
const subscription = widgetState.onModified(() => {
|
|
64
|
+
if (fromWidget) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const origin = widgetState.getOrigin().map((val) => Number(val.toFixed(4)));
|
|
68
|
+
const normal = widgetState.getNormal().map((val) => Number(val.toFixed(4)));
|
|
69
|
+
if (
|
|
70
|
+
!hasPlaneChanged(
|
|
71
|
+
origin,
|
|
72
|
+
normal,
|
|
73
|
+
planes.value[planeIndex].origin,
|
|
74
|
+
planes.value[planeIndex].normal,
|
|
75
|
+
)
|
|
76
|
+
) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
fromWidget = true;
|
|
80
|
+
planes.value[planeIndex].origin = origin;
|
|
81
|
+
planes.value[planeIndex].normal = normal;
|
|
82
|
+
nextTick(() => {
|
|
83
|
+
fromWidget = false;
|
|
84
|
+
});
|
|
85
|
+
debouncedApply();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return { planeWidget, widgetHandle, subscription };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function syncWidgets() {
|
|
92
|
+
if (!widgetManager || !localRenderWindow) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
while (widgetEntries.length > planes.value.length) {
|
|
96
|
+
const entry = widgetEntries.pop();
|
|
97
|
+
entry.subscription.unsubscribe();
|
|
98
|
+
widgetManager.removeWidget(entry.planeWidget);
|
|
99
|
+
entry.planeWidget.delete();
|
|
100
|
+
}
|
|
101
|
+
const { cubicBounds } = getSceneBoundsInfo();
|
|
102
|
+
for (const [idx, plane] of planes.value.entries()) {
|
|
103
|
+
const rgb = PLANE_COLORS[idx % PLANE_COLORS.length];
|
|
104
|
+
if (!widgetEntries[idx]) {
|
|
105
|
+
const planeWidget = vtkImplicitPlaneWidget();
|
|
106
|
+
const widgetHandle = widgetManager.addWidget(planeWidget);
|
|
107
|
+
widgetHandle.setAxisScale(AXIS_SCALE);
|
|
108
|
+
widgetHandle.setHandleSizeRatio(SIZE_RATIO);
|
|
109
|
+
widgetEntries.push(createWidgetEntry(planeWidget, widgetHandle, idx));
|
|
110
|
+
}
|
|
111
|
+
const entry = widgetEntries[idx];
|
|
112
|
+
entry.widgetHandle.setRepresentationStyle(getPlaneStyle(rgb));
|
|
113
|
+
fromWidget = true;
|
|
114
|
+
entry.widgetHandle.placeWidget(cubicBounds);
|
|
115
|
+
fromWidget = false;
|
|
116
|
+
entry.widgetHandle.setAxisScale(AXIS_SCALE);
|
|
117
|
+
entry.widgetHandle.setHandleSizeRatio(SIZE_RATIO);
|
|
118
|
+
const widgetState = entry.planeWidget.getWidgetState();
|
|
119
|
+
if (plane.origin) {
|
|
120
|
+
widgetState.setOrigin(plane.origin);
|
|
121
|
+
}
|
|
122
|
+
widgetState.setNormal(plane.normal);
|
|
123
|
+
}
|
|
124
|
+
localRenderWindow.getRenderWindow().render();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function limitCameraZoomOut(camera) {
|
|
128
|
+
if (maxDistance <= 0 || isLimitingCameraZoom) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const currentDist = camera.getDistance();
|
|
133
|
+
if (currentDist <= maxDistance + CHANGE_THRESHOLD) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
isLimitingCameraZoom = true;
|
|
138
|
+
const focal = camera.getFocalPoint();
|
|
139
|
+
const pos = camera.getPosition();
|
|
140
|
+
const ratio = maxDistance / currentDist;
|
|
141
|
+
|
|
142
|
+
camera.setPosition(
|
|
143
|
+
focal[0] + (pos[0] - focal[0]) * ratio,
|
|
144
|
+
focal[1] + (pos[1] - focal[1]) * ratio,
|
|
145
|
+
focal[2] + (pos[2] - focal[2]) * ratio,
|
|
146
|
+
);
|
|
147
|
+
localRenderWindow.getRenderWindow().render();
|
|
148
|
+
isLimitingCameraZoom = false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function syncLocalCamera() {
|
|
152
|
+
if (!localRenderWindow) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const renderer = localRenderWindow.getRenderer();
|
|
156
|
+
const camera = renderer.getActiveCamera();
|
|
157
|
+
const mainCam = hybridViewerStore.camera_options;
|
|
158
|
+
const { center, cubicBounds } = getSceneBoundsInfo();
|
|
159
|
+
renderer.resetCamera(cubicBounds);
|
|
160
|
+
if (mainCam && mainCam.focal_point && mainCam.position) {
|
|
161
|
+
const dir = [
|
|
162
|
+
mainCam.position[0] - mainCam.focal_point[0],
|
|
163
|
+
mainCam.position[1] - mainCam.focal_point[1],
|
|
164
|
+
mainCam.position[2] - mainCam.focal_point[2],
|
|
165
|
+
];
|
|
166
|
+
const dirLen = Math.hypot(...dir);
|
|
167
|
+
if (dirLen > 0) {
|
|
168
|
+
const distance = camera.getDistance();
|
|
169
|
+
const normDir = dir.map((component) => component / dirLen);
|
|
170
|
+
camera.setFocalPoint(...center);
|
|
171
|
+
camera.setPosition(
|
|
172
|
+
center[0] + normDir[0] * distance,
|
|
173
|
+
center[1] + normDir[1] * distance,
|
|
174
|
+
center[2] + normDir[2] * distance,
|
|
175
|
+
);
|
|
176
|
+
if (mainCam.view_up) {
|
|
177
|
+
camera.setViewUp(...mainCam.view_up);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
limitCameraZoomOut(camera);
|
|
183
|
+
localRenderWindow.getRenderWindow().render();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function cleanupLocalWidget() {
|
|
187
|
+
maxDistance = 0;
|
|
188
|
+
isLimitingCameraZoom = false;
|
|
189
|
+
for (const entry of widgetEntries) {
|
|
190
|
+
entry.subscription.unsubscribe();
|
|
191
|
+
if (widgetManager) {
|
|
192
|
+
widgetManager.removeWidget(entry.planeWidget);
|
|
193
|
+
}
|
|
194
|
+
entry.planeWidget.delete();
|
|
195
|
+
}
|
|
196
|
+
widgetEntries = [];
|
|
197
|
+
if (localRenderWindow) {
|
|
198
|
+
localRenderWindow.delete();
|
|
199
|
+
localRenderWindow = undefined;
|
|
200
|
+
widgetManager = undefined;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function initLocalWidget(container) {
|
|
205
|
+
cleanupLocalWidget();
|
|
206
|
+
container.addEventListener("wheel", (event) => event.stopPropagation(), { passive: true });
|
|
207
|
+
localRenderWindow = vtkGenericRenderWindow({
|
|
208
|
+
background: [0, 0, 0, 0],
|
|
209
|
+
listenWindowResize: false,
|
|
210
|
+
});
|
|
211
|
+
localRenderWindow.setContainer(container);
|
|
212
|
+
const camera = localRenderWindow.getRenderer().getActiveCamera();
|
|
213
|
+
camera.onModified(() => limitCameraZoomOut(camera));
|
|
214
|
+
const canvas = localRenderWindow.getApiSpecificRenderWindow().getCanvas();
|
|
215
|
+
Object.assign(canvas.style, { width: "100%", height: "100%", background: "transparent" });
|
|
216
|
+
localRenderWindow.resize();
|
|
217
|
+
widgetManager = vtkWidgetManager();
|
|
218
|
+
widgetManager.setRenderer(localRenderWindow.getRenderer());
|
|
219
|
+
updateWidgetPlacement();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function updateWidgetPlacement({ isReset = false } = {}) {
|
|
223
|
+
if (!widgetManager || !localRenderWindow) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (isReset) {
|
|
227
|
+
maxDistance = 0;
|
|
228
|
+
}
|
|
229
|
+
const center = getSceneCenter();
|
|
230
|
+
for (const plane of planes.value) {
|
|
231
|
+
if (!plane.origin || isReset) {
|
|
232
|
+
plane.origin = [...center];
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
syncWidgets();
|
|
236
|
+
syncLocalCamera();
|
|
237
|
+
if (maxDistance <= 0) {
|
|
238
|
+
maxDistance = localRenderWindow.getRenderer().getActiveCamera().getDistance();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function isFromWidget() {
|
|
243
|
+
return fromWidget;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function setFromWidget(value) {
|
|
247
|
+
fromWidget = value;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
getSceneCenter,
|
|
252
|
+
syncWidgets,
|
|
253
|
+
syncLocalCamera,
|
|
254
|
+
cleanupLocalWidget,
|
|
255
|
+
initLocalWidget,
|
|
256
|
+
updateWidgetPlacement,
|
|
257
|
+
isFromWidget,
|
|
258
|
+
setFromWidget,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { useClippingPlanesWidget };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
1
2
|
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
2
3
|
import vtk_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
3
4
|
|
|
@@ -5,6 +6,7 @@ const HOVER_DELAY = 200;
|
|
|
5
6
|
|
|
6
7
|
export function useHoverhighlight() {
|
|
7
8
|
const viewerStore = useViewerStore();
|
|
9
|
+
const dataStore = useDataStore();
|
|
8
10
|
let timer = undefined;
|
|
9
11
|
let currentId = undefined;
|
|
10
12
|
let currentType = undefined;
|
|
@@ -20,6 +22,10 @@ export function useHoverhighlight() {
|
|
|
20
22
|
currentId = id;
|
|
21
23
|
currentType = type;
|
|
22
24
|
|
|
25
|
+
if (!(await dataStore.isItemViewable(id))) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
let block_ids = [];
|
|
24
30
|
if (typeof block_ids_provider === "function") {
|
|
25
31
|
block_ids = await block_ids_provider();
|
|
@@ -2,8 +2,8 @@ import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.jso
|
|
|
2
2
|
import fileDownload from "js-file-download";
|
|
3
3
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
4
4
|
|
|
5
|
+
import { fetchRaw } from "@ogw_shared/utils/fetch_raw";
|
|
5
6
|
import { importWorkflowFromSnapshot } from "@ogw_front/utils/import_workflow";
|
|
6
|
-
|
|
7
7
|
import { useAppStore } from "@ogw_front/stores/app";
|
|
8
8
|
import { useBackStore } from "@ogw_front/stores/back";
|
|
9
9
|
import { useDataStore } from "@ogw_front/stores/data";
|
|
@@ -21,12 +21,14 @@ async function exportProject() {
|
|
|
21
21
|
const snapshot = await appStore.exportStores();
|
|
22
22
|
const schema = back_schemas.opengeodeweb_back.export_project;
|
|
23
23
|
const defaultName = "project.vease";
|
|
24
|
-
|
|
25
|
-
const result = await
|
|
24
|
+
const params = { snapshot, filename: defaultName };
|
|
25
|
+
const result = await fetchRaw({
|
|
26
|
+
route: schema.$id,
|
|
27
|
+
params,
|
|
28
|
+
method: schema.methods[0],
|
|
26
29
|
baseURL: backStore.base_url,
|
|
27
|
-
method: schema.methods.find((method) => method !== "OPTIONS"),
|
|
28
|
-
body: { snapshot, filename: defaultName },
|
|
29
30
|
});
|
|
31
|
+
|
|
30
32
|
fileDownload(result, defaultName);
|
|
31
33
|
feedbackStore.add_success("Project exported successfully");
|
|
32
34
|
return { result };
|
|
@@ -46,15 +48,15 @@ async function importProject(file) {
|
|
|
46
48
|
if (client && client.getConnection && client.getConnection().getSession) {
|
|
47
49
|
await client.getConnection().getSession().call("opengeodeweb_viewer.release_database", [{}]);
|
|
48
50
|
}
|
|
49
|
-
const
|
|
51
|
+
const resetVisualizationSchema = viewer_schemas.opengeodeweb_viewer.viewer.reset_visualization;
|
|
50
52
|
const timeout = undefined;
|
|
51
|
-
await viewerStore.request({ schema, timeout });
|
|
53
|
+
await viewerStore.request({ schema: resetVisualizationSchema, timeout });
|
|
52
54
|
|
|
53
55
|
treeviewStore.clear();
|
|
54
56
|
dataStore.clear();
|
|
55
57
|
hybridViewerStore.clear();
|
|
56
58
|
|
|
57
|
-
const
|
|
59
|
+
const importProjectSchema = back_schemas.opengeodeweb_back.import_project;
|
|
58
60
|
const form = new FormData();
|
|
59
61
|
const originalFileName = file && file.name ? file.name : "project.vease";
|
|
60
62
|
if (!originalFileName.toLowerCase().endsWith(".vease")) {
|
|
@@ -62,10 +64,11 @@ async function importProject(file) {
|
|
|
62
64
|
}
|
|
63
65
|
form.append("file", file, originalFileName);
|
|
64
66
|
|
|
65
|
-
const result = await
|
|
67
|
+
const result = await fetchRaw({
|
|
68
|
+
route: importProjectSchema.$id,
|
|
69
|
+
params: form,
|
|
70
|
+
method: importProjectSchema.methods[0],
|
|
66
71
|
baseURL: backStore.base_url,
|
|
67
|
-
method: "POST",
|
|
68
|
-
body: form,
|
|
69
72
|
});
|
|
70
73
|
const snapshot = result && result.snapshot ? result.snapshot : {};
|
|
71
74
|
|
|
@@ -64,8 +64,21 @@ export function useOverlappingPicker() {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
async function get_viewer_id({ x, y, containerWidth, containerHeight, containerRect }) {
|
|
67
|
-
const activeIds = new Set(dataItems.value.map((
|
|
68
|
-
const
|
|
67
|
+
const activeIds = new Set(dataItems.value.map((i) => i.id));
|
|
68
|
+
const visibleStyleIds = Object.keys(dataStyleStore.styles).filter(
|
|
69
|
+
(styleId) => activeIds.has(styleId) && dataStyleStore.objectVisibility(styleId),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const viewableChecks = await Promise.all(
|
|
73
|
+
visibleStyleIds.map(async (styleId) => {
|
|
74
|
+
try {
|
|
75
|
+
return (await dataStore.isItemViewable(styleId)) ? styleId : undefined;
|
|
76
|
+
} catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
const ids = viewableChecks.filter(Boolean);
|
|
69
82
|
|
|
70
83
|
const result = { id: undefined, viewer_id: undefined };
|
|
71
84
|
let pickedResponse = undefined;
|
package/app/stores/app.js
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
// Local imports
|
|
2
|
+
import { getRestApiPort, getRestApiProtocol, isCloudMode } from "@ogw_front/utils/stores.js";
|
|
3
|
+
import { Status } from "@ogw_front/utils/status";
|
|
2
4
|
import { api_fetch } from "@ogw_internal/utils/api_fetch.js";
|
|
3
|
-
import { upload_file } from "@ogw_internal/utils/upload_file.js";
|
|
4
|
-
|
|
5
5
|
import { killExtension } from "@ogw_front/utils/extension.js";
|
|
6
|
+
import { upload_file } from "@ogw_internal/utils/upload_file.js";
|
|
6
7
|
import { useInfraStore } from "@ogw_front/stores/infra";
|
|
7
8
|
|
|
8
9
|
// oxlint-disable-next-line max-lines-per-function, max-statements
|
|
9
10
|
export const useAppStore = defineStore("app", () => {
|
|
10
11
|
const stores = [];
|
|
12
|
+
const globalComponents = ref(new Map());
|
|
13
|
+
const default_local_port = ref(globalThis.location.port);
|
|
14
|
+
const status = ref(Status.NOT_CONNECTED);
|
|
15
|
+
const protocol = computed(() => getRestApiProtocol());
|
|
16
|
+
const port = computed(() => getRestApiPort(default_local_port.value));
|
|
17
|
+
|
|
18
|
+
const base_url = computed(() => {
|
|
19
|
+
const infraStore = useInfraStore();
|
|
20
|
+
let app_url = `${protocol.value}://${infraStore.domain_name}:${port.value}`;
|
|
21
|
+
if (isCloudMode()) {
|
|
22
|
+
app_url += `/server`;
|
|
23
|
+
}
|
|
24
|
+
return app_url;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function registerGlobalComponent(extensionId, componentId, component) {
|
|
28
|
+
if (!globalComponents.value.has(extensionId)) {
|
|
29
|
+
globalComponents.value.set(extensionId, new Map());
|
|
30
|
+
}
|
|
31
|
+
globalComponents.value.get(extensionId).set(componentId, component);
|
|
32
|
+
console.log(
|
|
33
|
+
`[AppStore] Registered global component ${componentId} for extension ${extensionId}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function unregisterGlobalComponent(extensionId, componentId) {
|
|
38
|
+
if (globalComponents.value.has(extensionId)) {
|
|
39
|
+
globalComponents.value.get(extensionId).delete(componentId);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
11
42
|
|
|
12
43
|
function registerStore(store) {
|
|
13
44
|
const isAlreadyRegistered = stores.some((registeredStore) => registeredStore.$id === store.$id);
|
|
@@ -91,7 +122,7 @@ export const useAppStore = defineStore("app", () => {
|
|
|
91
122
|
return loadedExtensions.value.get(id);
|
|
92
123
|
}
|
|
93
124
|
|
|
94
|
-
async function loadExtension(path,
|
|
125
|
+
async function loadExtension(path, extensionPort, backendPath = undefined) {
|
|
95
126
|
try {
|
|
96
127
|
let finalURL = path;
|
|
97
128
|
|
|
@@ -108,7 +139,7 @@ export const useAppStore = defineStore("app", () => {
|
|
|
108
139
|
// oxlint-disable-next-line no-inline-comments
|
|
109
140
|
const extensionModule = await import(/* @vite-ignore */ finalURL);
|
|
110
141
|
const store = extensionModule.metadata.store();
|
|
111
|
-
store.$patch({ default_local_port:
|
|
142
|
+
store.$patch({ default_local_port: extensionPort });
|
|
112
143
|
|
|
113
144
|
if (finalURL !== path && finalURL.startsWith("blob:")) {
|
|
114
145
|
URL.revokeObjectURL(finalURL);
|
|
@@ -196,11 +227,16 @@ export const useAppStore = defineStore("app", () => {
|
|
|
196
227
|
}
|
|
197
228
|
|
|
198
229
|
function upload(file, callbacks = {}) {
|
|
199
|
-
const
|
|
230
|
+
const schema = {
|
|
231
|
+
$id: "/api/local/extensions/upload",
|
|
232
|
+
methods: ["OPTIONS", "PUT"],
|
|
233
|
+
};
|
|
200
234
|
const store = useAppStore();
|
|
235
|
+
const { PROJECT: projectName } = useRuntimeConfig().public;
|
|
236
|
+
const params = { projectName };
|
|
201
237
|
return upload_file(
|
|
202
238
|
store,
|
|
203
|
-
{
|
|
239
|
+
{ schema, file, params },
|
|
204
240
|
{
|
|
205
241
|
...callbacks,
|
|
206
242
|
response_function: async (response) => {
|
|
@@ -214,16 +250,13 @@ export const useAppStore = defineStore("app", () => {
|
|
|
214
250
|
}
|
|
215
251
|
|
|
216
252
|
function request({ schema, params }, callbacks = {}) {
|
|
217
|
-
console.log("[APP] Request:", schema.$id);
|
|
218
|
-
|
|
219
253
|
const store = useAppStore();
|
|
220
254
|
return api_fetch(
|
|
221
255
|
store,
|
|
222
|
-
{ schema, params
|
|
256
|
+
{ schema, params },
|
|
223
257
|
{
|
|
224
258
|
...callbacks,
|
|
225
259
|
response_function: async (response) => {
|
|
226
|
-
console.log("[APP] Request completed:", schema.$id);
|
|
227
260
|
if (callbacks.response_function) {
|
|
228
261
|
await callbacks.response_function(response);
|
|
229
262
|
}
|
|
@@ -239,12 +272,14 @@ export const useAppStore = defineStore("app", () => {
|
|
|
239
272
|
function stop_request() {
|
|
240
273
|
request_counter.value -= 1;
|
|
241
274
|
}
|
|
275
|
+
const is_busy = computed(() => request_counter.value > 0);
|
|
242
276
|
|
|
243
277
|
const projectFolderPath = ref("");
|
|
278
|
+
|
|
244
279
|
function createProjectFolder() {
|
|
245
280
|
const { PROJECT } = useRuntimeConfig().public;
|
|
246
281
|
const schema = {
|
|
247
|
-
$id: "/api/local/project_folder_path",
|
|
282
|
+
$id: "/api/local/app/project_folder_path",
|
|
248
283
|
methods: ["POST"],
|
|
249
284
|
type: "object",
|
|
250
285
|
properties: { PROJECT: { type: "string" } },
|
|
@@ -265,6 +300,13 @@ export const useAppStore = defineStore("app", () => {
|
|
|
265
300
|
|
|
266
301
|
return {
|
|
267
302
|
stores,
|
|
303
|
+
default_local_port,
|
|
304
|
+
request_counter,
|
|
305
|
+
status,
|
|
306
|
+
protocol,
|
|
307
|
+
port,
|
|
308
|
+
base_url,
|
|
309
|
+
is_busy,
|
|
268
310
|
registerStore,
|
|
269
311
|
exportStores,
|
|
270
312
|
importStores,
|
|
@@ -285,5 +327,8 @@ export const useAppStore = defineStore("app", () => {
|
|
|
285
327
|
createProjectFolder,
|
|
286
328
|
start_request,
|
|
287
329
|
stop_request,
|
|
330
|
+
globalComponents,
|
|
331
|
+
registerGlobalComponent,
|
|
332
|
+
unregisterGlobalComponent,
|
|
288
333
|
};
|
|
289
334
|
});
|
package/app/stores/back.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { getRestApiPort, getRestApiProtocol, isCloudMode } from "@ogw_front/utils/stores";
|
|
1
2
|
import { Status } from "@ogw_front/utils/status";
|
|
2
3
|
import { api_fetch } from "@ogw_internal/utils/api_fetch";
|
|
3
|
-
import { appMode } from "@ogw_front/utils/local/app_mode";
|
|
4
4
|
import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json";
|
|
5
5
|
import { upload_file } from "@ogw_internal/utils/upload_file.js";
|
|
6
6
|
import { useAppStore } from "@ogw_front/stores/app";
|
|
@@ -19,24 +19,18 @@ export const useBackStore = defineStore("back", {
|
|
|
19
19
|
}),
|
|
20
20
|
getters: {
|
|
21
21
|
protocol() {
|
|
22
|
-
|
|
23
|
-
return "https";
|
|
24
|
-
}
|
|
25
|
-
return "http";
|
|
22
|
+
return getRestApiProtocol();
|
|
26
23
|
},
|
|
27
24
|
port() {
|
|
28
|
-
|
|
29
|
-
return "443";
|
|
30
|
-
}
|
|
31
|
-
return this.default_local_port;
|
|
25
|
+
return getRestApiPort(this.default_local_port);
|
|
32
26
|
},
|
|
33
27
|
base_url() {
|
|
34
28
|
const infraStore = useInfraStore();
|
|
35
|
-
let
|
|
36
|
-
if (
|
|
37
|
-
|
|
29
|
+
let back_url = `${this.protocol}://${infraStore.domain_name}:${this.port}`;
|
|
30
|
+
if (isCloudMode()) {
|
|
31
|
+
back_url += `/geode`;
|
|
38
32
|
}
|
|
39
|
-
return
|
|
33
|
+
return back_url;
|
|
40
34
|
},
|
|
41
35
|
is_busy() {
|
|
42
36
|
return this.request_counter > 0;
|
|
@@ -81,7 +75,7 @@ export const useBackStore = defineStore("back", {
|
|
|
81
75
|
const appStore = useAppStore();
|
|
82
76
|
const { COMMAND_BACK, NUXT_ROOT_PATH } = useRuntimeConfig().public;
|
|
83
77
|
const schema = {
|
|
84
|
-
$id: "/api/local/run_back",
|
|
78
|
+
$id: "/api/local/app/run_back",
|
|
85
79
|
methods: ["POST"],
|
|
86
80
|
type: "object",
|
|
87
81
|
properties: {
|
|
@@ -110,22 +104,12 @@ export const useBackStore = defineStore("back", {
|
|
|
110
104
|
return Promise.resolve();
|
|
111
105
|
},
|
|
112
106
|
request({ schema, params = {} }, callbacks = {}) {
|
|
113
|
-
console.log("[GEODE] Request:", schema.$id);
|
|
114
|
-
const start = Date.now();
|
|
115
|
-
|
|
116
107
|
return api_fetch(
|
|
117
108
|
this,
|
|
118
109
|
{ schema, params, headers: {} },
|
|
119
110
|
{
|
|
120
111
|
...callbacks,
|
|
121
112
|
response_function: async (response) => {
|
|
122
|
-
console.log(
|
|
123
|
-
"[GEODE] Request completed:",
|
|
124
|
-
schema.$id,
|
|
125
|
-
"in",
|
|
126
|
-
(Date.now() - start) / MILLISECONDS_IN_SECOND,
|
|
127
|
-
"s",
|
|
128
|
-
);
|
|
129
113
|
if (callbacks.response_function) {
|
|
130
114
|
await callbacks.response_function(response);
|
|
131
115
|
}
|
|
@@ -134,17 +118,16 @@ export const useBackStore = defineStore("back", {
|
|
|
134
118
|
);
|
|
135
119
|
},
|
|
136
120
|
upload(file, callbacks = {}) {
|
|
137
|
-
const
|
|
121
|
+
const schema = back_schemas.opengeodeweb_back.upload_file;
|
|
138
122
|
return upload_file(
|
|
139
123
|
this,
|
|
140
124
|
{
|
|
141
|
-
|
|
125
|
+
schema,
|
|
142
126
|
file,
|
|
143
127
|
},
|
|
144
128
|
{
|
|
145
129
|
...callbacks,
|
|
146
130
|
response_function: async (response) => {
|
|
147
|
-
console.log("[GEODE] Request completed:", route);
|
|
148
131
|
if (callbacks.response_function) {
|
|
149
132
|
await callbacks.response_function(response);
|
|
150
133
|
}
|