@geode/opengeodeweb-front 10.20.1 → 10.21.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 (45) hide show
  1. package/app/components/CrsSelector.vue +3 -3
  2. package/app/components/ExtensionSelector.vue +3 -3
  3. package/app/components/FileSelector.vue +3 -3
  4. package/app/components/FileUploader.vue +4 -4
  5. package/app/components/Inspector/InspectionButton.vue +3 -3
  6. package/app/components/Loading.vue +27 -0
  7. package/app/components/MissingFilesSelector.vue +3 -3
  8. package/app/components/ObjectSelector.vue +3 -3
  9. package/app/components/PackagesVersions.vue +4 -4
  10. package/app/components/Viewer/ObjectTree/Layout.vue +6 -3
  11. package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +47 -1
  12. package/app/components/Viewer/ObjectTree/Views/ModelCollections.vue +222 -0
  13. package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +10 -4
  14. package/app/components/Viewer/Options/AttributeSelector.vue +3 -3
  15. package/app/components/Viewer/Options/TextureItem.vue +4 -4
  16. package/app/composables/model_collections.js +72 -0
  17. package/app/composables/model_components.js +5 -1
  18. package/app/composables/project_manager.js +5 -5
  19. package/app/composables/virtual_tree.js +8 -7
  20. package/app/stores/{geode.js → back.js} +16 -1
  21. package/app/stores/data.js +39 -111
  22. package/app/stores/data_helpers/collections.js +102 -0
  23. package/app/stores/data_helpers/mesh.js +122 -0
  24. package/app/stores/treeview.js +18 -8
  25. package/app/stores/viewer.js +18 -0
  26. package/app/utils/extension.js +0 -2
  27. package/app/utils/import_workflow.js +3 -3
  28. package/internal/stores/hybrid_viewer_camera_animation.js +24 -2
  29. package/package.json +3 -3
  30. package/tests/integration/setup.js +3 -3
  31. package/tests/unit/components/CrsSelector.nuxt.test.js +6 -6
  32. package/tests/unit/components/ExtensionSelector.nuxt.test.js +4 -4
  33. package/tests/unit/components/FileSelector.nuxt.test.js +3 -3
  34. package/tests/unit/components/FileUploader.nuxt.test.js +3 -3
  35. package/tests/unit/components/Inspector/InspectionButton.nuxt.test.js +4 -4
  36. package/tests/unit/components/MissingFilesSelector.nuxt.test.js +4 -4
  37. package/tests/unit/components/ObjectSelector.nuxt.test.js +3 -3
  38. package/tests/unit/components/PackagesVersions.nuxt.test.js +3 -3
  39. package/tests/unit/composables/api_fetch.nuxt.test.js +9 -9
  40. package/tests/unit/composables/project_manager.nuxt.test.js +3 -3
  41. package/tests/unit/composables/run_function_when_microservices_connected.nuxt.test.js +7 -7
  42. package/tests/unit/composables/upload_file.nuxt.test.js +7 -7
  43. package/tests/unit/stores/app.nuxt.test.js +9 -9
  44. package/tests/unit/stores/{geode.nuxt.test.js → back.nuxt.test.js} +43 -43
  45. package/tests/unit/stores/infra.nuxt.test.js +34 -34
@@ -0,0 +1,72 @@
1
+ import { compareSelections } from "@ogw_front/utils/treeview";
2
+ import { useDataStore } from "@ogw_front/stores/data";
3
+ import { useDataStyleStore } from "@ogw_front/stores/data_style";
4
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
5
+
6
+ export function useModelCollections(viewId) {
7
+ const dataStore = useDataStore();
8
+ const dataStyleStore = useDataStyleStore();
9
+ const hybridViewerStore = useHybridViewerStore();
10
+
11
+ const items = dataStore.refFormatedCollectionComponents(viewId);
12
+ const collectionsCache = ref(undefined);
13
+ const localCategories = ref([]);
14
+
15
+ onMounted(async () => {
16
+ const data = await dataStore.fetchAllCollectionComponents(viewId);
17
+ collectionsCache.value = markRaw(data);
18
+ });
19
+
20
+ watch(
21
+ items,
22
+ async (newItems) => {
23
+ if (!newItems) {
24
+ localCategories.value = [];
25
+ return;
26
+ }
27
+
28
+ const data = await dataStore.fetchAllCollectionComponents(viewId);
29
+ collectionsCache.value = markRaw(data);
30
+
31
+ localCategories.value = newItems.map((newCategory) => {
32
+ const existing = localCategories.value.find((category) => category.id === newCategory.id);
33
+ if (existing) {
34
+ existing.title = newCategory.title || newCategory.id;
35
+ return existing;
36
+ }
37
+ return reactive({
38
+ ...newCategory,
39
+ title: newCategory.title || newCategory.id,
40
+ });
41
+ });
42
+ },
43
+ { immediate: true },
44
+ );
45
+
46
+ const selection = dataStyleStore.visibleMeshComponents(viewId);
47
+
48
+ async function updateVisibility(current) {
49
+ const previous = selection.value;
50
+ const { added, removed } = compareSelections(current, previous);
51
+
52
+ if (added.length === 0 && removed.length === 0) {
53
+ return;
54
+ }
55
+
56
+ if (added.length > 0) {
57
+ await dataStyleStore.setModelComponentsVisibility(viewId, added, true);
58
+ }
59
+ if (removed.length > 0) {
60
+ await dataStyleStore.setModelComponentsVisibility(viewId, removed, false);
61
+ }
62
+ hybridViewerStore.remoteRender();
63
+ }
64
+
65
+ return {
66
+ items,
67
+ collectionsCache,
68
+ localCategories,
69
+ selection,
70
+ updateVisibility,
71
+ };
72
+ }
@@ -19,11 +19,15 @@ export function useModelComponents(viewId) {
19
19
 
20
20
  watch(
21
21
  items,
22
- (newItems) => {
22
+ async (newItems) => {
23
23
  if (!newItems) {
24
24
  localCategories.value = [];
25
25
  return;
26
26
  }
27
+
28
+ const data = await dataStore.fetchAllMeshComponents(viewId);
29
+ componentsCache.value = markRaw(data);
30
+
27
31
  localCategories.value = newItems.map((newCategory) => {
28
32
  const existing = localCategories.value.find((category) => category.id === newCategory.id);
29
33
  if (existing) {
@@ -5,9 +5,9 @@ import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schem
5
5
  import { importWorkflowFromSnapshot } from "@ogw_front/utils/import_workflow";
6
6
 
7
7
  import { useAppStore } from "@ogw_front/stores/app";
8
+ import { useBackStore } from "@ogw_front/stores/back";
8
9
  import { useDataStore } from "@ogw_front/stores/data";
9
10
  import { useDataStyleStore } from "@ogw_front/stores/data_style";
10
- import { useGeodeStore } from "@ogw_front/stores/geode";
11
11
  import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
12
12
  import { useTreeviewStore } from "@ogw_front/stores/treeview";
13
13
  import { useViewerStore } from "@ogw_front/stores/viewer";
@@ -15,13 +15,13 @@ import { useViewerStore } from "@ogw_front/stores/viewer";
15
15
  async function exportProject() {
16
16
  console.log("[export triggered]");
17
17
  const appStore = useAppStore();
18
- const geodeStore = useGeodeStore();
18
+ const backStore = useBackStore();
19
19
  const snapshot = await appStore.exportStores();
20
20
  const schema = back_schemas.opengeodeweb_back.export_project;
21
21
  const defaultName = "project.vease";
22
22
 
23
23
  const result = await $fetch(schema.$id, {
24
- baseURL: geodeStore.base_url,
24
+ baseURL: backStore.base_url,
25
25
  method: schema.methods.find((method) => method !== "OPTIONS"),
26
26
  body: { snapshot, filename: defaultName },
27
27
  });
@@ -30,7 +30,7 @@ async function exportProject() {
30
30
  }
31
31
 
32
32
  async function importProject(file) {
33
- const geodeStore = useGeodeStore();
33
+ const backStore = useBackStore();
34
34
  const dataStyleStore = useDataStyleStore();
35
35
  const viewerStore = useViewerStore();
36
36
  const dataStore = useDataStore();
@@ -63,7 +63,7 @@ async function importProject(file) {
63
63
  form.append("file", file, originalFileName);
64
64
 
65
65
  const result = await $fetch(schemaImport.$id, {
66
- baseURL: geodeStore.base_url,
66
+ baseURL: backStore.base_url,
67
67
  method: "POST",
68
68
  body: form,
69
69
  });
@@ -30,13 +30,14 @@ export function useVirtualTree(propsIn, emit) {
30
30
  emit("update:opened", [...newOpened]);
31
31
  }
32
32
 
33
- function getAllChildrenIds(item, ids = []) {
33
+ function getLeafChildrenIds(item, ids = []) {
34
34
  const children = item[actualItemProps.value.children];
35
- if (children) {
35
+ if (children && children.length > 0) {
36
36
  for (const child of children) {
37
- ids.push(child[actualItemProps.value.value]);
38
- getAllChildrenIds(child, ids);
37
+ getLeafChildrenIds(child, ids);
39
38
  }
39
+ } else {
40
+ ids.push(item[actualItemProps.value.value]);
40
41
  }
41
42
  return ids;
42
43
  }
@@ -47,7 +48,7 @@ export function useVirtualTree(propsIn, emit) {
47
48
  return true;
48
49
  }
49
50
  if (actualSelection.value.strategy === "classic") {
50
- const childrenIds = getAllChildrenIds(item);
51
+ const childrenIds = getLeafChildrenIds(item);
51
52
  return (
52
53
  childrenIds.length > 0 && childrenIds.every((childId) => selectedSet.value.has(childId))
53
54
  );
@@ -59,7 +60,7 @@ export function useVirtualTree(propsIn, emit) {
59
60
  if (actualSelection.value.strategy !== "classic") {
60
61
  return false;
61
62
  }
62
- const childrenIds = getAllChildrenIds(item);
63
+ const childrenIds = getLeafChildrenIds(item);
63
64
  if (childrenIds.length === 0) {
64
65
  return false;
65
66
  }
@@ -75,7 +76,7 @@ export function useVirtualTree(propsIn, emit) {
75
76
  const isCurrentlySelected = newSelected.has(id) || isSelected(item);
76
77
 
77
78
  if (actualSelection.value.strategy === "classic") {
78
- const childrenIds = getAllChildrenIds(item);
79
+ const childrenIds = getLeafChildrenIds(item);
79
80
  if (isCurrentlySelected) {
80
81
  newSelected.delete(id);
81
82
  for (const childId of childrenIds) {
@@ -10,11 +10,12 @@ import { useInfraStore } from "@ogw_front/stores/infra";
10
10
  const MILLISECONDS_IN_SECOND = 1000;
11
11
  const DEFAULT_PING_INTERVAL_SECONDS = 10;
12
12
 
13
- export const useGeodeStore = defineStore("geode", {
13
+ export const useBackStore = defineStore("back", {
14
14
  state: () => ({
15
15
  default_local_port: "5000",
16
16
  request_counter: 0,
17
17
  status: Status.NOT_CONNECTED,
18
+ version: "0.0.0",
18
19
  }),
19
20
  getters: {
20
21
  protocol() {
@@ -148,6 +149,20 @@ export const useGeodeStore = defineStore("geode", {
148
149
  },
149
150
  );
150
151
  },
152
+ get_version(schema) {
153
+ if (!schema) {
154
+ return;
155
+ }
156
+ return this.request(
157
+ schema,
158
+ {},
159
+ {
160
+ response_function: (response) => {
161
+ this.version = response.microservice_version;
162
+ },
163
+ },
164
+ );
165
+ },
151
166
  },
152
167
  share: {
153
168
  omit: ["status"],
@@ -5,6 +5,8 @@ import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schem
5
5
 
6
6
  // Local imports
7
7
  import { database } from "@ogw_internal/database/database.js";
8
+ import { useDataCollections } from "./data_helpers/collections.js";
9
+ import { useDataMesh } from "./data_helpers/mesh.js";
8
10
  import { useViewerStore } from "@ogw_front/stores/viewer";
9
11
 
10
12
  const viewer_generic_schemas = viewer_schemas.opengeodeweb_viewer.generic;
@@ -16,6 +18,27 @@ export const useDataStore = defineStore("data", () => {
16
18
  const model_components_db = database.model_components;
17
19
  const model_components_relation_db = database.model_components_relation;
18
20
 
21
+ const {
22
+ formatedMeshComponents,
23
+ refFormatedMeshComponents,
24
+ getMeshComponentsByType,
25
+ getAllMeshComponents,
26
+ fetchAllMeshComponents,
27
+ getMeshComponentGeodeIds,
28
+ getCornersGeodeIds,
29
+ getLinesGeodeIds,
30
+ getSurfacesGeodeIds,
31
+ getBlocksGeodeIds,
32
+ } = useDataMesh();
33
+
34
+ const {
35
+ hasCollectionComponents,
36
+ getAllCollectionComponents,
37
+ fetchAllCollectionComponents,
38
+ formatedCollectionComponents,
39
+ refFormatedCollectionComponents,
40
+ } = useDataCollections();
41
+
19
42
  async function item(id) {
20
43
  const data_item = await data_db.get(id);
21
44
  if (!data_item) {
@@ -42,84 +65,6 @@ export const useDataStore = defineStore("data", () => {
42
65
  );
43
66
  }
44
67
 
45
- async function formatedMeshComponents(modelId) {
46
- const items = await model_components_db.where("id").equals(modelId).toArray();
47
- const componentTitles = {
48
- Corner: "Corners",
49
- Line: "Lines",
50
- Surface: "Surfaces",
51
- Block: "Blocks",
52
- };
53
-
54
- const componentsByType = {};
55
- for (const component_item of items) {
56
- if (componentTitles[component_item.type]) {
57
- if (!componentsByType[component_item.type]) {
58
- componentsByType[component_item.type] = [];
59
- }
60
- componentsByType[component_item.type].push(component_item);
61
- }
62
- }
63
-
64
- return Object.keys(componentTitles)
65
- .filter((type) => componentsByType[type])
66
- .map((type) => ({
67
- id: type,
68
- title: componentTitles[type],
69
- children: componentsByType[type].map((meshComponent) => ({
70
- id: meshComponent.geode_id,
71
- title: meshComponent.name,
72
- category: meshComponent.type,
73
- viewer_id: Number(meshComponent.viewer_id),
74
- is_active: meshComponent.is_active,
75
- })),
76
- }));
77
- }
78
-
79
- async function getMeshComponentsByType(modelId, type) {
80
- const components = await model_components_db
81
- .where("[id+type]")
82
- .equals([modelId, type])
83
- .toArray();
84
- return components.map((meshComponent) => ({
85
- id: meshComponent.geode_id,
86
- title: meshComponent.name,
87
- category: meshComponent.type,
88
- viewer_id: Number(meshComponent.viewer_id),
89
- is_active: meshComponent.is_active,
90
- }));
91
- }
92
-
93
- async function getAllMeshComponents(modelId) {
94
- const items = await model_components_db.where("id").equals(modelId).toArray();
95
- return items.map((meshComponent) => ({
96
- id: meshComponent.geode_id,
97
- title: meshComponent.name,
98
- category: meshComponent.type,
99
- viewer_id: Number(meshComponent.viewer_id),
100
- is_active: meshComponent.is_active,
101
- }));
102
- }
103
-
104
- async function fetchAllMeshComponents(modelId) {
105
- const components = await getAllMeshComponents(modelId);
106
- const byType = {};
107
- for (const component of components) {
108
- if (!byType[component.category]) {
109
- byType[component.category] = [];
110
- }
111
- byType[component.category].push(component);
112
- }
113
- return byType;
114
- }
115
-
116
- function refFormatedMeshComponents(modelId) {
117
- return useObservable(
118
- liveQuery(() => formatedMeshComponents(modelId)),
119
- { initialValue: undefined },
120
- );
121
- }
122
-
123
68
  async function meshComponentType(modelId, geode_id) {
124
69
  const component = await model_components_db
125
70
  .where("[id+geode_id]")
@@ -227,30 +172,6 @@ export const useDataStore = defineStore("data", () => {
227
172
  await database.model_components_relation.where("id").equals(modelId).delete();
228
173
  }
229
174
 
230
- async function getMeshComponentGeodeIds(modelId, type) {
231
- const components = await model_components_db
232
- .where("[id+type]")
233
- .equals([modelId, type])
234
- .toArray();
235
- return components.map((component) => component.geode_id);
236
- }
237
-
238
- async function getCornersGeodeIds(modelId) {
239
- return await getMeshComponentGeodeIds(modelId, "Corner");
240
- }
241
-
242
- async function getLinesGeodeIds(modelId) {
243
- return await getMeshComponentGeodeIds(modelId, "Line");
244
- }
245
-
246
- async function getSurfacesGeodeIds(modelId) {
247
- return await getMeshComponentGeodeIds(modelId, "Surface");
248
- }
249
-
250
- async function getBlocksGeodeIds(modelId) {
251
- return await getMeshComponentGeodeIds(modelId, "Block");
252
- }
253
-
254
175
  async function getAllModelComponentsViewerIds(modelId) {
255
176
  const components = await model_components_db.where("id").equals(modelId).toArray();
256
177
  return components.map((component) => Number.parseInt(component.viewer_id, 10));
@@ -283,10 +204,6 @@ export const useDataStore = defineStore("data", () => {
283
204
  allItems,
284
205
  refItem,
285
206
  meshComponentType,
286
- formatedMeshComponents,
287
- refFormatedMeshComponents,
288
- getMeshComponentsByType,
289
- getAllMeshComponents,
290
207
  registerObject,
291
208
  deregisterObject,
292
209
  addItem,
@@ -294,18 +211,29 @@ export const useDataStore = defineStore("data", () => {
294
211
  addComponentRelations,
295
212
  deleteItem,
296
213
  updateItem,
297
- getCornersGeodeIds,
298
- getLinesGeodeIds,
299
- getSurfacesGeodeIds,
300
- getBlocksGeodeIds,
301
214
  getAllModelComponentsViewerIds,
302
- getMeshComponentGeodeIds,
303
215
  getMeshComponentsViewerIds,
304
216
  getComponentByViewerId,
305
217
 
306
218
  exportStores,
307
219
  importStores,
308
220
  clear,
221
+
222
+ formatedMeshComponents,
223
+ refFormatedMeshComponents,
224
+ getMeshComponentsByType,
225
+ getAllMeshComponents,
309
226
  fetchAllMeshComponents,
227
+ getMeshComponentGeodeIds,
228
+ getCornersGeodeIds,
229
+ getLinesGeodeIds,
230
+ getSurfacesGeodeIds,
231
+ getBlocksGeodeIds,
232
+
233
+ hasCollectionComponents,
234
+ getAllCollectionComponents,
235
+ fetchAllCollectionComponents,
236
+ formatedCollectionComponents,
237
+ refFormatedCollectionComponents,
310
238
  };
311
239
  });
@@ -0,0 +1,102 @@
1
+ import { database } from "@ogw_internal/database/database.js";
2
+ import { liveQuery } from "dexie";
3
+ import { useDataMesh } from "./mesh.js";
4
+ import { useObservable } from "@vueuse/rxjs";
5
+
6
+ export function useDataCollections() {
7
+ const model_components_db = database.model_components;
8
+ const model_components_relation_db = database.model_components_relation;
9
+ const { getAllMeshComponents } = useDataMesh();
10
+
11
+ async function hasCollectionComponents(modelId) {
12
+ const count = await model_components_db
13
+ .where("id")
14
+ .equals(modelId)
15
+ .and((component) =>
16
+ ["Horizon", "Fault", "FaultBlock", "StratigraphicUnit", "ModelBoundary"].includes(
17
+ component.type,
18
+ ),
19
+ )
20
+ .count();
21
+ return count > 0;
22
+ }
23
+
24
+ async function getAllCollectionComponents(modelId) {
25
+ const items = await model_components_db.where("id").equals(modelId).toArray();
26
+ return items
27
+ .filter((component) =>
28
+ ["Horizon", "Fault", "FaultBlock", "StratigraphicUnit", "ModelBoundary"].includes(
29
+ component.type,
30
+ ),
31
+ )
32
+ .map((component) => ({
33
+ id: component.geode_id,
34
+ title: component.name,
35
+ category: component.type,
36
+ viewer_id: Number(component.viewer_id),
37
+ is_active: component.is_active,
38
+ }));
39
+ }
40
+
41
+ async function fetchAllCollectionComponents(modelId) {
42
+ const components = await getAllCollectionComponents(modelId);
43
+ const relations = await model_components_relation_db.where("id").equals(modelId).toArray();
44
+ const allMeshComponents = await getAllMeshComponents(modelId);
45
+ const meshComponentsById = {};
46
+ for (const meshComponent of allMeshComponents) {
47
+ meshComponentsById[meshComponent.id] = meshComponent;
48
+ }
49
+
50
+ const byType = {};
51
+ for (const component of components) {
52
+ if (!byType[component.category]) {
53
+ byType[component.category] = [];
54
+ }
55
+ const itemRelations = relations.filter(
56
+ (relation) => relation.parent === component.id && relation.type === "collection",
57
+ );
58
+ const children = itemRelations
59
+ .map((relation) => meshComponentsById[relation.child])
60
+ .filter(Boolean);
61
+ byType[component.category].push({
62
+ ...component,
63
+ children,
64
+ });
65
+ }
66
+ return byType;
67
+ }
68
+
69
+ async function formatedCollectionComponents(modelId) {
70
+ const byType = await fetchAllCollectionComponents(modelId);
71
+ const collectionTitles = {
72
+ Horizon: "Horizons",
73
+ Fault: "Faults",
74
+ FaultBlock: "FaultBlocks",
75
+ StratigraphicUnit: "StratigraphicUnits",
76
+ ModelBoundary: "ModelBoundaries",
77
+ };
78
+
79
+ return Object.keys(collectionTitles)
80
+ .filter((type) => byType[type] && byType[type].length > 0)
81
+ .map((type) => ({
82
+ id: type,
83
+ title: collectionTitles[type],
84
+ children: byType[type],
85
+ }));
86
+ }
87
+
88
+ function refFormatedCollectionComponents(modelId) {
89
+ return useObservable(
90
+ liveQuery(() => formatedCollectionComponents(modelId)),
91
+ { initialValue: undefined },
92
+ );
93
+ }
94
+
95
+ return {
96
+ hasCollectionComponents,
97
+ getAllCollectionComponents,
98
+ fetchAllCollectionComponents,
99
+ formatedCollectionComponents,
100
+ refFormatedCollectionComponents,
101
+ };
102
+ }
@@ -0,0 +1,122 @@
1
+ import { database } from "@ogw_internal/database/database.js";
2
+ import { liveQuery } from "dexie";
3
+ import { useObservable } from "@vueuse/rxjs";
4
+
5
+ export function useDataMesh() {
6
+ const model_components_db = database.model_components;
7
+
8
+ async function formatedMeshComponents(modelId) {
9
+ const items = await model_components_db.where("id").equals(modelId).toArray();
10
+ const componentTitles = {
11
+ Corner: "Corners",
12
+ Line: "Lines",
13
+ Surface: "Surfaces",
14
+ Block: "Blocks",
15
+ };
16
+
17
+ const componentsByType = {};
18
+ for (const component_item of items) {
19
+ if (componentTitles[component_item.type]) {
20
+ if (!componentsByType[component_item.type]) {
21
+ componentsByType[component_item.type] = [];
22
+ }
23
+ componentsByType[component_item.type].push(component_item);
24
+ }
25
+ }
26
+
27
+ return Object.keys(componentTitles)
28
+ .filter((type) => componentsByType[type])
29
+ .map((type) => ({
30
+ id: type,
31
+ title: componentTitles[type],
32
+ children: componentsByType[type].map((meshComponent) => ({
33
+ id: meshComponent.geode_id,
34
+ title: meshComponent.name,
35
+ category: meshComponent.type,
36
+ viewer_id: Number(meshComponent.viewer_id),
37
+ is_active: meshComponent.is_active,
38
+ })),
39
+ }));
40
+ }
41
+
42
+ function refFormatedMeshComponents(modelId) {
43
+ return useObservable(
44
+ liveQuery(() => formatedMeshComponents(modelId)),
45
+ { initialValue: undefined },
46
+ );
47
+ }
48
+
49
+ async function getMeshComponentsByType(modelId, type) {
50
+ const components = await model_components_db
51
+ .where("[id+type]")
52
+ .equals([modelId, type])
53
+ .toArray();
54
+ return components.map((meshComponent) => ({
55
+ id: meshComponent.geode_id,
56
+ title: meshComponent.name,
57
+ category: meshComponent.type,
58
+ viewer_id: Number(meshComponent.viewer_id),
59
+ is_active: meshComponent.is_active,
60
+ }));
61
+ }
62
+
63
+ async function getAllMeshComponents(modelId) {
64
+ const items = await model_components_db.where("id").equals(modelId).toArray();
65
+ return items.map((meshComponent) => ({
66
+ id: meshComponent.geode_id,
67
+ title: meshComponent.name,
68
+ category: meshComponent.type,
69
+ viewer_id: Number(meshComponent.viewer_id),
70
+ is_active: meshComponent.is_active,
71
+ }));
72
+ }
73
+
74
+ async function fetchAllMeshComponents(modelId) {
75
+ const components = await getAllMeshComponents(modelId);
76
+ const byType = {};
77
+ for (const component of components) {
78
+ if (!byType[component.category]) {
79
+ byType[component.category] = [];
80
+ }
81
+ byType[component.category].push(component);
82
+ }
83
+ return byType;
84
+ }
85
+
86
+ async function getMeshComponentGeodeIds(modelId, type) {
87
+ const components = await model_components_db
88
+ .where("[id+type]")
89
+ .equals([modelId, type])
90
+ .toArray();
91
+ return components.map((component) => component.geode_id);
92
+ }
93
+
94
+ async function getCornersGeodeIds(modelId) {
95
+ return await getMeshComponentGeodeIds(modelId, "Corner");
96
+ }
97
+
98
+ async function getLinesGeodeIds(modelId) {
99
+ return await getMeshComponentGeodeIds(modelId, "Line");
100
+ }
101
+
102
+ async function getSurfacesGeodeIds(modelId) {
103
+ return await getMeshComponentGeodeIds(modelId, "Surface");
104
+ }
105
+
106
+ async function getBlocksGeodeIds(modelId) {
107
+ return await getMeshComponentGeodeIds(modelId, "Block");
108
+ }
109
+
110
+ return {
111
+ formatedMeshComponents,
112
+ refFormatedMeshComponents,
113
+ getMeshComponentsByType,
114
+ getAllMeshComponents,
115
+ fetchAllMeshComponents,
116
+ getMeshComponentGeodeIds,
117
+ getCornersGeodeIds,
118
+ getLinesGeodeIds,
119
+ getSurfacesGeodeIds,
120
+ getBlocksGeodeIds,
121
+ };
122
+ }
@@ -1,6 +1,6 @@
1
1
  import { defineStore } from "pinia";
2
2
 
3
- import { ref, toRaw, watch } from "vue";
3
+ import { ref, watch } from "vue";
4
4
  import { compareSelections } from "@ogw_front/utils/treeview";
5
5
  import { database } from "@ogw_internal/database/database";
6
6
 
@@ -45,13 +45,20 @@ export const useTreeviewStore = defineStore("treeview", () => {
45
45
  watch(
46
46
  [opened_views, panelWidth, additionalPanelWidth, selection, rowHeights],
47
47
  () => {
48
+ // oxlint-disable-next-line unicorn/prefer-structured-clone
49
+ const clean_opened_views = JSON.parse(JSON.stringify(opened_views.value));
50
+ // oxlint-disable-next-line unicorn/prefer-structured-clone
51
+ const clean_selectionIds = JSON.parse(JSON.stringify(selection.value));
52
+ // oxlint-disable-next-line unicorn/prefer-structured-clone
53
+ const clean_rowHeights = JSON.parse(JSON.stringify(rowHeights.value));
54
+
48
55
  database.treeview_config.put({
49
56
  id: "main",
50
- opened_views: toRaw(opened_views.value),
57
+ opened_views: clean_opened_views,
51
58
  panelWidth: panelWidth.value,
52
59
  additionalPanelWidth: additionalPanelWidth.value,
53
- selectionIds: toRaw(selection.value),
54
- rowHeights: toRaw(rowHeights.value),
60
+ selectionIds: clean_selectionIds,
61
+ rowHeights: clean_rowHeights,
55
62
  });
56
63
  },
57
64
  { deep: true },
@@ -127,15 +134,18 @@ export const useTreeviewStore = defineStore("treeview", () => {
127
134
  }
128
135
  }
129
136
 
130
- function displayAdditionalTree(id, title, geodeObjectType) {
131
- const index = opened_views.value.findIndex((view) => view.id === id);
137
+ function displayAdditionalTree(id, title, geodeObjectType, viewType = "model_components") {
138
+ const viewId = `${id}_${viewType}`;
139
+ const index = opened_views.value.findIndex((view) => view.id === viewId);
132
140
  if (index !== -1) {
133
- return closeView(id);
141
+ return closeView(viewId);
134
142
  }
135
143
  additionalPanelWidth.value = panelWidth.value;
136
144
  opened_views.value.push({
137
145
  type: "component",
138
- id,
146
+ id: viewId,
147
+ modelId: id,
148
+ viewType,
139
149
  title: title || id,
140
150
  geode_object_type: geodeObjectType,
141
151
  scrollTop: 0,