@geode/opengeodeweb-front 10.34.0-rc.8 → 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
@@ -1,8 +1,5 @@
1
+ import type { JsonRpcSchema } from "@ogw_shared/utils/types";
1
2
  import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json";
2
- import { computed } from "vue";
3
- // oxlint-disable-next-line eslint/no-duplicate-imports
4
- import type { Ref } from "vue";
5
-
6
3
  import { getAttributeRange } from "@ogw_front/utils/attributes";
7
4
  import { useBackStore } from "@ogw_front/stores/back";
8
5
  import { useDataStyleStore } from "@ogw_front/stores/data_style";
@@ -19,26 +16,67 @@ interface ActiveComponent extends ComponentNameEntry {
19
16
  attributeType: string;
20
17
  }
21
18
 
22
- // This composable resolves a batch of dynamically-named getter/setter methods on the data style store (e.g. "meshPointsVertexAttributeRange", "setMeshPointsVertexAttributeRange", ...) - the store's real, fully-typed surface has no index signature for this, so dynamic lookups are cast through this loosely-typed view of it, matching how these methods are actually shaped (getters take an id and return a value, setters take an id plus arbitrary arguments).
23
- type DynamicStore = Record<string, ((...args: unknown[]) => unknown) | undefined>;
19
+ // This composable resolves a batch of dynamically-named getter/setter methods on the data style store (e.g. "meshPointsVertexAttributeRange", "setMeshPointsVertexAttributeRange", ...) - the store's real, fully-typed surface has no index signature for this, so dynamic lookups go through this type guard instead of an unsafe cast of the whole store (which mixes these methods with state refs and other members), matching how these methods are actually shaped (getters take an id and return a value, setters take an id plus arbitrary arguments).
20
+ type DynamicStoreMethod = (...args: readonly unknown[]) => unknown;
21
+
22
+ function isDynamicStoreMethod(value: unknown): value is DynamicStoreMethod {
23
+ return typeof value === "function";
24
+ }
25
+
26
+ function getDynamicStoreMethod(store: object, key: string): DynamicStoreMethod | undefined {
27
+ const value: unknown = Reflect.get(store, key);
28
+ return isDynamicStoreMethod(value) ? value : undefined;
29
+ }
24
30
 
25
31
  interface AttributeStyleComponent {
26
32
  coloring?: { active?: string };
27
33
  }
28
34
 
29
35
  interface AttributeResponse {
30
- attributes?: {
31
- attribute_name?: string;
32
- min_values?: number[];
33
- max_values?: number[];
34
- min_value?: number;
35
- max_value?: number;
36
+ readonly attributes?: readonly {
37
+ readonly attribute_name?: string;
38
+ readonly min_values?: readonly number[];
39
+ readonly max_values?: readonly number[];
40
+ readonly min_value?: number;
41
+ readonly max_value?: number;
36
42
  }[];
37
43
  }
38
44
 
39
- export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
45
+ function isColoringValue(
46
+ value: unknown,
47
+ ): value is NonNullable<AttributeStyleComponent["coloring"]> {
48
+ return typeof value === "object" && value !== null;
49
+ }
50
+
51
+ function isJsonRpcSchema(value: unknown): value is JsonRpcSchema {
52
+ return (
53
+ typeof value === "object" && value !== null && "$id" in value && typeof value.$id === "string"
54
+ );
55
+ }
56
+
57
+ function isAttributeResponse(value: unknown): value is AttributeResponse {
58
+ return typeof value === "object" && value !== null;
59
+ }
60
+
61
+ function isNumberArray(value: unknown): value is number[] {
62
+ return Array.isArray(value) && value.every((item) => typeof item === "number");
63
+ }
64
+
65
+ function isStringOrUndefined(value: unknown): value is string | undefined {
66
+ return value === undefined || typeof value === "string";
67
+ }
68
+
69
+ function isNumberOrUndefined(value: unknown): value is number | undefined {
70
+ return value === undefined || typeof value === "number";
71
+ }
72
+
73
+ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>): {
74
+ currentColormap: typeof currentColormap;
75
+ currentRange: typeof currentRange;
76
+ applyGlobalColormap: typeof applyGlobalColormap;
77
+ resetGlobalRange: typeof resetGlobalRange;
78
+ } {
40
79
  const dataStyleStore = useDataStyleStore();
41
- const dynamicDataStyleStore = dataStyleStore as unknown as DynamicStore;
42
80
  const hybridViewerStore = useHybridViewerStore();
43
81
  const backStore = useBackStore();
44
82
 
@@ -51,23 +89,47 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
51
89
  ];
52
90
 
53
91
  function getActiveComponents(targetId: string): ActiveComponent[] {
54
- const style = dataStyleStore.getStyle(targetId) as unknown as Record<
55
- string,
56
- AttributeStyleComponent | undefined
57
- >;
92
+ const style = dataStyleStore.getStyle(targetId);
58
93
  const activeComponents: ActiveComponent[] = [];
59
- if (!style) {
60
- return activeComponents;
61
- }
62
94
  for (const { key, getterKey, setterKey } of componentNames) {
63
- const componentStyle = style[key];
64
- if (!componentStyle || !componentStyle.coloring) {
95
+ let componentStyle: Record<string, unknown> | undefined = undefined;
96
+ switch (key) {
97
+ case "points": {
98
+ componentStyle = style.points;
99
+ break;
100
+ }
101
+ case "edges": {
102
+ componentStyle = style.edges;
103
+ break;
104
+ }
105
+ case "polygons": {
106
+ componentStyle = style.polygons;
107
+ break;
108
+ }
109
+ case "cells": {
110
+ componentStyle = style.cells;
111
+ break;
112
+ }
113
+ case "polyhedra": {
114
+ componentStyle = style.polyhedra;
115
+ break;
116
+ }
117
+ default: {
118
+ componentStyle = undefined;
119
+ }
120
+ }
121
+ if (componentStyle === undefined) {
65
122
  continue;
66
123
  }
67
124
 
68
- const activeColoring = componentStyle.coloring.active;
125
+ const { coloring } = componentStyle;
126
+ if (!isColoringValue(coloring)) {
127
+ continue;
128
+ }
129
+
130
+ const { active: activeColoring } = coloring;
69
131
  if (
70
- !activeColoring ||
132
+ activeColoring === undefined ||
71
133
  !["vertex", "edge", "polygon", "cell", "polyhedron"].includes(activeColoring)
72
134
  ) {
73
135
  continue;
@@ -79,19 +141,19 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
79
141
  return activeComponents;
80
142
  }
81
143
 
82
- const currentColormap = computed(() => {
144
+ const currentColormap = computed((): string => {
83
145
  const targetId = dataIdRef.value;
84
- if (!targetId) {
146
+ if (targetId === undefined || targetId === "") {
85
147
  return "batlow";
86
148
  }
87
149
 
88
150
  for (const comp of getActiveComponents(targetId)) {
89
151
  const getterName = `${comp.getterKey}${comp.attributeType}ColorMap`;
90
- const getter = dynamicDataStyleStore[getterName];
152
+ const getter = getDynamicStoreMethod(dataStyleStore, getterName);
91
153
  if (getter) {
92
154
  const colorMap = getter(targetId);
93
- if (colorMap) {
94
- return colorMap as string;
155
+ if (typeof colorMap === "string" && colorMap.length > 0) {
156
+ return colorMap;
95
157
  }
96
158
  }
97
159
  }
@@ -99,18 +161,39 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
99
161
  return "batlow";
100
162
  });
101
163
 
102
- const currentRange = computed<[number, number]>({
103
- get() {
164
+ async function applyCurrentRange(newValue: readonly [number, number]): Promise<void> {
165
+ const targetId = dataIdRef.value;
166
+ if (targetId === undefined || targetId === "") {
167
+ return;
168
+ }
169
+
170
+ let updated = false;
171
+ for (const comp of getActiveComponents(targetId)) {
172
+ const setterName = `set${comp.setterKey}${comp.attributeType}Range`;
173
+ const setter = getDynamicStoreMethod(dataStyleStore, setterName);
174
+ if (setter) {
175
+ setter(targetId, newValue[0], newValue[1]);
176
+ updated = true;
177
+ }
178
+ }
179
+ if (updated) {
180
+ await hybridViewerStore.remoteRender();
181
+ }
182
+ }
183
+
184
+ const currentRange = computed<readonly [number, number]>({
185
+ get(): readonly [number, number] {
104
186
  const targetId = dataIdRef.value;
105
- if (!targetId) {
187
+ if (targetId === undefined || targetId === "") {
106
188
  return [0, 1];
107
189
  }
108
190
 
109
191
  for (const comp of getActiveComponents(targetId)) {
110
192
  const getterName = `${comp.getterKey}${comp.attributeType}Range`;
111
- const getter = dynamicDataStyleStore[getterName];
193
+ const getter = getDynamicStoreMethod(dataStyleStore, getterName);
112
194
  if (getter) {
113
- const range = getter(targetId) as number[] | undefined;
195
+ const rawRange = getter(targetId);
196
+ const range = isNumberArray(rawRange) ? rawRange : undefined;
114
197
  if (range && range.length === 2) {
115
198
  return [range[0] ?? 0, range[1] ?? 1];
116
199
  }
@@ -118,30 +201,16 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
118
201
  }
119
202
  return [0, 1];
120
203
  },
121
- set(newValue) {
122
- const targetId = dataIdRef.value;
123
- if (!targetId) {
124
- return;
125
- }
126
-
127
- let updated = false;
128
- for (const comp of getActiveComponents(targetId)) {
129
- const setterName = `set${comp.setterKey}${comp.attributeType}Range`;
130
- const setter = dynamicDataStyleStore[setterName];
131
- if (setter) {
132
- setter(targetId, newValue[0], newValue[1]);
133
- updated = true;
134
- }
135
- }
136
- if (updated) {
137
- hybridViewerStore.remoteRender();
138
- }
204
+ // Vue's WritableComputedOptions setter is strictly `(v: T) => void`, so the async render call is delegated to a helper (see the same trade-off in `app/composables/hover_highlight.ts`'s `onHoverEnter`).
205
+ set: (newValue: readonly [number, number]): void => {
206
+ /* oxlint-disable-next-line promise/prefer-await-to-then -- setter cannot be async; see comment above. */
207
+ applyCurrentRange(newValue).catch(() => undefined);
139
208
  },
140
209
  });
141
210
 
142
211
  async function applyGlobalColormap(newMap: string): Promise<void> {
143
212
  const targetId = dataIdRef.value;
144
- if (!targetId) {
213
+ if (targetId === undefined || targetId === "") {
145
214
  return;
146
215
  }
147
216
 
@@ -149,7 +218,7 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
149
218
 
150
219
  for (const comp of getActiveComponents(targetId)) {
151
220
  const setterName = `set${comp.setterKey}${comp.attributeType}ColorMap`;
152
- const setter = dynamicDataStyleStore[setterName];
221
+ const setter = getDynamicStoreMethod(dataStyleStore, setterName);
153
222
 
154
223
  if (setter) {
155
224
  promises.push(Promise.resolve(setter(targetId, newMap)));
@@ -157,61 +226,72 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>) {
157
226
  }
158
227
 
159
228
  await Promise.all(promises);
160
- hybridViewerStore.remoteRender();
229
+ await hybridViewerStore.remoteRender();
161
230
  }
162
231
 
163
- function resetGlobalRange(): void {
232
+ async function resetGlobalRange(): Promise<void> {
164
233
  const targetId = dataIdRef.value;
165
- if (!targetId) {
234
+ if (targetId === undefined || targetId === "") {
166
235
  return;
167
236
  }
168
237
 
238
+ const requestPromises: Promise<unknown>[] = [];
239
+
169
240
  for (const comp of getActiveComponents(targetId)) {
170
241
  const { activeColoring, attributeType, getterKey, setterKey } = comp;
171
242
 
172
- const nameGetter = dynamicDataStyleStore[`${getterKey}${attributeType}Name`];
173
- const itemGetter = dynamicDataStyleStore[`${getterKey}${attributeType}Item`];
243
+ const nameGetter = getDynamicStoreMethod(dataStyleStore, `${getterKey}${attributeType}Name`);
244
+ const itemGetter = getDynamicStoreMethod(dataStyleStore, `${getterKey}${attributeType}Item`);
174
245
  if (!nameGetter || !itemGetter) {
175
246
  continue;
176
247
  }
177
248
 
178
- const attrName = nameGetter(targetId) as string | undefined;
179
- const attrItem = (itemGetter(targetId) as number | undefined) ?? 0;
249
+ const rawAttrName = nameGetter(targetId);
250
+ const attrName = isStringOrUndefined(rawAttrName) ? rawAttrName : undefined;
251
+ const rawAttrItem = itemGetter(targetId);
252
+ const attrItem = (isNumberOrUndefined(rawAttrItem) ? rawAttrItem : undefined) ?? 0;
180
253
 
181
- if (!attrName) {
254
+ if (attrName === undefined || attrName === "") {
182
255
  continue;
183
256
  }
184
257
 
185
258
  const schemaName = `${activeColoring}_attribute_names`;
186
259
  const backSchemas = back_schemas.opengeodeweb_back as Record<string, unknown>;
187
260
  const schema = backSchemas[schemaName];
188
- if (!schema) {
261
+ if (schema === undefined || !isJsonRpcSchema(schema)) {
189
262
  continue;
190
263
  }
191
264
 
192
- backStore.request(
193
- {
194
- schema: schema as Parameters<typeof backStore.request>[0]["schema"],
195
- params: { id: targetId },
196
- },
197
- {
198
- response_function: (response: unknown) => {
199
- const attributes = (response as AttributeResponse).attributes || [];
200
- const currentAttribute = attributes.find((attr) => attr.attribute_name === attrName);
201
- if (currentAttribute) {
202
- const { min, max } = getAttributeRange(currentAttribute, attrItem);
203
-
204
- const setterName = `set${setterKey}${attributeType}Range`;
205
- const setter = dynamicDataStyleStore[setterName];
206
- if (setter) {
207
- setter(targetId, min, max);
208
- hybridViewerStore.remoteRender();
265
+ requestPromises.push(
266
+ backStore.request(
267
+ {
268
+ schema,
269
+ params: { id: targetId },
270
+ },
271
+ {
272
+ response_function: async (response: unknown): Promise<void> => {
273
+ if (!isAttributeResponse(response)) {
274
+ return;
275
+ }
276
+ const attributes = response.attributes ?? [];
277
+ const currentAttribute = attributes.find((attr) => attr.attribute_name === attrName);
278
+ if (currentAttribute) {
279
+ const { min, max } = getAttributeRange(currentAttribute, attrItem);
280
+
281
+ const setterName = `set${setterKey}${attributeType}Range`;
282
+ const setter = getDynamicStoreMethod(dataStyleStore, setterName);
283
+ if (setter) {
284
+ setter(targetId, min, max);
285
+ await hybridViewerStore.remoteRender();
286
+ }
209
287
  }
210
- }
288
+ },
211
289
  },
212
- },
290
+ ),
213
291
  );
214
292
  }
293
+
294
+ await Promise.all(requestPromises);
215
295
  }
216
296
 
217
297
  return {
@@ -1,3 +1,4 @@
1
+ import type { JsonRpcSchema } from "@ogw_shared/utils/types";
1
2
  import { useDataStore } from "@ogw_front/stores/data";
2
3
  import { useViewerStore } from "@ogw_front/stores/viewer";
3
4
  import vtk_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
@@ -5,9 +6,12 @@ import vtk_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.
5
6
  const HOVER_DELAY = 200;
6
7
 
7
8
  type HighlightType = "mesh" | "model";
8
- type BlockIdsProvider = number[] | (() => number[] | Promise<number[]>);
9
+ type BlockIdsProvider = readonly number[] | (() => readonly number[] | Promise<readonly number[]>);
9
10
 
10
- export function useHoverhighlight() {
11
+ export function useHoverhighlight(): {
12
+ onHoverEnter: typeof onHoverEnter;
13
+ onHoverLeave: typeof onHoverLeave;
14
+ } {
11
15
  const viewerStore = useViewerStore();
12
16
  const dataStore = useDataStore();
13
17
  let timer: ReturnType<typeof setTimeout> | undefined = undefined;
@@ -26,7 +30,7 @@ export function useHoverhighlight() {
26
30
  }
27
31
  const schema = vtk_schemas.opengeodeweb_viewer[type].highlight;
28
32
 
29
- async function highlightAction() {
33
+ async function highlightAction(): Promise<void> {
30
34
  currentId = id;
31
35
  currentType = type;
32
36
 
@@ -34,11 +38,14 @@ export function useHoverhighlight() {
34
38
  return;
35
39
  }
36
40
 
37
- let block_ids: number[] =
38
- typeof block_ids_provider === "function" ? await block_ids_provider() : block_ids_provider;
41
+ let block_ids: number[] = [
42
+ ...(typeof block_ids_provider === "function"
43
+ ? await block_ids_provider()
44
+ : block_ids_provider),
45
+ ];
39
46
 
40
47
  block_ids = (Array.isArray(block_ids) ? block_ids : [])
41
- .map((blockId) => Math.trunc(Number(blockId)))
48
+ .map((blockId) => Math.trunc(blockId))
42
49
  .filter((blockId) => !Number.isNaN(blockId));
43
50
 
44
51
  if (currentId !== id) {
@@ -57,10 +64,38 @@ export function useHoverhighlight() {
57
64
  }
58
65
  }
59
66
 
67
+ async function runHighlightAction(): Promise<void> {
68
+ try {
69
+ await highlightAction();
70
+ } catch {
71
+ // Ignore
72
+ }
73
+ }
74
+
60
75
  if (immediate) {
61
- highlightAction();
76
+ // oxlint-disable-next-line typescript/no-floating-promises -- runHighlightAction catches its own errors internally.
77
+ runHighlightAction();
62
78
  } else {
63
- timer = setTimeout(highlightAction, HOVER_DELAY);
79
+ timer = setTimeout(() => {
80
+ // oxlint-disable-next-line typescript/no-floating-promises -- runHighlightAction catches its own errors internally.
81
+ runHighlightAction();
82
+ }, HOVER_DELAY);
83
+ }
84
+ }
85
+
86
+ async function unhighlightAction(
87
+ type: HighlightType,
88
+ id: string,
89
+ request: {
90
+ schema: JsonRpcSchema;
91
+ params?: Record<string, unknown>;
92
+ timeout?: number;
93
+ },
94
+ ): Promise<void> {
95
+ try {
96
+ await viewerStore.request(request);
97
+ } catch (error) {
98
+ console.error(`Unhighlight failed for ${type} ${id}:`, error);
64
99
  }
65
100
  }
66
101
 
@@ -76,16 +111,13 @@ export function useHoverhighlight() {
76
111
  visibility: false,
77
112
  ...(currentType === "model" && { block_ids: [] }),
78
113
  };
79
- try {
80
- viewerStore.request({ schema, params });
81
- } catch (error) {
82
- console.error(`Unhighlight failed for ${currentType} ${id}:`, error);
83
- }
114
+ // oxlint-disable-next-line typescript/no-floating-promises -- unhighlightAction catches its own errors internally.
115
+ unhighlightAction(currentType, id, { schema, params });
84
116
  currentId = undefined;
85
117
  currentType = undefined;
86
118
  }
87
119
 
88
- if (!currentId) {
120
+ if (currentId === undefined) {
89
121
  currentId = undefined;
90
122
  currentType = undefined;
91
123
  }
@@ -1,15 +1,26 @@
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 { compareSelections } from "@ogw_front/utils/treeview";
4
- import { useDataStore } from "@ogw_front/stores/data";
5
- import { useDataStyleStore } from "@ogw_front/stores/data_style";
6
- import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
7
1
  import type {
8
2
  CollectionComponent,
9
3
  CollectionComponentGroup,
10
4
  } from "@ogw_front/stores/data_helpers/collections";
5
+ import { compareSelections } from "@ogw_front/utils/treeview";
6
+ import { useDataStore } from "@ogw_front/stores/data";
7
+ import { useDataStyleStore } from "@ogw_front/stores/data_style";
8
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
9
+
10
+ // The `watch` callback receives the freshly-fetched collection groups purely for reading (matching against and copying into `localCategories`, never mutated in place), so it's typed with its own fully-readonly mirror of `CollectionComponentGroup` rather than that (intentionally mutable, see `existing.title` below) store type directly.
11
+ interface ReadonlyCollectionComponentGroup {
12
+ readonly id: string;
13
+ readonly title: string;
14
+ readonly children: readonly CollectionComponent[];
15
+ }
11
16
 
12
- export function useModelCollections(viewId: string) {
17
+ export function useModelCollections(viewId: string): {
18
+ items: typeof items;
19
+ collectionsCache: typeof collectionsCache;
20
+ localCategories: typeof localCategories;
21
+ selection: typeof selection;
22
+ updateVisibility: typeof updateVisibility;
23
+ } {
13
24
  const dataStore = useDataStore();
14
25
  const dataStyleStore = useDataStyleStore();
15
26
  const hybridViewerStore = useHybridViewerStore();
@@ -25,7 +36,7 @@ export function useModelCollections(viewId: string) {
25
36
 
26
37
  watch(
27
38
  items,
28
- async (newItems) => {
39
+ async (newItems: readonly ReadonlyCollectionComponentGroup[] | undefined) => {
29
40
  if (!newItems) {
30
41
  localCategories.value = [];
31
42
  return;
@@ -34,8 +45,10 @@ export function useModelCollections(viewId: string) {
34
45
  const data = await dataStore.fetchAllCollectionComponents(viewId);
35
46
  collectionsCache.value = markRaw(data);
36
47
 
37
- localCategories.value = newItems.map((newCategory) => {
38
- const existing = localCategories.value.find((category) => category.id === newCategory.id);
48
+ localCategories.value = newItems.map((newCategory: ReadonlyCollectionComponentGroup) => {
49
+ const existing = localCategories.value.find(
50
+ (category: ReadonlyCollectionComponentGroup) => category.id === newCategory.id,
51
+ );
39
52
  if (existing) {
40
53
  existing.title = newCategory.title || newCategory.id;
41
54
  return existing;
@@ -51,9 +64,9 @@ export function useModelCollections(viewId: string) {
51
64
 
52
65
  const selection = dataStyleStore.visibleMeshComponents(viewId);
53
66
 
54
- async function updateVisibility(current: string[]) {
67
+ async function updateVisibility(current: readonly string[]): Promise<void> {
55
68
  const previous = selection.value;
56
- const { added, removed } = compareSelections(current, previous);
69
+ const { added, removed } = compareSelections([...current], previous);
57
70
 
58
71
  if (added.length === 0 && removed.length === 0) {
59
72
  return;
@@ -65,7 +78,7 @@ export function useModelCollections(viewId: string) {
65
78
  if (removed.length > 0) {
66
79
  await dataStyleStore.setModelComponentsVisibility(viewId, removed, false);
67
80
  }
68
- hybridViewerStore.remoteRender();
81
+ await hybridViewerStore.remoteRender();
69
82
  }
70
83
 
71
84
  return {
@@ -1,15 +1,26 @@
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 { compareSelections } from "@ogw_front/utils/treeview";
4
- import { useDataStore } from "@ogw_front/stores/data";
5
- import { useDataStyleStore } from "@ogw_front/stores/data_style";
6
- import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
7
1
  import type {
8
2
  FormattedComponent,
9
3
  FormattedComponentGroup,
10
4
  } from "@ogw_front/stores/data_helpers/mesh";
5
+ import { compareSelections } from "@ogw_front/utils/treeview";
6
+ import { useDataStore } from "@ogw_front/stores/data";
7
+ import { useDataStyleStore } from "@ogw_front/stores/data_style";
8
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
9
+
10
+ // The `watch` callback receives the freshly-fetched component groups purely for reading (matching against and copying into `localCategories`, never mutated in place), so it's typed with its own fully-readonly mirror of `FormattedComponentGroup` rather than that (intentionally mutable, see `existing.title` below) store type directly.
11
+ interface ReadonlyFormattedComponentGroup {
12
+ readonly id: string;
13
+ readonly title: string;
14
+ readonly children: readonly FormattedComponent[];
15
+ }
11
16
 
12
- export function useModelComponents(viewId: string) {
17
+ export function useModelComponents(viewId: string): {
18
+ items: typeof items;
19
+ componentsCache: typeof componentsCache;
20
+ localCategories: typeof localCategories;
21
+ selection: typeof selection;
22
+ updateVisibility: typeof updateVisibility;
23
+ } {
13
24
  const dataStore = useDataStore();
14
25
  const dataStyleStore = useDataStyleStore();
15
26
  const hybridViewerStore = useHybridViewerStore();
@@ -25,7 +36,7 @@ export function useModelComponents(viewId: string) {
25
36
 
26
37
  watch(
27
38
  items,
28
- async (newItems) => {
39
+ async (newItems: readonly ReadonlyFormattedComponentGroup[] | undefined) => {
29
40
  if (!newItems) {
30
41
  localCategories.value = [];
31
42
  return;
@@ -34,8 +45,10 @@ export function useModelComponents(viewId: string) {
34
45
  const data = await dataStore.fetchAllMeshComponents(viewId);
35
46
  componentsCache.value = markRaw(data);
36
47
 
37
- localCategories.value = newItems.map((newCategory) => {
38
- const existing = localCategories.value.find((category) => category.id === newCategory.id);
48
+ localCategories.value = newItems.map((newCategory: ReadonlyFormattedComponentGroup) => {
49
+ const existing = localCategories.value.find(
50
+ (category: ReadonlyFormattedComponentGroup) => category.id === newCategory.id,
51
+ );
39
52
  if (existing) {
40
53
  existing.title = newCategory.title || newCategory.id;
41
54
  return existing;
@@ -51,9 +64,9 @@ export function useModelComponents(viewId: string) {
51
64
 
52
65
  const selection = dataStyleStore.visibleMeshComponents(viewId);
53
66
 
54
- async function updateVisibility(current: string[]) {
67
+ async function updateVisibility(current: readonly string[]): Promise<void> {
55
68
  const previous = selection.value;
56
- const { added, removed } = compareSelections(current, previous);
69
+ const { added, removed } = compareSelections([...current], previous);
57
70
 
58
71
  if (added.length === 0 && removed.length === 0) {
59
72
  return;
@@ -65,7 +78,7 @@ export function useModelComponents(viewId: string) {
65
78
  if (removed.length > 0) {
66
79
  await dataStyleStore.setModelComponentsVisibility(viewId, removed, false);
67
80
  }
68
- hybridViewerStore.remoteRender();
81
+ await hybridViewerStore.remoteRender();
69
82
  }
70
83
 
71
84
  return {