@geode/opengeodeweb-front 10.34.0-rc.9 → 10.34.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.
Files changed (282) hide show
  1. package/{server → .build/server}/utils/app_config.js +10 -9
  2. package/{server → .build/server}/utils/cleanup.js +31 -17
  3. package/{server → .build/server}/utils/cloud.js +1 -4
  4. package/{server → .build/server}/utils/microservices.js +21 -9
  5. package/{server → .build/server}/utils/path.js +4 -4
  6. package/{server → .build/server}/utils/scripts.js +9 -9
  7. package/.build/server/utils/server_config.js +51 -0
  8. package/.build/server/utils/stream.js +6 -0
  9. package/{server → .build/server}/utils/ws_client.js +18 -3
  10. package/{shared → .build/shared}/scripts.js +10 -10
  11. package/.build/shared/utils/call_raw.js +31 -0
  12. package/{shared → .build/shared}/utils/call_schema.js +2 -2
  13. package/.build/shared/utils/fetch_raw.js +52 -0
  14. package/{shared → .build/shared}/utils/fetch_schema.js +2 -2
  15. package/{shared → .build/shared}/utils/file.js +3 -1
  16. package/{shared → .build/shared}/utils/response_handlers/load.js +10 -7
  17. package/{shared → .build/shared}/utils/validate_schema.js +1 -1
  18. package/app/components/ActionButton.vue +6 -6
  19. package/app/components/CameraManager/List.vue +5 -5
  20. package/app/components/CameraManager/Saver.vue +3 -5
  21. package/app/components/CameraManager.vue +6 -4
  22. package/app/components/CameraOrientation.vue +12 -12
  23. package/app/components/ClippingPlaneCard.vue +4 -2
  24. package/app/components/ClippingPlanes.vue +8 -8
  25. package/app/components/CrsSelector.vue +9 -10
  26. package/app/components/DeleteDialog.vue +4 -2
  27. package/app/components/DragAndDrop.vue +10 -12
  28. package/app/components/DragAndDropInternal/DragAndDropInline.vue +4 -2
  29. package/app/components/ExtensionSelector.vue +4 -4
  30. package/app/components/FeedBack/ErrorBanner.vue +3 -1
  31. package/app/components/FeedBack/Snackers.vue +4 -3
  32. package/app/components/FileSelector.vue +10 -8
  33. package/app/components/FileUploader.vue +11 -11
  34. package/app/components/GlassCard.vue +1 -1
  35. package/app/components/HybridRenderingView.vue +7 -5
  36. package/app/components/HybridViewerTooltip.vue +7 -7
  37. package/app/components/Launcher.vue +1 -1
  38. package/app/components/Loading/EcoMessages.vue +9 -3
  39. package/app/components/Loading.vue +2 -2
  40. package/app/components/MissingFilesSelector.vue +12 -10
  41. package/app/components/ObjectSelector.vue +10 -9
  42. package/app/components/PackagesVersions.vue +6 -5
  43. package/app/components/Recaptcha.vue +3 -3
  44. package/app/components/RemoteRenderingView.vue +6 -7
  45. package/app/components/Ruler.vue +3 -3
  46. package/app/components/Screenshot.vue +6 -6
  47. package/app/components/SearchBar.vue +4 -2
  48. package/app/components/ShrinkFilter.vue +7 -7
  49. package/app/components/Step.vue +6 -5
  50. package/app/components/Stepper.vue +4 -3
  51. package/app/components/ToolPanel.vue +6 -3
  52. package/app/components/ViewToolbar.vue +25 -28
  53. package/app/components/Viewer/ContextMenu/CenterButton.vue +7 -5
  54. package/app/components/Viewer/ContextMenu/CircularItems.vue +3 -3
  55. package/app/components/Viewer/ContextMenu/ContextMenu.vue +22 -19
  56. package/app/components/Viewer/ContextMenu/ContextMenuItem.vue +10 -8
  57. package/app/components/Viewer/ContextMenu/InfoCard.vue +11 -12
  58. package/app/components/Viewer/EdgedCurve/SpecificEdgesOptions.vue +13 -17
  59. package/app/components/Viewer/Generic/Mesh/CellsOptions.vue +11 -15
  60. package/app/components/Viewer/Generic/Mesh/EdgesOptions.vue +12 -16
  61. package/app/components/Viewer/Generic/Mesh/PointsOptions.vue +8 -12
  62. package/app/components/Viewer/Generic/Mesh/PolygonsOptions.vue +11 -15
  63. package/app/components/Viewer/Generic/Mesh/PolyhedraOptions.vue +11 -15
  64. package/app/components/Viewer/Generic/Model/BlocksOptions.vue +67 -38
  65. package/app/components/Viewer/Generic/Model/CornersOptions.vue +53 -23
  66. package/app/components/Viewer/Generic/Model/EdgesOptions.vue +1 -3
  67. package/app/components/Viewer/Generic/Model/LinesOptions.vue +67 -38
  68. package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +31 -15
  69. package/app/components/Viewer/Generic/Model/ModelStyleOptions.vue +2 -3
  70. package/app/components/Viewer/Generic/Model/PointsOptions.vue +6 -6
  71. package/app/components/Viewer/Generic/Model/SurfacesOptions.vue +69 -38
  72. package/app/components/Viewer/ObjectTree/Base/CommonTreeView.vue +64 -46
  73. package/app/components/Viewer/ObjectTree/Base/Controls.vue +5 -5
  74. package/app/components/Viewer/ObjectTree/Base/ItemLabel.vue +13 -9
  75. package/app/components/Viewer/ObjectTree/Base/StickyHeader.vue +5 -5
  76. package/app/components/Viewer/ObjectTree/Base/TreeRow.vue +10 -10
  77. package/app/components/Viewer/ObjectTree/Box.vue +6 -4
  78. package/app/components/Viewer/ObjectTree/Layout.vue +23 -21
  79. package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +14 -14
  80. package/app/components/Viewer/ObjectTree/Views/{ModelCollections.vue → ModelTree.vue} +59 -24
  81. package/app/components/Viewer/Options/AttributeColorBar.vue +4 -2
  82. package/app/components/Viewer/Options/AttributeRangeSelector.vue +4 -2
  83. package/app/components/Viewer/Options/AttributeSelector.vue +7 -9
  84. package/app/components/Viewer/Options/ColorMapList.vue +15 -13
  85. package/app/components/Viewer/Options/ColorMapPicker.vue +4 -4
  86. package/app/components/Viewer/Options/ColorPicker.vue +223 -41
  87. package/app/components/Viewer/Options/ColoringTypeSelector.vue +16 -16
  88. package/app/components/Viewer/Options/ColormapQuickPicker.vue +7 -5
  89. package/app/components/Viewer/Options/OptionsSection.vue +1 -1
  90. package/app/components/Viewer/Options/TextureItem.vue +8 -6
  91. package/app/components/Viewer/Options/TexturesSelector.vue +1 -1
  92. package/app/components/Viewer/OverlappingObjectsPicker.vue +8 -9
  93. package/app/components/Viewer/PointSet/SpecificPointsOptions.vue +2 -6
  94. package/app/components/Viewer/Solid/SpecificPolyhedraOptions.vue +12 -16
  95. package/app/components/Viewer/Surface/PolygonsOptions.vue +12 -16
  96. package/app/components/Viewer/Ui.vue +2 -2
  97. package/app/components/Wrapper.vue +1 -4
  98. package/app/components/ZScaling.vue +5 -3
  99. package/app/components/csv-preview/CsvPreviewer.vue +38 -37
  100. package/app/components/csv-preview/CsvSettings.vue +6 -4
  101. package/app/components/csv-preview/CsvTable.vue +1 -1
  102. package/app/composables/batch_style.ts +5 -6
  103. package/app/composables/clipping_planes_widget.ts +73 -181
  104. package/app/composables/clipping_planes_widget_entries.ts +189 -0
  105. package/app/composables/copy_to_clipboard.ts +7 -0
  106. package/app/composables/global_attribute_style.ts +163 -83
  107. package/app/composables/hover_highlight.ts +46 -14
  108. package/app/composables/model_collections.ts +26 -13
  109. package/app/composables/model_components.ts +26 -13
  110. package/app/composables/project_manager.ts +76 -19
  111. package/app/composables/responsive_middle_truncate.ts +13 -13
  112. package/app/composables/stepper_tree.ts +34 -11
  113. package/app/composables/tree_filter.ts +66 -44
  114. package/app/composables/tree_keyboard_nav.ts +25 -11
  115. package/app/composables/tree_scroll.ts +44 -14
  116. package/app/composables/use_adaptive_styles.ts +66 -23
  117. package/app/composables/use_overlapping_picker.ts +66 -16
  118. package/app/composables/use_quick_colormap.ts +16 -5
  119. package/app/composables/virtual_tree.ts +75 -43
  120. package/app/composables/vtk_implicit_plane_widget.d.ts +2 -0
  121. package/app/plugins/auto_store_register.ts +2 -7
  122. package/app/plugins/click_outside_ignore_snackbars.client.ts +39 -0
  123. package/app/stores/app.ts +57 -192
  124. package/app/stores/app_helpers/extension.ts +179 -0
  125. package/app/stores/back.ts +37 -21
  126. package/app/stores/camera_manager.ts +22 -20
  127. package/app/stores/cloud.ts +17 -13
  128. package/app/stores/data.ts +88 -47
  129. package/app/stores/data_helpers/collections.ts +36 -38
  130. package/app/stores/data_helpers/mesh.ts +45 -36
  131. package/app/stores/data_style.ts +50 -28
  132. package/app/stores/feedback.ts +6 -6
  133. package/app/stores/hybrid_viewer.ts +41 -52
  134. package/app/stores/infra.ts +39 -37
  135. package/app/stores/menu.ts +23 -14
  136. package/app/stores/treeview.ts +72 -42
  137. package/app/stores/viewer.ts +39 -27
  138. package/app/utils/attributes.ts +3 -3
  139. package/app/utils/clipping_planes.ts +111 -14
  140. package/app/utils/color_picker.ts +57 -0
  141. package/app/utils/colormap.ts +58 -35
  142. package/app/utils/default_styles/index.ts +2 -2
  143. package/app/utils/default_styles/meshes.ts +107 -13
  144. package/app/utils/default_styles/models.ts +83 -14
  145. package/app/utils/extension.ts +47 -20
  146. package/app/utils/import_workflow.ts +21 -13
  147. package/app/utils/name_cleaner.ts +1 -1
  148. package/app/utils/string.ts +1 -1
  149. package/app/utils/treeview.ts +2 -2
  150. package/internal/database/base_database.ts +7 -3
  151. package/internal/database/database.ts +36 -26
  152. package/internal/database/extended_database.ts +1 -1
  153. package/internal/stores/data_style/mesh/cells/cell.ts +70 -34
  154. package/internal/stores/data_style/mesh/cells/color.ts +12 -6
  155. package/internal/stores/data_style/mesh/cells/common.ts +18 -8
  156. package/internal/stores/data_style/mesh/cells/index.ts +122 -42
  157. package/internal/stores/data_style/mesh/cells/textures.ts +12 -6
  158. package/internal/stores/data_style/mesh/cells/vertex.ts +75 -34
  159. package/internal/stores/data_style/mesh/cells/visibility.ts +15 -4
  160. package/internal/stores/data_style/mesh/edges/color.ts +12 -6
  161. package/internal/stores/data_style/mesh/edges/common.ts +14 -6
  162. package/internal/stores/data_style/mesh/edges/edge.ts +71 -39
  163. package/internal/stores/data_style/mesh/edges/index.ts +117 -42
  164. package/internal/stores/data_style/mesh/edges/vertex.ts +76 -39
  165. package/internal/stores/data_style/mesh/edges/visibility.ts +15 -4
  166. package/internal/stores/data_style/mesh/edges/width.ts +12 -4
  167. package/internal/stores/data_style/mesh/index.ts +30 -11
  168. package/internal/stores/data_style/mesh/points/color.ts +12 -6
  169. package/internal/stores/data_style/mesh/points/common.ts +21 -8
  170. package/internal/stores/data_style/mesh/points/index.ts +101 -50
  171. package/internal/stores/data_style/mesh/points/size.ts +12 -4
  172. package/internal/stores/data_style/mesh/points/vertex.ts +75 -34
  173. package/internal/stores/data_style/mesh/points/visibility.ts +17 -7
  174. package/internal/stores/data_style/mesh/polygons/color.ts +12 -6
  175. package/internal/stores/data_style/mesh/polygons/common.ts +23 -6
  176. package/internal/stores/data_style/mesh/polygons/index.ts +130 -70
  177. package/internal/stores/data_style/mesh/polygons/polygon.ts +77 -43
  178. package/internal/stores/data_style/mesh/polygons/textures.ts +12 -6
  179. package/internal/stores/data_style/mesh/polygons/vertex.ts +79 -39
  180. package/internal/stores/data_style/mesh/polygons/visibility.ts +16 -6
  181. package/internal/stores/data_style/mesh/polyhedra/color.ts +12 -6
  182. package/internal/stores/data_style/mesh/polyhedra/common.ts +14 -6
  183. package/internal/stores/data_style/mesh/polyhedra/index.ts +115 -56
  184. package/internal/stores/data_style/mesh/polyhedra/polyhedron.ts +80 -39
  185. package/internal/stores/data_style/mesh/polyhedra/vertex.ts +79 -39
  186. package/internal/stores/data_style/mesh/polyhedra/visibility.ts +16 -6
  187. package/internal/stores/data_style/model/blocks/color.ts +43 -13
  188. package/internal/stores/data_style/model/blocks/common.ts +21 -6
  189. package/internal/stores/data_style/model/blocks/index.ts +89 -59
  190. package/internal/stores/data_style/model/blocks/polyhedron.ts +101 -44
  191. package/internal/stores/data_style/model/blocks/vertex.ts +107 -42
  192. package/internal/stores/data_style/model/blocks/visibility.ts +17 -4
  193. package/internal/stores/data_style/model/color.ts +171 -83
  194. package/internal/stores/data_style/model/common.ts +70 -21
  195. package/internal/stores/data_style/model/corners/color.ts +43 -11
  196. package/internal/stores/data_style/model/corners/common.ts +25 -6
  197. package/internal/stores/data_style/model/corners/index.ts +66 -41
  198. package/internal/stores/data_style/model/corners/vertex.ts +105 -74
  199. package/internal/stores/data_style/model/corners/visibility.ts +19 -4
  200. package/internal/stores/data_style/model/edges/common.ts +12 -4
  201. package/internal/stores/data_style/model/edges/index.ts +2 -1
  202. package/internal/stores/data_style/model/edges/visibility.ts +24 -7
  203. package/internal/stores/data_style/model/index.ts +24 -11
  204. package/internal/stores/data_style/model/lines/color.ts +41 -11
  205. package/internal/stores/data_style/model/lines/common.ts +17 -6
  206. package/internal/stores/data_style/model/lines/edge.ts +105 -42
  207. package/internal/stores/data_style/model/lines/index.ts +86 -59
  208. package/internal/stores/data_style/model/lines/vertex.ts +105 -42
  209. package/internal/stores/data_style/model/lines/visibility.ts +17 -4
  210. package/internal/stores/data_style/model/points/common.ts +8 -4
  211. package/internal/stores/data_style/model/points/index.ts +10 -3
  212. package/internal/stores/data_style/model/points/size.ts +12 -4
  213. package/internal/stores/data_style/model/points/visibility.ts +16 -6
  214. package/internal/stores/data_style/model/selection.ts +80 -58
  215. package/internal/stores/data_style/model/surfaces/color.ts +41 -11
  216. package/internal/stores/data_style/model/surfaces/common.ts +23 -6
  217. package/internal/stores/data_style/model/surfaces/index.ts +89 -59
  218. package/internal/stores/data_style/model/surfaces/polygon.ts +107 -67
  219. package/internal/stores/data_style/model/surfaces/vertex.ts +111 -67
  220. package/internal/stores/data_style/model/surfaces/visibility.ts +18 -5
  221. package/internal/stores/data_style/model/visibility.ts +82 -20
  222. package/internal/stores/data_style/state.ts +77 -65
  223. package/internal/stores/hybrid_viewer/brightness.ts +49 -31
  224. package/internal/stores/hybrid_viewer/camera.ts +191 -177
  225. package/internal/stores/hybrid_viewer/camera_animation.ts +11 -10
  226. package/internal/stores/hybrid_viewer/core.ts +64 -0
  227. package/internal/stores/hybrid_viewer/filters.ts +10 -16
  228. package/internal/stores/hybrid_viewer/highlight.ts +91 -130
  229. package/internal/stores/hybrid_viewer/ruler.ts +24 -15
  230. package/internal/stores/hybrid_viewer/scene.ts +96 -117
  231. package/internal/stores/hybrid_viewer/viewport.ts +74 -65
  232. package/internal/stores/hybrid_viewer/vtk_types.ts +13 -29
  233. package/internal/utils/api_fetch.ts +54 -23
  234. package/internal/utils/upload_file.ts +74 -53
  235. package/internal/utils/viewer_call.ts +22 -13
  236. package/internal/utils/ws_client.ts +24 -13
  237. package/nuxt.config.ts +58 -1
  238. package/package.json +20 -8
  239. package/server/api/cloud/extensions/run.post.ts +6 -10
  240. package/server/api/local/app/project_folder_path.post.ts +4 -4
  241. package/server/api/local/app/run_back.post.ts +5 -7
  242. package/server/api/local/app/run_viewer.post.ts +5 -7
  243. package/server/api/local/extensions/kill.post.ts +4 -3
  244. package/server/api/local/extensions/run.post.ts +7 -10
  245. package/server/api/local/extensions/upload.put.ts +44 -54
  246. package/server/api/microservice/app/get_is_app_ready.get.ts +4 -5
  247. package/server/api/microservice/app/set_app_base_url.post.ts +5 -6
  248. package/server/api/microservice/app/set_back_base_url.post.ts +5 -6
  249. package/server/api/microservice/app/set_is_app_ready.post.ts +5 -6
  250. package/server/api/microservice/app/set_viewer_base_url.post.ts +5 -6
  251. package/server/api/microservice/extensions/download.post.ts +5 -4
  252. package/server/api/serverless/run_cloud.post.ts +53 -11
  253. package/server/utils/app_config.ts +29 -22
  254. package/server/utils/cleanup.ts +60 -30
  255. package/server/utils/cloud.ts +9 -8
  256. package/server/utils/extension.ts +23 -9
  257. package/server/utils/microservices.ts +33 -24
  258. package/server/utils/path.ts +4 -4
  259. package/server/utils/scripts.ts +26 -23
  260. package/server/utils/server.ts +2 -2
  261. package/server/utils/server_config.ts +41 -27
  262. package/server/utils/stream.ts +6 -0
  263. package/server/utils/ws_client.ts +42 -8
  264. package/shared/scripts.ts +15 -10
  265. package/shared/utils/call_raw.ts +23 -16
  266. package/shared/utils/call_schema.ts +5 -8
  267. package/shared/utils/fetch_raw.ts +87 -47
  268. package/shared/utils/fetch_schema.ts +6 -9
  269. package/shared/utils/file.ts +8 -2
  270. package/shared/utils/response_handlers/load.ts +26 -11
  271. package/shared/utils/types.ts +9 -9
  272. package/shared/utils/validate_schema.ts +1 -1
  273. package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +0 -276
  274. package/server/types/vendor.d.ts +0 -64
  275. package/server/utils/server_config.js +0 -43
  276. package/shared/utils/call_raw.js +0 -30
  277. package/shared/utils/fetch_raw.js +0 -40
  278. /package/{opengeodeweb_front_schemas.js → .build/opengeodeweb_front_schemas.js} +0 -0
  279. /package/{server → .build/server}/utils/server.js +0 -0
  280. /package/{shared → .build/shared}/app_mode.js +0 -0
  281. /package/{shared → .build/shared}/utils/parse_boolean.js +0 -0
  282. /package/{shared → .build/shared}/utils/types.js +0 -0
@@ -2,18 +2,50 @@ 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 { type DataStyleSnapshot, useDataStyleStore } from "@ogw_front/stores/data_style";
6
+ import { type NewDataItem, useDataStore } from "@ogw_front/stores/data";
7
+ import { type TreeviewSnapshot, useTreeviewStore } from "@ogw_front/stores/treeview";
8
+ import type { CameraSnapshot } from "@ogw_internal/stores/hybrid_viewer/camera";
9
+ import type { ModelComponentRecord } from "@ogw_front/stores/data_helpers/mesh.js";
10
+ import type { ModelComponentRelationRecord } from "@ogw_front/stores/data.js";
5
11
  import { fetchRaw } from "@ogw_shared/utils/fetch_raw";
6
12
  import { importWorkflowFromSnapshot } from "@ogw_front/utils/import_workflow";
7
13
  import { useAppStore } from "@ogw_front/stores/app";
8
14
  import { useBackStore } from "@ogw_front/stores/back";
9
- import { useDataStore } from "@ogw_front/stores/data";
10
- import { useDataStyleStore } from "@ogw_front/stores/data_style";
11
15
  import { useFeedbackStore } from "@ogw_front/stores/feedback";
12
16
  import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
13
- import { useTreeviewStore } from "@ogw_front/stores/treeview";
14
17
  import { useViewerStore } from "@ogw_front/stores/viewer";
15
18
 
16
- async function exportProject() {
19
+ interface ProjectDataSnapshot {
20
+ items: NewDataItem[];
21
+ modelComponents: ModelComponentRecord[];
22
+ modelComponentsRelations: ModelComponentRelationRecord[];
23
+ }
24
+
25
+ interface ProjectSnapshot {
26
+ treeview?: TreeviewSnapshot;
27
+ data?: ProjectDataSnapshot;
28
+ hybridViewer?: CameraSnapshot;
29
+ dataStyle?: DataStyleSnapshot;
30
+ }
31
+
32
+ // The backend response is an untyped network payload; this is the one place its shape is asserted.
33
+ function isImportSnapshotResponse(value: unknown): value is { snapshot?: ProjectSnapshot } {
34
+ return typeof value === "object" && value !== null;
35
+ }
36
+
37
+ function isFileDownloadData(
38
+ value: unknown,
39
+ ): value is string | ArrayBuffer | ArrayBufferView | Blob {
40
+ return (
41
+ typeof value === "string" ||
42
+ value instanceof ArrayBuffer ||
43
+ ArrayBuffer.isView(value) ||
44
+ value instanceof Blob
45
+ );
46
+ }
47
+
48
+ async function exportProject(): Promise<{ result: unknown }> {
17
49
  console.log("[export triggered]");
18
50
  const appStore = useAppStore();
19
51
  const backStore = useBackStore();
@@ -29,11 +61,38 @@ async function exportProject() {
29
61
  baseURL: backStore.base_url,
30
62
  });
31
63
 
64
+ if (!isFileDownloadData(result)) {
65
+ throw new Error("Unexpected export_project response type");
66
+ }
32
67
  fileDownload(result, defaultName);
33
68
  feedbackStore.add_success("Project exported successfully");
34
69
  return { result };
35
70
  }
36
71
 
72
+ async function releaseViewerDatabase(
73
+ client: ReturnType<typeof useViewerStore>["client"],
74
+ ): Promise<void> {
75
+ if (
76
+ client !== undefined &&
77
+ client.getConnection !== undefined &&
78
+ client.getConnection().getSession !== undefined
79
+ ) {
80
+ await client.getConnection().getSession().call("opengeodeweb_viewer.release_database", [{}]);
81
+ }
82
+ }
83
+
84
+ async function importProjectToViewer(
85
+ client: ReturnType<typeof useViewerStore>["client"],
86
+ ): Promise<void> {
87
+ if (
88
+ client !== undefined &&
89
+ client.getConnection !== undefined &&
90
+ client.getConnection().getSession !== undefined
91
+ ) {
92
+ await client.getConnection().getSession().call("opengeodeweb_viewer.import_project", [{}]);
93
+ }
94
+ }
95
+
37
96
  async function importProject(file: File): Promise<void> {
38
97
  const backStore = useBackStore();
39
98
  const dataStyleStore = useDataStyleStore();
@@ -44,21 +103,18 @@ async function importProject(file: File): Promise<void> {
44
103
 
45
104
  await viewerStore.ws_connect();
46
105
 
47
- const { client } = viewerStore;
48
- if (client && client.getConnection && client.getConnection().getSession) {
49
- await client.getConnection().getSession().call("opengeodeweb_viewer.release_database", [{}]);
50
- }
106
+ await releaseViewerDatabase(viewerStore.client);
51
107
  const resetVisualizationSchema = viewer_schemas.opengeodeweb_viewer.viewer.reset_visualization;
52
108
  const timeout = undefined;
53
109
  await viewerStore.request({ schema: resetVisualizationSchema, timeout });
54
110
 
55
111
  treeviewStore.clear();
56
- dataStore.clear();
112
+ await dataStore.clear();
57
113
  hybridViewerStore.clear();
58
114
 
59
115
  const importProjectSchema = back_schemas.opengeodeweb_back.import_project;
60
116
  const form = new FormData();
61
- const originalFileName = file && file.name ? file.name : "project.vease";
117
+ const originalFileName = file.name.length > 0 ? file.name : "project.vease";
62
118
  if (!originalFileName.toLowerCase().endsWith(".vease")) {
63
119
  throw new Error("Uploaded file must be a .vease");
64
120
  }
@@ -70,23 +126,24 @@ async function importProject(file: File): Promise<void> {
70
126
  method: importProjectSchema.methods[0],
71
127
  baseURL: backStore.base_url,
72
128
  });
73
- const snapshot = result && result.snapshot ? result.snapshot : {};
129
+ const snapshot = (isImportSnapshotResponse(result) ? result.snapshot : undefined) ?? {};
74
130
 
75
131
  treeviewStore.isImporting = true;
76
132
 
77
- const { client: client2 } = viewerStore;
78
- if (client2 && client2.getConnection && client2.getConnection().getSession) {
79
- await client2.getConnection().getSession().call("opengeodeweb_viewer.import_project", [{}]);
80
- }
133
+ await importProjectToViewer(viewerStore.client);
81
134
 
82
- await treeviewStore.importStores(snapshot.treeview);
83
- await dataStore.importStores(snapshot.data);
135
+ treeviewStore.importStores(snapshot.treeview);
136
+ if (snapshot.data !== undefined) {
137
+ await dataStore.importStores(snapshot.data);
138
+ }
84
139
  await hybridViewerStore.initHybridViewer();
85
140
 
86
- const items = snapshot?.data?.items || [];
141
+ const items = snapshot.data?.items ?? [];
87
142
  await importWorkflowFromSnapshot(items);
88
143
  await hybridViewerStore.importStores(snapshot.hybridViewer);
89
- await dataStyleStore.importStores(snapshot.dataStyle);
144
+ if (snapshot.dataStyle !== undefined) {
145
+ await dataStyleStore.importStores(snapshot.dataStyle);
146
+ }
90
147
  await dataStyleStore.applyAllStylesFromState();
91
148
 
92
149
  treeviewStore.finalizeImportSelection();
@@ -1,7 +1,4 @@
1
- // Not auto-fixable (eslint's sort-imports core rule has no autofixer) and this file's import order doesn't match its syntax-kind-then-alphabetical requirement - left as-is rather than manually reordered across the codebase for a purely cosmetic rule.
2
- // oxlint-disable eslint/sort-imports
3
1
  import { middleTruncate } from "@ogw_front/utils/string";
4
- import type { MaybeRefOrGetter } from "vue";
5
2
 
6
3
  const UUID_END_CHARS = 12;
7
4
  const ELLIPSIS_LENGTH = 3;
@@ -9,17 +6,20 @@ const MIN_START_CHARS = 4;
9
6
  const DEFAULT_ESTIMATED_CHAR_WIDTH = 8.5;
10
7
 
11
8
  interface ResponsiveMiddleTruncateOptions {
12
- estimatedCharWidth?: number;
13
- uuidEndChars?: number;
14
- ellipsisLength?: number;
15
- minStartChars?: number;
9
+ readonly estimatedCharWidth?: number;
10
+ readonly uuidEndChars?: number;
11
+ readonly ellipsisLength?: number;
12
+ readonly minStartChars?: number;
16
13
  }
17
14
 
15
+ // Same shape as Vue's MaybeRefOrGetter<T>, kept as a local alias for readability at call sites.
16
+ type ReadonlyMaybeRefOrGetter<Value> = Value | Ref<Value> | (() => Value);
17
+
18
18
  export function useResponsiveMiddleTruncate(
19
- textRef: MaybeRefOrGetter<string | undefined | null>,
20
- containerWidthRef: MaybeRefOrGetter<number | undefined>,
19
+ textRef: ReadonlyMaybeRefOrGetter<string | undefined | null>,
20
+ containerWidthRef: ReadonlyMaybeRefOrGetter<number | undefined>,
21
21
  options: ResponsiveMiddleTruncateOptions = {},
22
- ) {
22
+ ): ComputedRef<string> {
23
23
  const {
24
24
  estimatedCharWidth = DEFAULT_ESTIMATED_CHAR_WIDTH,
25
25
  uuidEndChars = UUID_END_CHARS,
@@ -29,11 +29,11 @@ export function useResponsiveMiddleTruncate(
29
29
 
30
30
  return computed(() => {
31
31
  const text = toValue(textRef);
32
- if (!text) {
32
+ if (text === undefined || text === null || text === "") {
33
33
  return "";
34
34
  }
35
35
 
36
- const width = toValue(containerWidthRef) || 0;
36
+ const width = toValue(containerWidthRef) ?? 0;
37
37
  const maxChars = Math.floor(width / estimatedCharWidth);
38
38
 
39
39
  if (maxChars <= 0 || text.length <= maxChars) {
@@ -43,6 +43,6 @@ export function useResponsiveMiddleTruncate(
43
43
  const endChars = Math.min(uuidEndChars, Math.floor(maxChars / ellipsisLength));
44
44
  const startChars = Math.max(minStartChars, maxChars - endChars - ellipsisLength);
45
45
 
46
- return middleTruncate(text, maxChars, startChars, endChars);
46
+ return middleTruncate(text, maxChars, startChars, endChars) ?? "";
47
47
  });
48
48
  }
@@ -1,13 +1,36 @@
1
- export function useStepperTree(steps: unknown[], initial_state: Record<string, unknown> = {}) {
1
+ interface StepperTreeApi {
2
+ state: Record<string, unknown>;
3
+ update_values: (keys_values_object: Record<string, unknown>) => void;
4
+ increment_step: () => void;
5
+ decrement_step: () => void;
6
+ reset_values: () => void;
7
+ }
8
+
9
+ function isUnknownArray(value: unknown): value is unknown[] {
10
+ return Array.isArray(value);
11
+ }
12
+
13
+ function get_current_step_index(state: Record<string, unknown>): number {
14
+ const value = state.current_step_index;
15
+ return typeof value === "number" ? value : 0;
16
+ }
17
+
18
+ function build_initial_state_unref(
19
+ initial_state: Record<string, unknown>,
20
+ ): Record<string, unknown> {
2
21
  const initial_state_unref: Record<string, unknown> = {};
3
22
  for (const [key, value] of Object.entries(initial_state)) {
4
- const unref_val = unref(value);
5
- if (Array.isArray(unref_val)) {
6
- initial_state_unref[key] = [...unref_val];
7
- } else {
8
- initial_state_unref[key] = unref_val;
9
- }
23
+ const unref_val: unknown = unref(value);
24
+ initial_state_unref[key] = isUnknownArray(unref_val) ? [...unref_val] : unref_val;
10
25
  }
26
+ return initial_state_unref;
27
+ }
28
+
29
+ export function useStepperTree(
30
+ steps: readonly unknown[],
31
+ initial_state: Record<string, unknown> = {},
32
+ ): StepperTreeApi {
33
+ const initial_state_unref = build_initial_state_unref(initial_state);
11
34
  const state = reactive<Record<string, unknown>>({
12
35
  current_step_index: 0,
13
36
  navigating_back: false,
@@ -16,7 +39,7 @@ export function useStepperTree(steps: unknown[], initial_state: Record<string, u
16
39
  });
17
40
 
18
41
  watch(
19
- () => state.current_step_index as number,
42
+ () => get_current_step_index(state),
20
43
  (newVal, oldVal) => {
21
44
  if (newVal < oldVal) {
22
45
  state.navigating_back = true;
@@ -31,18 +54,18 @@ export function useStepperTree(steps: unknown[], initial_state: Record<string, u
31
54
  }
32
55
 
33
56
  function increment_step(): void {
34
- (state.current_step_index as number) += 1;
57
+ state.current_step_index = get_current_step_index(state) + 1;
35
58
  }
36
59
 
37
60
  function decrement_step(): void {
38
- (state.current_step_index as number) -= 1;
61
+ state.current_step_index = get_current_step_index(state) - 1;
39
62
  }
40
63
 
41
64
  function reset_values(): void {
42
65
  state.current_step_index = 0;
43
66
  state.navigating_back = false;
44
67
  for (const [key, initial_val] of Object.entries(initial_state_unref)) {
45
- state[key] = Array.isArray(initial_val) ? [...initial_val] : initial_val;
68
+ state[key] = isUnknownArray(initial_val) ? [...initial_val] : initial_val;
46
69
  }
47
70
  }
48
71
 
@@ -1,20 +1,37 @@
1
- import type { MaybeRefOrGetter } from "vue";
1
+ import type { Ref } from "vue";
2
+
3
+ // Same shape as Vue's MaybeRefOrGetter<T>, kept as a local alias for readability at call sites.
4
+ type ReadonlyMaybeRefOrGetter<Value> = Value | Ref<Value> | (() => Value);
2
5
 
3
6
  // This composable filters/sorts different flavors of "category with children" trees (treeview groups, model component/collection groups, ...); this shape captures just the fields it reads/writes, generically, across all of them.
4
7
  interface FilterableItem {
5
- id: unknown;
6
- title?: string;
7
- children?: FilterableItem[];
8
+ readonly id: unknown;
9
+ readonly title?: string;
10
+ readonly children?: readonly FilterableItem[];
8
11
  }
9
12
 
10
13
  interface FilterContext {
11
- raw?: FilterableItem;
14
+ readonly raw?: FilterableItem;
12
15
  }
13
16
 
14
17
  interface TreeFilterOptions {
15
- recursiveSort?: boolean;
16
- defaultSort?: string;
17
- defaultFilters?: Record<string, boolean>;
18
+ readonly recursiveSort?: boolean;
19
+ readonly defaultSort?: string;
20
+ readonly defaultFilters?: Record<string, boolean>;
21
+ }
22
+
23
+ interface UseTreeFilterReturn {
24
+ search: Ref<string>;
25
+ sortType: Ref<string>;
26
+ filterOptions: Ref<Record<string, boolean>>;
27
+ processedItems: ComputedRef<FilterableItem[]>;
28
+ availableFilterOptions: ComputedRef<string[]>;
29
+ toggleSort: () => void;
30
+ customFilter: typeof customFilter;
31
+ applySearchFilter: (
32
+ newSelection: readonly unknown[],
33
+ previousSelection?: readonly unknown[],
34
+ ) => unknown[];
18
35
  }
19
36
 
20
37
  function customFilter(
@@ -22,37 +39,50 @@ function customFilter(
22
39
  searchQuery: string | undefined,
23
40
  item: FilterContext,
24
41
  ): boolean {
25
- if (!searchQuery) {
42
+ if (searchQuery === undefined || searchQuery === "") {
26
43
  return true;
27
44
  }
28
- if (!item || !item.raw) {
45
+ if (!item.raw) {
29
46
  return false;
30
47
  }
31
48
  const query = searchQuery.toLowerCase();
32
- const { title = "", id = value } = item.raw || {};
49
+ const { title = "", id = value } = item.raw;
33
50
  return [title, id].some((field) => String(field).toLowerCase().includes(query));
34
51
  }
35
52
 
53
+ // Extracted so we never call String() directly on a value typed as `unknown`/`any`.
54
+ // The `id` field can be anything at runtime, so only stringify primitives that have a sane toString.
55
+ // Anything else falls back to "" instead of risking "[object Object]".
56
+ function toSortKey(item: FilterableItem, field: "title" | "id"): string {
57
+ const raw = item[field] ?? item.id ?? "";
58
+ if (typeof raw === "string" || typeof raw === "number" || typeof raw === "boolean") {
59
+ return String(raw);
60
+ }
61
+ return "";
62
+ }
63
+
36
64
  function sortAndFormatItems(
37
- itemList: FilterableItem[] | undefined | null,
65
+ itemList: readonly FilterableItem[] | undefined | null,
38
66
  sortType: string,
39
67
  options: TreeFilterOptions = {},
40
68
  ): FilterableItem[] {
41
- if (!itemList || !Array.isArray(itemList)) {
69
+ if (!itemList) {
42
70
  return [];
43
71
  }
44
72
  const field: "title" | "id" = sortType === "name" ? "title" : "id";
45
73
  const localeOptions: Intl.CollatorOptions = { numeric: true, sensitivity: "base" };
46
74
 
47
- const sorted = itemList
75
+ // Copy into a plain mutable array up front: chaining .filter()/.toSorted() straight off the
76
+ // Readonly-typed parameter (previously combined with an Array.isArray guard here) has been
77
+ // Observed to make oxlint's type-aware analysis silently widen the result to `any[]`.
78
+ const items: FilterableItem[] = [...itemList];
79
+ const sorted = items
48
80
  .filter((item) => item !== null && item !== undefined)
49
- .toSorted((itemA, itemB) => {
50
- const fieldA = String(itemA[field] || itemA.id || "");
51
- const fieldB = String(itemB[field] || itemB.id || "");
52
- return fieldA.localeCompare(fieldB, undefined, localeOptions);
53
- });
81
+ .toSorted((itemA, itemB) =>
82
+ toSortKey(itemA, field).localeCompare(toSortKey(itemB, field), undefined, localeOptions),
83
+ );
54
84
 
55
- if (options.recursiveSort) {
85
+ if (options.recursiveSort === true) {
56
86
  return sorted.map((item) => {
57
87
  if (item.children && item.children.length > 0) {
58
88
  return {
@@ -67,39 +97,31 @@ function sortAndFormatItems(
67
97
  }
68
98
 
69
99
  function useTreeFilter(
70
- itemsIn: MaybeRefOrGetter<FilterableItem[]>,
100
+ itemsIn: ReadonlyMaybeRefOrGetter<readonly FilterableItem[]>,
71
101
  options: TreeFilterOptions = {},
72
- ) {
102
+ ): UseTreeFilterReturn {
73
103
  const rawItems = typeof itemsIn === "function" ? computed(itemsIn) : toRef(itemsIn);
74
104
  const search = ref("");
75
- const sortType = ref(options.defaultSort || "name");
76
- const filterOptions = ref<Record<string, boolean>>(options.defaultFilters || {});
105
+ const sortType = ref(options.defaultSort ?? "name");
106
+ const filterOptions = ref<Record<string, boolean>>({ ...options.defaultFilters });
77
107
 
78
- const availableFilterOptions = computed(() => {
79
- if (!rawItems.value) {
80
- return [];
81
- }
82
- return rawItems.value.map((category) => String(category.title || category.id));
83
- });
108
+ const availableFilterOptions = computed(() =>
109
+ rawItems.value.map((category) => String(category.title ?? category.id)),
110
+ );
84
111
 
85
112
  watch(
86
113
  availableFilterOptions,
87
- (newOptions) => {
114
+ (newOptions: readonly string[]) => {
88
115
  for (const option of newOptions) {
89
- if (filterOptions.value[option] === undefined) {
90
- filterOptions.value[option] = true;
91
- }
116
+ filterOptions.value[option] ??= true;
92
117
  }
93
118
  },
94
119
  { immediate: true },
95
120
  );
96
121
 
97
122
  const processedItems = computed(() => {
98
- if (!rawItems.value) {
99
- return [];
100
- }
101
123
  const filteredByCategory = rawItems.value.filter((category) => {
102
- const key = String(category.title || category.id);
124
+ const key = String(category.title ?? category.id);
103
125
  return filterOptions.value[key] !== false;
104
126
  });
105
127
 
@@ -111,7 +133,7 @@ function useTreeFilter(
111
133
 
112
134
  const result: FilterableItem[] = [];
113
135
  for (const category of sorted) {
114
- const children = (category.children || []).filter((child) =>
136
+ const children = (category.children ?? []).filter((child) =>
115
137
  customFilter(child.id, search.value, { raw: child }),
116
138
  );
117
139
  if (children.length > 0 || customFilter(category.id, search.value, { raw: category })) {
@@ -127,7 +149,7 @@ function useTreeFilter(
127
149
 
128
150
  const allItems = computed(() => {
129
151
  const map = new Map<unknown, FilterableItem>();
130
- function traverse(items: FilterableItem[]): void {
152
+ function traverse(items: readonly FilterableItem[]): void {
131
153
  for (const item of items) {
132
154
  map.set(item.id, item);
133
155
  if (item.children) {
@@ -135,16 +157,16 @@ function useTreeFilter(
135
157
  }
136
158
  }
137
159
  }
138
- traverse(rawItems.value || []);
160
+ traverse(rawItems.value);
139
161
  return map;
140
162
  });
141
163
 
142
164
  function applySearchFilter(
143
- newSelection: unknown[],
144
- previousSelection: unknown[] = [],
165
+ newSelection: readonly unknown[],
166
+ previousSelection: readonly unknown[] = [],
145
167
  ): unknown[] {
146
168
  if (!search.value) {
147
- return newSelection;
169
+ return [...newSelection];
148
170
  }
149
171
  const allItemsMap = allItems.value;
150
172
  function matches(id: unknown): boolean {
@@ -1,6 +1,3 @@
1
- // Not auto-fixable (eslint's sort-imports core rule has no autofixer) and this file's import order doesn't match its syntax-kind-then-alphabetical requirement - left as-is rather than manually reordered across the codebase for a purely cosmetic rule.
2
- // oxlint-disable eslint/sort-imports
3
- import type { Ref } from "vue";
4
1
  import type { DisplayItem, EmitFn } from "./virtual_tree";
5
2
 
6
3
  interface VisibleBounds {
@@ -14,6 +11,20 @@ interface ScrollInfo {
14
11
  itemHeight: number;
15
12
  }
16
13
 
14
+ type ReadonlyDisplayItem = Omit<DisplayItem, "raw"> & {
15
+ readonly raw: Record<string, unknown>;
16
+ };
17
+
18
+ interface KeyboardEventLike {
19
+ readonly key: string;
20
+ preventDefault: () => void;
21
+ }
22
+
23
+ interface UseTreeKeyboardNavReturn {
24
+ focusedIndex: Ref<number>;
25
+ handleKeyDown: (event: KeyboardEventLike) => void;
26
+ }
27
+
17
28
  function getBaseIndex(
18
29
  currentIndex: number,
19
30
  lastIndex: number,
@@ -38,17 +49,17 @@ function getBaseIndex(
38
49
  }
39
50
 
40
51
  export function useTreeKeyboardNav(
41
- displayItems: Ref<DisplayItem[]>,
52
+ displayItems: Ref<readonly ReadonlyDisplayItem[]>,
42
53
  emit: EmitFn,
43
54
  scrollToIndex: (index: number) => void,
44
55
  toggleOpen: (raw: Record<string, unknown>) => void,
45
- handleItemClick: (item: DisplayItem, index: number) => void,
56
+ handleItemClick: (item: ReadonlyDisplayItem, index: number) => void,
46
57
  getScrollInfo: (() => ScrollInfo | undefined) | undefined,
47
58
  externalFocusedIndex: Ref<number> | undefined,
48
- ) {
49
- const focusedIndex = externalFocusedIndex || ref(-1);
59
+ ): UseTreeKeyboardNavReturn {
60
+ const focusedIndex = externalFocusedIndex ?? ref(-1);
50
61
 
51
- function findParentIndex(item: DisplayItem, currentIndex: number): number {
62
+ function findParentIndex(item: ReadonlyDisplayItem, currentIndex: number): number {
52
63
  for (let index = currentIndex - 1; index >= 0; index -= 1) {
53
64
  const candidate = displayItems.value[index];
54
65
  if (candidate && candidate.depth < item.depth) {
@@ -74,7 +85,7 @@ export function useTreeKeyboardNav(
74
85
  }
75
86
 
76
87
  function handleExpandOrNext(
77
- item: DisplayItem | undefined,
88
+ item: ReadonlyDisplayItem | undefined,
78
89
  currentIndex: number,
79
90
  lastIndex: number,
80
91
  ): number {
@@ -85,7 +96,10 @@ export function useTreeKeyboardNav(
85
96
  return Math.min(currentIndex + 1, lastIndex);
86
97
  }
87
98
 
88
- function handleCollapseOrParent(item: DisplayItem | undefined, currentIndex: number): number {
99
+ function handleCollapseOrParent(
100
+ item: ReadonlyDisplayItem | undefined,
101
+ currentIndex: number,
102
+ ): number {
89
103
  if (item && !item.isLeaf && item.isOpen) {
90
104
  toggleOpen(item.raw);
91
105
  return currentIndex;
@@ -129,7 +143,7 @@ export function useTreeKeyboardNav(
129
143
  return currentIndex;
130
144
  }
131
145
 
132
- function handleKeyDown(event: KeyboardEvent): void {
146
+ function handleKeyDown(event: KeyboardEventLike): void {
133
147
  if (displayItems.value.length === 0) {
134
148
  return;
135
149
  }
@@ -1,6 +1,3 @@
1
- // Not auto-fixable (eslint's sort-imports core rule has no autofixer) and this file's import order doesn't match its syntax-kind-then-alphabetical requirement - left as-is rather than manually reordered across the codebase for a purely cosmetic rule.
2
- // oxlint-disable eslint/sort-imports
3
- import type { MaybeRefOrGetter, Ref } from "vue";
4
1
  import type { DisplayItem, EmitFn, ItemPropsConfig } from "./virtual_tree";
5
2
 
6
3
  interface TreeScrollProps {
@@ -8,24 +5,57 @@ interface TreeScrollProps {
8
5
  }
9
6
 
10
7
  interface ScrollableElement {
11
- $el: { scrollTop: number; clientHeight: number };
8
+ $el: { scrollTop: number; clientHeight: number } | undefined;
9
+ }
10
+
11
+ interface ScrollInfo {
12
+ scrollTop: number;
13
+ containerHeight: number;
14
+ itemHeight: number;
15
+ }
16
+
17
+ type ReadonlyMaybeRefOrGetter<Value> = Value | Ref<Value> | (() => Value);
18
+
19
+ type ReadonlyDisplayItem = Omit<DisplayItem, "raw"> & {
20
+ readonly raw: Record<string, unknown>;
21
+ };
22
+
23
+ interface ScrollEventLike {
24
+ readonly target: EventTarget | null;
25
+ }
26
+
27
+ interface UseTreeScrollReturn {
28
+ internalScrollTop: Ref<number>;
29
+ virtualScrollRef: Ref<ScrollableElement | undefined>;
30
+ stickyHeader: ComputedRef<ReadonlyDisplayItem | undefined>;
31
+ handleScroll: (event: ScrollEventLike) => void;
32
+ scrollToIndex: (index: number) => void;
33
+ getScrollInfo: () => ScrollInfo;
34
+ }
35
+
36
+ function isHtmlElement(value: EventTarget | null): value is HTMLElement {
37
+ return value instanceof HTMLElement;
12
38
  }
13
39
 
14
40
  export function useTreeScroll(
15
- propsIn: MaybeRefOrGetter<TreeScrollProps>,
41
+ propsIn: ReadonlyMaybeRefOrGetter<TreeScrollProps>,
16
42
  emit: EmitFn,
17
- displayItems: Ref<DisplayItem[]>,
43
+ displayItems: Ref<readonly ReadonlyDisplayItem[]>,
18
44
  actualItemProps: Ref<ItemPropsConfig>,
19
- ) {
45
+ ): UseTreeScrollReturn {
20
46
  const SCROLL_STICKY_THRESHOLD = 10;
21
47
  const DEFAULT_ITEM_HEIGHT = 28;
22
48
 
23
49
  const props = toRef(propsIn);
24
- const internalScrollTop = ref(props.value.scrollTop || 0);
50
+ const internalScrollTop = ref(props.value.scrollTop ?? 0);
25
51
  const virtualScrollRef = ref<ScrollableElement | undefined>(undefined);
26
52
 
27
- function handleScroll(event: Event): void {
28
- const { scrollTop } = event.target as HTMLElement;
53
+ function handleScroll(event: ScrollEventLike): void {
54
+ const { target } = event;
55
+ if (!isHtmlElement(target)) {
56
+ return;
57
+ }
58
+ const { scrollTop } = target;
29
59
  internalScrollTop.value = scrollTop;
30
60
  emit("update:scrollTop", scrollTop);
31
61
  }
@@ -35,7 +65,7 @@ export function useTreeScroll(
35
65
  (newVal = 0) => {
36
66
  if (Math.abs(newVal - internalScrollTop.value) > 1) {
37
67
  internalScrollTop.value = newVal;
38
- if (virtualScrollRef.value && virtualScrollRef.value.$el) {
68
+ if (virtualScrollRef.value !== undefined && virtualScrollRef.value.$el !== undefined) {
39
69
  virtualScrollRef.value.$el.scrollTop = newVal;
40
70
  }
41
71
  }
@@ -76,12 +106,12 @@ export function useTreeScroll(
76
106
  });
77
107
 
78
108
  function scrollToIndex(index: number): void {
79
- if (index === -1 || !virtualScrollRef.value) {
109
+ if (index === -1 || virtualScrollRef.value === undefined) {
80
110
  return;
81
111
  }
82
112
 
83
113
  const container = virtualScrollRef.value.$el;
84
- if (!container) {
114
+ if (container === undefined) {
85
115
  return;
86
116
  }
87
117
 
@@ -100,7 +130,7 @@ export function useTreeScroll(
100
130
  }
101
131
  }
102
132
 
103
- function getScrollInfo() {
133
+ function getScrollInfo(): ScrollInfo {
104
134
  const container = virtualScrollRef.value?.$el;
105
135
  const containerHeight = container ? container.clientHeight : 0;
106
136
  const itemHeight = actualItemProps.value?.height || DEFAULT_ITEM_HEIGHT;