@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.
Files changed (82) hide show
  1. package/app/components/ClippingPlaneCard.vue +112 -0
  2. package/app/components/ClippingPlanes.vue +238 -0
  3. package/app/components/Launcher.vue +1 -1
  4. package/app/components/ObjectSelector.vue +26 -76
  5. package/app/components/ToolPanel.vue +3 -2
  6. package/app/components/ViewToolbar.vue +12 -0
  7. package/app/components/Viewer/ObjectTree/Base/TreeRow.vue +58 -20
  8. package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +42 -40
  9. package/app/composables/clipping_planes_widget.js +262 -0
  10. package/app/composables/hover_highlight.js +6 -0
  11. package/app/composables/project_manager.js +14 -11
  12. package/app/composables/use_overlapping_picker.js +15 -2
  13. package/app/stores/app.js +56 -11
  14. package/app/stores/back.js +10 -27
  15. package/app/stores/cloud.js +7 -1
  16. package/app/stores/data.js +32 -1
  17. package/app/stores/data_style.js +11 -0
  18. package/app/stores/hybrid_viewer.js +13 -5
  19. package/app/stores/infra.js +2 -7
  20. package/app/stores/viewer.js +9 -27
  21. package/app/utils/clipping_planes.js +110 -0
  22. package/app/utils/extension.js +30 -3
  23. package/app/utils/import_workflow.js +9 -12
  24. package/app/utils/log.js +18 -0
  25. package/app/utils/stores.js +32 -0
  26. package/internal/stores/hybrid_viewer.js +8 -63
  27. package/internal/stores/hybrid_viewer_brightness.js +62 -0
  28. package/internal/utils/api_fetch.js +27 -53
  29. package/internal/utils/upload_file.js +36 -29
  30. package/internal/utils/viewer_call.js +7 -2
  31. package/nuxt.config.js +2 -1
  32. package/package.json +4 -3
  33. package/server/api/local/{project_folder_path.post.js → app/project_folder_path.post.js} +1 -1
  34. package/server/api/local/{run_back.post.js → app/run_back.post.js} +1 -1
  35. package/server/api/local/{run_viewer.post.js → app/run_viewer.post.js} +1 -1
  36. package/server/api/{microservice → local}/extensions/upload.put.js +16 -37
  37. package/server/api/microservice/app/set_app_base_url.post.js +25 -0
  38. package/server/api/microservice/app/set_back_base_url.post.js +22 -0
  39. package/server/api/microservice/app/set_viewer_base_url.post.js +22 -0
  40. package/server/api/microservice/extensions/download.post.js +32 -0
  41. package/server/api/microservice/extensions/kill.post.js +3 -3
  42. package/server/api/microservice/extensions/run.post.js +5 -4
  43. package/server/api/serverless/{run_cloud.js → run_cloud.post.js} +1 -1
  44. package/{app/utils/config.js → server/utils/app_config.js} +28 -3
  45. package/{app/utils/local → server/utils}/path.js +1 -1
  46. package/{app/utils/local → server/utils}/scripts.js +5 -2
  47. package/server/utils/server_config.js +32 -0
  48. package/shared/scripts.js +56 -0
  49. package/shared/utils/fetch_raw.js +61 -0
  50. package/shared/utils/fetch_schema.js +46 -0
  51. package/shared/utils/file.js +16 -0
  52. package/shared/utils/response_handlers/load.js +74 -0
  53. package/tests/integration/setup.js +3 -3
  54. package/tests/integration/stores/data_style/mesh/cells.nuxt.test.js +1 -1
  55. package/tests/integration/stores/data_style/mesh/edges.nuxt.test.js +1 -1
  56. package/tests/integration/stores/data_style/mesh/index.nuxt.test.js +1 -1
  57. package/tests/integration/stores/data_style/mesh/points.nuxt.test.js +1 -1
  58. package/tests/integration/stores/data_style/mesh/polygons.nuxt.test.js +1 -1
  59. package/tests/integration/stores/data_style/mesh/polyhedra.nuxt.test.js +1 -1
  60. package/tests/integration/stores/data_style/model/blocks.nuxt.test.js +1 -1
  61. package/tests/integration/stores/data_style/model/corners.nuxt.test.js +1 -1
  62. package/tests/integration/stores/data_style/model/edges.nuxt.test.js +1 -1
  63. package/tests/integration/stores/data_style/model/index.nuxt.test.js +1 -1
  64. package/tests/integration/stores/data_style/model/lines.nuxt.test.js +1 -1
  65. package/tests/integration/stores/data_style/model/points.nuxt.test.js +1 -1
  66. package/tests/integration/stores/data_style/model/surfaces.nuxt.test.js +1 -1
  67. package/tests/integration/stores/viewer.nuxt.test.js +1 -1
  68. package/tests/unit/composables/project_manager.nuxt.test.js +14 -2
  69. package/tests/unit/composables/upload_file.nuxt.test.js +2 -2
  70. package/tests/unit/stores/back.nuxt.test.js +1 -1
  71. package/tests/unit/stores/cloud.nuxt.test.js +22 -20
  72. package/tests/unit/stores/data.nuxt.test.js +35 -0
  73. package/tests/unit/stores/infra.nuxt.test.js +13 -6
  74. package/tests/unit/stores/viewer.nuxt.test.js +1 -1
  75. package/tests/unit/utils/validate_schema.nuxt.test.js +1 -1
  76. package/tests/vitest.config.js +7 -5
  77. /package/server/api/local/{kill.post.js → app/kill.post.js} +0 -0
  78. /package/{app/utils/local → server/utils}/cleanup.js +0 -0
  79. /package/{app/utils/local → server/utils}/microservices.js +0 -0
  80. /package/{app → server}/utils/server.js +0 -0
  81. /package/{app/utils/local → shared}/app_mode.js +0 -0
  82. /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-btn
183
- v-if="item.viewer_type"
184
- icon="mdi-target"
185
- size="medium"
186
- variant="text"
187
- v-tooltip="'Focus camera on object'"
188
- @click.stop="hybridViewerStore.focusCameraOnObject(item.id)"
189
- />
190
- <v-btn
191
- v-if="isModel(item)"
192
- icon="mdi-magnify-expand"
193
- size="medium"
194
- class="ml-2"
195
- variant="text"
196
- v-tooltip="'Model\'s mesh components'"
197
- @click.stop="
198
- treeviewStore.displayAdditionalTree(
199
- item.id,
200
- item.title,
201
- item.geode_object_type,
202
- 'model_components',
203
- )
204
- "
205
- />
206
- <v-btn
207
- v-if="isModel(item) && hasCollectionsMap[item.id]"
208
- icon="mdi-format-list-group"
209
- size="medium"
210
- class="ml-2"
211
- variant="text"
212
- v-tooltip="'Model\'s collections'"
213
- @click.stop="
214
- treeviewStore.displayAdditionalTree(
215
- item.id,
216
- item.title,
217
- item.geode_object_type,
218
- 'model_collections',
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 $fetch(schema.$id, {
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 schema = viewer_schemas.opengeodeweb_viewer.viewer.reset_visualization;
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 schemaImport = back_schemas.opengeodeweb_back.import_project;
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 $fetch(schemaImport.$id, {
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((item) => item.id));
68
- const ids = Object.keys(dataStyleStore.styles).filter((styleId) => activeIds.has(styleId));
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, port, backendPath = undefined) {
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: 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 route = "/api/microservice/extensions/upload";
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
- { route, file },
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, headers: {} },
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
  });
@@ -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
- if (useInfraStore().app_mode === appMode.CLOUD) {
23
- return "https";
24
- }
25
- return "http";
22
+ return getRestApiProtocol();
26
23
  },
27
24
  port() {
28
- if (useInfraStore().app_mode === appMode.CLOUD) {
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 geode_url = `${this.protocol}://${infraStore.domain_name}:${this.port}`;
36
- if (infraStore.app_mode === appMode.CLOUD) {
37
- geode_url += `/geode`;
29
+ let back_url = `${this.protocol}://${infraStore.domain_name}:${this.port}`;
30
+ if (isCloudMode()) {
31
+ back_url += `/geode`;
38
32
  }
39
- return geode_url;
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 route = back_schemas.opengeodeweb_back.upload_file.$id;
121
+ const schema = back_schemas.opengeodeweb_back.upload_file;
138
122
  return upload_file(
139
123
  this,
140
124
  {
141
- route,
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
  }