@geode/opengeodeweb-front 10.32.3-rc.1 → 10.33.0-rc.2

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 (68) hide show
  1. package/app/components/CameraManager.vue +9 -16
  2. package/app/components/CameraOrientation.vue +0 -2
  3. package/app/components/ClippingPlanes.vue +20 -17
  4. package/app/components/CrsSelector.vue +8 -8
  5. package/app/components/HybridRenderingView.vue +12 -12
  6. package/app/components/ObjectSelector.vue +7 -7
  7. package/app/components/RemoteRenderingView.vue +11 -11
  8. package/app/components/ShrinkFilter.vue +2 -2
  9. package/app/components/ToolPanel.vue +1 -1
  10. package/app/components/ViewToolbar.vue +37 -15
  11. package/app/components/Viewer/ContextMenu/ContextMenu.vue +30 -30
  12. package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +2 -2
  13. package/app/components/Viewer/ObjectTree/Base/CommonTreeView.vue +3 -1
  14. package/app/components/Viewer/ObjectTree/Views/ModelCollections.vue +10 -10
  15. package/app/components/Viewer/Options/TextureItem.vue +4 -4
  16. package/app/components/csv-preview/CsvPreviewer.vue +21 -21
  17. package/app/composables/clipping_planes_widget.js +28 -37
  18. package/app/composables/tree_keyboard_nav.js +8 -3
  19. package/app/stores/data.js +36 -43
  20. package/app/stores/treeview.js +4 -4
  21. package/app/stores/viewer.js +61 -68
  22. package/app/utils/extension.js +50 -44
  23. package/app/utils/import_workflow.js +33 -35
  24. package/internal/database/database.js +3 -1
  25. package/internal/stores/data_style/mesh/cells/cell.js +53 -44
  26. package/internal/stores/data_style/mesh/cells/vertex.js +53 -44
  27. package/internal/stores/data_style/mesh/edges/edge.js +53 -45
  28. package/internal/stores/data_style/mesh/edges/vertex.js +53 -45
  29. package/internal/stores/data_style/mesh/points/common.js +6 -1
  30. package/internal/stores/data_style/mesh/points/vertex.js +53 -44
  31. package/internal/stores/data_style/mesh/points/visibility.js +3 -1
  32. package/internal/stores/data_style/mesh/polygons/polygon.js +53 -45
  33. package/internal/stores/data_style/mesh/polygons/vertex.js +53 -45
  34. package/internal/stores/data_style/mesh/polyhedra/polyhedron.js +53 -45
  35. package/internal/stores/data_style/mesh/polyhedra/vertex.js +53 -45
  36. package/internal/stores/data_style/model/blocks/polyhedron.js +45 -50
  37. package/internal/stores/data_style/model/blocks/vertex.js +49 -51
  38. package/internal/stores/data_style/model/color.js +38 -50
  39. package/internal/stores/data_style/model/corners/vertex.js +45 -50
  40. package/internal/stores/data_style/model/lines/edge.js +48 -50
  41. package/internal/stores/data_style/model/lines/vertex.js +49 -51
  42. package/internal/stores/data_style/model/surfaces/polygon.js +45 -50
  43. package/internal/stores/data_style/model/surfaces/vertex.js +45 -50
  44. package/internal/stores/data_style/model/visibility.js +40 -33
  45. package/internal/stores/hybrid_viewer/brightness.js +21 -25
  46. package/internal/stores/hybrid_viewer/camera.js +116 -116
  47. package/internal/stores/hybrid_viewer/filters.js +28 -21
  48. package/internal/stores/hybrid_viewer/highlight.js +66 -63
  49. package/internal/stores/hybrid_viewer/scene.js +40 -45
  50. package/internal/stores/hybrid_viewer/viewport.js +33 -43
  51. package/internal/utils/api_fetch.js +1 -1
  52. package/internal/utils/viewer_call.js +37 -53
  53. package/internal/utils/ws_client.js +29 -0
  54. package/nuxt.config.js +24 -1
  55. package/package.json +1 -1
  56. package/server/utils/app_config.js +10 -15
  57. package/server/utils/cleanup.js +23 -20
  58. package/server/utils/microservices.js +42 -47
  59. package/server/utils/path.js +23 -28
  60. package/server/utils/scripts.js +38 -36
  61. package/server/utils/server_config.js +23 -2
  62. package/server/utils/ws_client.js +112 -0
  63. package/shared/utils/call_raw.js +46 -0
  64. package/shared/utils/call_schema.js +45 -0
  65. package/shared/utils/fetch_schema.js +7 -4
  66. package/shared/utils/parse_boolean.js +16 -0
  67. package/shared/utils/validate_schema.js +2 -2
  68. package/tests/unit/utils/validate_schema.nuxt.test.js +3 -3
@@ -11,6 +11,14 @@ const { showDialog, width, escapeFunction } = defineProps({
11
11
  escapeFunction: { type: Function, default: undefined },
12
12
  });
13
13
 
14
+ function handleClose() {
15
+ if (escapeFunction) {
16
+ escapeFunction();
17
+ } else {
18
+ emit("close");
19
+ }
20
+ }
21
+
14
22
  const show = computed({
15
23
  get: () => showDialog,
16
24
  set: (val) => {
@@ -19,25 +27,10 @@ const show = computed({
19
27
  }
20
28
  },
21
29
  });
22
-
23
- function handleClose() {
24
- if (escapeFunction) {
25
- escapeFunction();
26
- } else {
27
- emit("close");
28
- }
29
- }
30
30
  </script>
31
31
 
32
32
  <template>
33
- <ToolPanel
34
- v-model="show"
35
- title="Camera Positions"
36
- :width="width"
37
- :escapeFunction="handleClose"
38
- style="top: 90px; right: 55px"
39
- z-index="1"
40
- >
33
+ <ToolPanel v-model="show" title="Camera Positions" :width="width" :escapeFunction="handleClose">
41
34
  <v-card-text class="pa-0">
42
35
  <Saver />
43
36
  <v-divider />
@@ -174,8 +174,6 @@ watch(hoveredFace, (newFace, oldFace) => {
174
174
  title="Camera Orientations"
175
175
  :width="width"
176
176
  :escapeFunction="escapeFunction"
177
- style="top: 90px; right: 55px"
178
- z-index="1"
179
177
  >
180
178
  <div
181
179
  class="pa-0 overflow-hidden position-relative"
@@ -22,7 +22,8 @@ const availableDatasets = computed(() =>
22
22
  allItems.value.map((item) => ({ title: item.name || item.id, value: item.id })),
23
23
  );
24
24
  const widgetContainer = useTemplateRef("widgetContainer");
25
- const debouncedApply = useDebounceFn(() => applyClippingPlanes(), DEBOUNCE_DELAY);
25
+ let debouncedApply = undefined;
26
+
26
27
  const {
27
28
  getSceneCenter,
28
29
  syncWidgets,
@@ -38,24 +39,9 @@ const {
38
39
  selectedDatasetIds,
39
40
  allItems,
40
41
  hybridViewerStore,
41
- debouncedApply,
42
+ debouncedApply: () => debouncedApply(),
42
43
  });
43
44
 
44
- function addPlane() {
45
- const normal = DEFAULT_NORMALS[planes.value.length % DEFAULT_NORMALS.length];
46
- planes.value.push({ origin: getSceneCenter(), normal });
47
- }
48
-
49
- function removePlane(index) {
50
- planes.value.splice(index, 1);
51
- }
52
-
53
- function flipNormal(plane) {
54
- plane.normal = plane.normal.map((component) => -component);
55
- syncWidgets();
56
- applyClippingPlanes();
57
- }
58
-
59
45
  async function applyClippingPlanes() {
60
46
  const allIds = allItems.value.map((item) => item.id);
61
47
  if (allIds.length === 0) {
@@ -77,6 +63,23 @@ async function applyClippingPlanes() {
77
63
  }
78
64
  }
79
65
 
66
+ debouncedApply = useDebounceFn(() => applyClippingPlanes(), DEBOUNCE_DELAY);
67
+
68
+ function addPlane() {
69
+ const normal = DEFAULT_NORMALS[planes.value.length % DEFAULT_NORMALS.length];
70
+ planes.value.push({ origin: getSceneCenter(), normal });
71
+ }
72
+
73
+ function removePlane(index) {
74
+ planes.value.splice(index, 1);
75
+ }
76
+
77
+ function flipNormal(plane) {
78
+ plane.normal = plane.normal.map((component) => -component);
79
+ syncWidgets();
80
+ applyClippingPlanes();
81
+ }
82
+
80
83
  async function resetClippingPlanes() {
81
84
  setFromWidget(true);
82
85
  planes.value = [{ origin: undefined, normal: [1, 0, 0] }];
@@ -18,6 +18,14 @@ const selected_crs = ref([]);
18
18
  const toggle_loading = useToggle(data_table_loading);
19
19
  const backStore = useBackStore();
20
20
 
21
+ function get_selected_crs(crs_code) {
22
+ for (let i = 0; i <= crs_list.value.length; i += 1) {
23
+ if (crs_list.value[i]["code"] === crs_code) {
24
+ return crs_list.value[i];
25
+ }
26
+ }
27
+ }
28
+
21
29
  watch(selected_crs, (new_value) => {
22
30
  const crs = get_selected_crs(new_value[0]);
23
31
  const keys_values_object = {
@@ -27,14 +35,6 @@ watch(selected_crs, (new_value) => {
27
35
  emit("increment_step");
28
36
  });
29
37
 
30
- function get_selected_crs(crs_code) {
31
- for (let i = 0; i <= crs_list.value.length; i += 1) {
32
- if (crs_list.value[i]["code"] === crs_code) {
33
- return crs_list.value[i];
34
- }
35
- }
36
- }
37
-
38
38
  async function get_crs_table() {
39
39
  const params = { geode_object_type: geodeObjectType };
40
40
  toggle_loading();
@@ -22,6 +22,18 @@ const dataStore = useDataStore();
22
22
  const { width: elementWidth, height: elementHeight } = useElementSize(container);
23
23
  const { width: windowWidth, height: windowHeight } = useWindowSize();
24
24
 
25
+ function debounce(func, wait) {
26
+ let timeout = undefined;
27
+ return function executedFunction(...args) {
28
+ function later() {
29
+ clearTimeout(timeout);
30
+ func(...args);
31
+ }
32
+ clearTimeout(timeout);
33
+ timeout = setTimeout(later, wait);
34
+ };
35
+ }
36
+
25
37
  const debouncedResize = debounce(() => {
26
38
  hybridViewerStore.resize(elementWidth.value, elementHeight.value);
27
39
  }, DEFAULT_ELEMENT_HEIGHT);
@@ -41,18 +53,6 @@ onMounted(async () => {
41
53
 
42
54
  const { pickColormap, quickColormap } = useQuickColormap();
43
55
 
44
- function debounce(func, wait) {
45
- let timeout = undefined;
46
- return function executedFunction(...args) {
47
- function later() {
48
- clearTimeout(timeout);
49
- func(...args);
50
- }
51
- clearTimeout(timeout);
52
- timeout = setTimeout(later, wait);
53
- };
54
- }
55
-
56
56
  async function handleClick(event) {
57
57
  const { offsetX, offsetY, clientX, clientY } = event;
58
58
  if (hybridViewerStore.is_ruler_active) {
@@ -29,6 +29,13 @@ async function fetchAllowedObjectsList() {
29
29
  return responses.map((response) => response.allowed_objects);
30
30
  }
31
31
 
32
+ function setGeodeObject(geode_object_type) {
33
+ if (geode_object_type) {
34
+ emit("update_values", { geode_object_type });
35
+ emit("increment_step");
36
+ }
37
+ }
38
+
32
39
  async function getAllowedGeodeObjects() {
33
40
  toggleLoading();
34
41
  allowedGeodeObjects.value = {};
@@ -44,13 +51,6 @@ async function getAllowedGeodeObjects() {
44
51
  }
45
52
  toggleLoading();
46
53
  }
47
-
48
- function setGeodeObject(geode_object_type) {
49
- if (geode_object_type) {
50
- emit("update_values", { geode_object_type });
51
- emit("increment_step");
52
- }
53
- }
54
54
  // oxlint-disable-next-line no-top-level-await
55
55
  await getAllowedGeodeObjects();
56
56
  </script>
@@ -71,6 +71,17 @@ watch([width, height], () => {
71
71
  resize();
72
72
  });
73
73
 
74
+ function connect() {
75
+ if (viewerStore.status !== Status.CONNECTED) {
76
+ return;
77
+ }
78
+ const session = viewerStore.client.getConnection().getSession();
79
+ view.setSession(session);
80
+ view.setViewId(props.viewId);
81
+ connected.value = true;
82
+ view.render();
83
+ }
84
+
74
85
  watch(
75
86
  () => viewerStore.client,
76
87
  () => {
@@ -88,17 +99,6 @@ watch(
88
99
  },
89
100
  );
90
101
 
91
- function connect() {
92
- if (viewerStore.status !== Status.CONNECTED) {
93
- return;
94
- }
95
- const session = viewerStore.client.getConnection().getSession();
96
- view.setSession(session);
97
- view.setViewId(props.viewId);
98
- connected.value = true;
99
- view.render();
100
- }
101
-
102
102
  onMounted(async () => {
103
103
  if (import.meta.client) {
104
104
  window.addEventListener("resize", resize);
@@ -24,8 +24,6 @@ const availableDatasets = computed(() =>
24
24
  allItems.value.map((item) => ({ title: item.name || item.id, value: item.id })),
25
25
  );
26
26
 
27
- const debouncedApply = useDebounceFn(() => applyShrink(), DEBOUNCE_DELAY);
28
-
29
27
  async function applyShrink() {
30
28
  const allIds = allItems.value.map((item) => item.id);
31
29
  if (allIds.length === 0) {
@@ -42,6 +40,8 @@ async function applyShrink() {
42
40
  }
43
41
  }
44
42
 
43
+ const debouncedApply = useDebounceFn(() => applyShrink(), DEBOUNCE_DELAY);
44
+
45
45
  async function resetShrink() {
46
46
  shrinkFactor.value = DEFAULT_SHRINK_VALUE;
47
47
  await applyShrink();
@@ -71,7 +71,7 @@ function close() {
71
71
  .tool-panel {
72
72
  z-index: 1;
73
73
  top: 90px;
74
- right: 55px;
74
+ right: 70px;
75
75
  }
76
76
  :deep(.v-card-title) {
77
77
  font-size: 0.9rem !important;
@@ -15,14 +15,14 @@ import { useViewerStore } from "@ogw_front/stores/viewer";
15
15
 
16
16
  const hybridViewerStore = useHybridViewerStore();
17
17
  const viewerStore = useViewerStore();
18
- const take_screenshot = ref(false);
19
- const show_camera_manager = ref(false);
18
+ const showScreenshot = ref(false);
19
+ const showCameraManager = ref(false);
20
20
  const showCameraOrientation = ref(false);
21
21
  const showZScaling = ref(false);
22
22
  const showClippingPlanes = ref(false);
23
23
  const showShrinkFilter = ref(false);
24
24
  const showRuler = ref(false);
25
- const grid_scale = ref(false);
25
+ const gridScale = ref(false);
26
26
  const zScale = ref(hybridViewerStore.zScale);
27
27
  const openSubMenus = ref({});
28
28
 
@@ -47,6 +47,28 @@ onKeyStroke("Escape", () => {
47
47
  }
48
48
  });
49
49
 
50
+ function closeAllToolsExcept(toolRef) {
51
+ const tools = [
52
+ showCameraOrientation,
53
+ showCameraManager,
54
+ showScreenshot,
55
+ showZScaling,
56
+ showClippingPlanes,
57
+ showShrinkFilter,
58
+ showRuler,
59
+ ];
60
+ for (const tool of tools) {
61
+ if (tool !== toolRef) {
62
+ tool.value = false;
63
+ }
64
+ }
65
+ }
66
+
67
+ function toggleTool(toolRef) {
68
+ closeAllToolsExcept(toolRef);
69
+ toolRef.value = !toolRef.value;
70
+ }
71
+
50
72
  const camera_options = computed(() => [
51
73
  {
52
74
  testId: "resetCameraButton",
@@ -118,7 +140,7 @@ const camera_options = computed(() => [
118
140
  tooltip: "Camera orientation",
119
141
  icon: "mdi-rotate-3d",
120
142
  action: () => {
121
- showCameraOrientation.value = !showCameraOrientation.value;
143
+ toggleTool(showCameraOrientation);
122
144
  },
123
145
  },
124
146
  {
@@ -127,7 +149,7 @@ const camera_options = computed(() => [
127
149
  icon: CameraBookmarkIcon,
128
150
  iconSize: 34,
129
151
  action: () => {
130
- show_camera_manager.value = !show_camera_manager.value;
152
+ toggleTool(showCameraManager);
131
153
  },
132
154
  },
133
155
  {
@@ -135,17 +157,17 @@ const camera_options = computed(() => [
135
157
  tooltip: "Take a screenshot",
136
158
  icon: "mdi-camera",
137
159
  action: () => {
138
- take_screenshot.value = !take_screenshot.value;
160
+ toggleTool(showScreenshot);
139
161
  },
140
162
  },
141
163
  {
142
164
  testId: "gridScaleButton",
143
165
  tooltip: "Toggle grid scale",
144
166
  icon: "mdi-ruler-square",
145
- color: grid_scale.value ? "primary" : undefined,
167
+ color: gridScale.value ? "primary" : undefined,
146
168
  action: () => {
147
169
  const schema = schemas.opengeodeweb_viewer.viewer.grid_scale;
148
- const params = { visibility: !grid_scale.value };
170
+ const params = { visibility: !gridScale.value };
149
171
  viewerStore.request(
150
172
  {
151
173
  schema,
@@ -153,7 +175,7 @@ const camera_options = computed(() => [
153
175
  },
154
176
  {
155
177
  response_function: () => {
156
- grid_scale.value = !grid_scale.value;
178
+ gridScale.value = !gridScale.value;
157
179
  hybridViewerStore.remoteRender();
158
180
  },
159
181
  },
@@ -165,7 +187,7 @@ const camera_options = computed(() => [
165
187
  tooltip: "Z Scaling Control",
166
188
  icon: "mdi-sort",
167
189
  action: () => {
168
- showZScaling.value = !showZScaling.value;
190
+ toggleTool(showZScaling);
169
191
  },
170
192
  },
171
193
  {
@@ -174,7 +196,7 @@ const camera_options = computed(() => [
174
196
  icon: "mdi-content-cut",
175
197
  color: showClippingPlanes.value ? "primary" : undefined,
176
198
  action: () => {
177
- showClippingPlanes.value = !showClippingPlanes.value;
199
+ toggleTool(showClippingPlanes);
178
200
  },
179
201
  },
180
202
  {
@@ -183,7 +205,7 @@ const camera_options = computed(() => [
183
205
  icon: "mdi-arrow-collapse-all",
184
206
  color: showShrinkFilter.value ? "primary" : undefined,
185
207
  action: () => {
186
- showShrinkFilter.value = !showShrinkFilter.value;
208
+ toggleTool(showShrinkFilter);
187
209
  },
188
210
  },
189
211
  {
@@ -192,7 +214,7 @@ const camera_options = computed(() => [
192
214
  icon: "mdi-ruler",
193
215
  color: showRuler.value ? "primary" : undefined,
194
216
  action: () => {
195
- showRuler.value = !showRuler.value;
217
+ toggleTool(showRuler);
196
218
  },
197
219
  },
198
220
  ]);
@@ -260,8 +282,8 @@ const camera_options = computed(() => [
260
282
  panel
261
283
  @select="hybridViewerStore.setCameraOrientation"
262
284
  />
263
- <Screenshot v-model="take_screenshot" :escapeFunction="() => (take_screenshot = false)" />
264
- <CameraManager :showDialog="show_camera_manager" @close="show_camera_manager = false" />
285
+ <Screenshot v-model="showScreenshot" :escapeFunction="() => (showScreenshot = false)" />
286
+ <CameraManager :showDialog="showCameraManager" @close="showCameraManager = false" />
265
287
  <ZScaling
266
288
  v-model:show="showZScaling"
267
289
  v-model="zScale"
@@ -36,6 +36,36 @@ const dragStartY = ref(0);
36
36
  const menuX = ref(x);
37
37
  const menuY = ref(y);
38
38
 
39
+ function clampPosition(posX, posY) {
40
+ const margin = RADIUS + MARGIN_OFFSET;
41
+ return {
42
+ x: Math.min(Math.max(posX, margin), containerWidth - margin),
43
+ y: Math.min(Math.max(posY, margin), containerHeight - margin),
44
+ };
45
+ }
46
+
47
+ function startDrag(event) {
48
+ isDragging.value = true;
49
+ dragStartX.value = event.clientX - menuX.value;
50
+ dragStartY.value = event.clientY - menuY.value;
51
+ }
52
+
53
+ function handleDrag(event) {
54
+ const { x: clampedX, y: clampedY } = clampPosition(
55
+ event.clientX - dragStartX.value,
56
+ event.clientY - dragStartY.value,
57
+ );
58
+ menuX.value = clampedX;
59
+ menuY.value = clampedY;
60
+ menuStore.setMenuPosition(clampedX, clampedY);
61
+ }
62
+
63
+ function stopDrag(event) {
64
+ isDragging.value = false;
65
+ event.stopPropagation();
66
+ menuStore.setMenuPosition(menuX.value, menuY.value);
67
+ }
68
+
39
69
  watch(show_menu, (newVal) => {
40
70
  if (!newVal) {
41
71
  menuStore.closeMenu();
@@ -115,36 +145,6 @@ const isOverToolbar = computed(() => {
115
145
  );
116
146
  });
117
147
 
118
- function startDrag(event) {
119
- isDragging.value = true;
120
- dragStartX.value = event.clientX - menuX.value;
121
- dragStartY.value = event.clientY - menuY.value;
122
- }
123
-
124
- function clampPosition(posX, posY) {
125
- const margin = RADIUS + MARGIN_OFFSET;
126
- return {
127
- x: Math.min(Math.max(posX, margin), containerWidth - margin),
128
- y: Math.min(Math.max(posY, margin), containerHeight - margin),
129
- };
130
- }
131
-
132
- function handleDrag(event) {
133
- const { x: clampedX, y: clampedY } = clampPosition(
134
- event.clientX - dragStartX.value,
135
- event.clientY - dragStartY.value,
136
- );
137
- menuX.value = clampedX;
138
- menuY.value = clampedY;
139
- menuStore.setMenuPosition(clampedX, clampedY);
140
- }
141
-
142
- function stopDrag(event) {
143
- isDragging.value = false;
144
- event.stopPropagation();
145
- menuStore.setMenuPosition(menuX.value, menuY.value);
146
- }
147
-
148
148
  function getMenuStyle() {
149
149
  return {
150
150
  position: "fixed",
@@ -99,7 +99,7 @@ const modelComponentsActiveColoring = computed({
99
99
  await dataStyleStore.setModelComponentsColor(
100
100
  modelId.value,
101
101
  selection.value,
102
- modelComponentsColor.value,
102
+ dataStyleStore.getModelColor(modelId.value),
103
103
  coloringType,
104
104
  );
105
105
  hybridViewerStore.remoteRender();
@@ -116,7 +116,7 @@ const modelComponentsColor = computed({
116
116
  modelId.value,
117
117
  selection.value,
118
118
  color,
119
- modelComponentsActiveColoring.value,
119
+ dataStyleStore.getModelActiveColoring(modelId.value),
120
120
  );
121
121
  hybridViewerStore.remoteRender();
122
122
  },
@@ -53,6 +53,7 @@ const { virtualScrollRef, stickyHeader, handleScroll, scrollToIndex } = useTreeS
53
53
  );
54
54
 
55
55
  const lastActiveIndex = ref(-1);
56
+ const focusedIndex = ref(-1);
56
57
 
57
58
  function handleItemClick(item, index, event) {
58
59
  if (index !== undefined) {
@@ -101,12 +102,13 @@ function handleItemClick(item, index, event) {
101
102
  }
102
103
  }
103
104
 
104
- const { focusedIndex, handleKeyDown } = useTreeKeyboardNav(
105
+ const { handleKeyDown } = useTreeKeyboardNav(
105
106
  displayItems,
106
107
  emit,
107
108
  scrollToIndex,
108
109
  toggleOpen,
109
110
  handleItemClick,
111
+ focusedIndex,
110
112
  );
111
113
  </script>
112
114
 
@@ -96,6 +96,16 @@ function showContextMenu(event, item) {
96
96
  });
97
97
  }
98
98
 
99
+ function extractIds(node) {
100
+ if (node.children) {
101
+ return node.children.flatMap((child) => extractIds(child));
102
+ }
103
+ if (Number.isInteger(node.viewer_id)) {
104
+ return [node.viewer_id];
105
+ }
106
+ return [];
107
+ }
108
+
99
109
  function handleHoverEnter({ item, immediate = false }) {
100
110
  const actualItem = item.raw || item;
101
111
 
@@ -126,16 +136,6 @@ function expandAll() {
126
136
  opened.value = allIds;
127
137
  }
128
138
 
129
- function extractIds(node) {
130
- if (node.children) {
131
- return node.children.flatMap((child) => extractIds(child));
132
- }
133
- if (Number.isInteger(node.viewer_id)) {
134
- return [node.viewer_id];
135
- }
136
- return [];
137
- }
138
-
139
139
  function getLeafViewerIds(item) {
140
140
  const actualItem = item.raw || item;
141
141
  return extractIds(actualItem);
@@ -35,10 +35,6 @@ watch(
35
35
  const textureCoordinates = ref([]);
36
36
  const backStore = useBackStore();
37
37
 
38
- onMounted(() => {
39
- getTextureCoordinates();
40
- });
41
-
42
38
  function getTextureCoordinates() {
43
39
  const schema = back_schemas.opengeodeweb_back.texture_coordinates;
44
40
  const params = { id };
@@ -52,6 +48,10 @@ function getTextureCoordinates() {
52
48
  );
53
49
  }
54
50
 
51
+ onMounted(() => {
52
+ getTextureCoordinates();
53
+ });
54
+
55
55
  async function files_uploaded_event(value) {
56
56
  if (value.length > 0) {
57
57
  const schema = back_schemas.opengeodeweb_back.save_viewable_file;
@@ -54,27 +54,6 @@ function autoDetectSeparator(content) {
54
54
  return best;
55
55
  }
56
56
 
57
- function readAndParse() {
58
- if (!file) {
59
- return;
60
- }
61
- toggleLoading(true);
62
-
63
- const reader = new FileReader();
64
- reader.addEventListener("load", (event) => {
65
- rawContent.value = event.target.result;
66
- if (!separator.value || separator.value === ",") {
67
- separator.value = autoDetectSeparator(rawContent.value);
68
- }
69
- parseContent();
70
- toggleLoading(false);
71
- });
72
- reader.addEventListener("error", () => {
73
- toggleLoading(false);
74
- });
75
- reader.readAsText(file, "utf8");
76
- }
77
-
78
57
  function parseContent() {
79
58
  if (!rawContent.value) {
80
59
  return;
@@ -124,6 +103,27 @@ function parseContent() {
124
103
  return obj;
125
104
  });
126
105
  }
106
+
107
+ function readAndParse() {
108
+ if (!file) {
109
+ return;
110
+ }
111
+ toggleLoading(true);
112
+
113
+ const reader = new FileReader();
114
+ reader.addEventListener("load", (event) => {
115
+ rawContent.value = event.target.result;
116
+ if (!separator.value || separator.value === ",") {
117
+ separator.value = autoDetectSeparator(rawContent.value);
118
+ }
119
+ parseContent();
120
+ toggleLoading(false);
121
+ });
122
+ reader.addEventListener("error", () => {
123
+ toggleLoading(false);
124
+ });
125
+ reader.readAsText(file, "utf8");
126
+ }
127
127
  const computedResult = computed(() => {
128
128
  const xIndex = previewHeaders.value.findIndex((header) => header.key === xColumn.value);
129
129
  const yIndex = previewHeaders.value.findIndex((header) => header.key === yColumn.value);