@geode/opengeodeweb-front 10.34.0-rc.15 → 10.34.0-rc.17
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.
- package/app/components/Viewer/ObjectTree/Layout.vue +5 -8
- package/app/components/Viewer/ObjectTree/Views/{ModelCollections.vue → ModelTree.vue} +28 -12
- package/internal/stores/data_style/model/blocks/color.ts +4 -1
- package/internal/stores/data_style/model/blocks/polyhedron.ts +2 -1
- package/internal/stores/data_style/model/blocks/vertex.ts +2 -1
- package/internal/stores/data_style/model/corners/color.ts +4 -1
- package/internal/stores/data_style/model/corners/vertex.ts +2 -1
- package/internal/stores/data_style/model/lines/color.ts +4 -1
- package/internal/stores/data_style/model/lines/edge.ts +2 -1
- package/internal/stores/data_style/model/lines/vertex.ts +2 -1
- package/internal/stores/data_style/model/surfaces/color.ts +4 -1
- package/internal/stores/data_style/model/surfaces/polygon.ts +2 -1
- package/internal/stores/data_style/model/surfaces/vertex.ts +2 -1
- package/package.json +1 -1
- package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +0 -277
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import GlobalObjects from "@ogw_front/components/Viewer/ObjectTree/Views/GlobalObjects.vue";
|
|
3
|
-
import
|
|
4
|
-
import ModelComponents from "@ogw_front/components/Viewer/ObjectTree/Views/ModelComponents.vue";
|
|
3
|
+
import ModelTree from "@ogw_front/components/Viewer/ObjectTree/Views/ModelTree.vue";
|
|
5
4
|
import ViewerObjectTreeBox from "@ogw_front/components/Viewer/ObjectTree/Box.vue";
|
|
6
5
|
import { geode_objects } from "@ogw_front/assets/geode_objects";
|
|
7
6
|
import { useAdaptiveStyles } from "@ogw_front/composables/use_adaptive_styles";
|
|
@@ -35,10 +34,8 @@ const { adaptiveStyles: activityBarAdaptiveStyles } = useAdaptiveStyles(activity
|
|
|
35
34
|
|
|
36
35
|
const maxWidth = computed<number>(() => containerWidth * MAX_PANEL_WIDTH_RATIO);
|
|
37
36
|
|
|
38
|
-
const mainView = computed
|
|
39
|
-
|
|
40
|
-
);
|
|
41
|
-
const additionalViews = computed<TreeViewItem[]>(() =>
|
|
37
|
+
const mainView = computed(() => treeviewStore.opened_views.find((view) => view.id === "main"));
|
|
38
|
+
const additionalViews = computed(() =>
|
|
42
39
|
treeviewStore.opened_views.filter((view) => view.id !== "main"),
|
|
43
40
|
);
|
|
44
41
|
|
|
@@ -284,11 +281,11 @@ function onVerticalResizeStart(event: MouseEvent, index: number): void {
|
|
|
284
281
|
@dragstart="onDragStart(index + 1)"
|
|
285
282
|
@update:scroll-top="treeviewStore.setScrollTop(view.id, $event)"
|
|
286
283
|
>
|
|
287
|
-
<
|
|
288
|
-
:is="view.viewType === 'model_collections' ? ModelCollections : ModelComponents"
|
|
284
|
+
<ModelTree
|
|
289
285
|
data-testid="modelComponentsObjectTree"
|
|
290
286
|
:id="view.modelId || view.id"
|
|
291
287
|
:view-id="view.id"
|
|
288
|
+
:view-type="view.viewType"
|
|
292
289
|
@show-menu="emit('show-menu', $event)"
|
|
293
290
|
/>
|
|
294
291
|
</ViewerObjectTreeBox>
|
|
@@ -8,14 +8,16 @@ import ObjectTreeItemLabel from "@ogw_front/components/Viewer/ObjectTree/Base/It
|
|
|
8
8
|
import { useHoverhighlight } from "@ogw_front/composables/hover_highlight";
|
|
9
9
|
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
10
10
|
import { useModelCollections } from "@ogw_front/composables/model_collections";
|
|
11
|
+
import { useModelComponents } from "@ogw_front/composables/model_components";
|
|
11
12
|
import { useTreeviewStore } from "@ogw_front/stores/treeview";
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
id: string;
|
|
15
16
|
viewId?: string;
|
|
17
|
+
viewType?: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
const { id, viewId = undefined } = defineProps<Props>();
|
|
20
|
+
const { id, viewId = undefined, viewType = "model_components" } = defineProps<Props>();
|
|
19
21
|
const actualViewId = viewId || id;
|
|
20
22
|
|
|
21
23
|
interface CollectionTreeItem {
|
|
@@ -29,7 +31,6 @@ interface CollectionTreeItem {
|
|
|
29
31
|
|
|
30
32
|
const { onHoverEnter, onHoverLeave } = useHoverhighlight();
|
|
31
33
|
const hybridViewerStore = useHybridViewerStore();
|
|
32
|
-
|
|
33
34
|
interface Emits {
|
|
34
35
|
"show-menu": [
|
|
35
36
|
payload: {
|
|
@@ -37,7 +38,8 @@ interface Emits {
|
|
|
37
38
|
itemId: string;
|
|
38
39
|
context_type: "model_component" | "model_component_type";
|
|
39
40
|
modelId: string;
|
|
40
|
-
modelComponentType
|
|
41
|
+
modelComponentType?: string;
|
|
42
|
+
targetComponentIds?: string[];
|
|
41
43
|
},
|
|
42
44
|
];
|
|
43
45
|
}
|
|
@@ -45,15 +47,24 @@ interface Emits {
|
|
|
45
47
|
const emit = defineEmits<Emits>();
|
|
46
48
|
|
|
47
49
|
const treeviewStore = useTreeviewStore();
|
|
50
|
+
|
|
51
|
+
const isCollections = computed(() => viewType === "model_collections");
|
|
52
|
+
|
|
53
|
+
const composable = isCollections.value ? useModelCollections(id) : useModelComponents(id);
|
|
48
54
|
const {
|
|
49
55
|
items: rawItems,
|
|
50
|
-
collectionsCache: componentsCache,
|
|
51
56
|
localCategories,
|
|
52
57
|
selection: visibleComponents,
|
|
53
58
|
updateVisibility,
|
|
54
|
-
} =
|
|
59
|
+
} = composable;
|
|
55
60
|
|
|
56
|
-
const
|
|
61
|
+
const cache = computed(
|
|
62
|
+
() =>
|
|
63
|
+
("componentsCache" in composable ? composable.componentsCache.value : undefined) ??
|
|
64
|
+
("collectionsCache" in composable ? composable.collectionsCache.value : undefined),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const currentView = computed(() =>
|
|
57
68
|
treeviewStore.opened_views.find((view) => view.id === actualViewId),
|
|
58
69
|
);
|
|
59
70
|
|
|
@@ -78,14 +89,16 @@ function onUpdateSelection(newSelection: string[]): void {
|
|
|
78
89
|
updateVisibility(finalSelection as string[]);
|
|
79
90
|
}
|
|
80
91
|
|
|
81
|
-
const visibleSelection = computed<string[]>(
|
|
92
|
+
const visibleSelection = computed<string[]>(
|
|
93
|
+
() => applySearchFilter(visibleComponents.value, []) as string[],
|
|
94
|
+
);
|
|
82
95
|
|
|
83
96
|
const itemsForTreeView = computed<CollectionTreeItem[]>(() => {
|
|
84
|
-
if (search.value &&
|
|
97
|
+
if (search.value && cache.value) {
|
|
85
98
|
const query = search.value.toLowerCase();
|
|
86
99
|
const result: CollectionTreeItem[] = [];
|
|
87
|
-
for (const type of Object.keys(
|
|
88
|
-
const matches = (
|
|
100
|
+
for (const type of Object.keys(cache.value)) {
|
|
101
|
+
const matches = (cache.value[type] ?? []).filter(
|
|
89
102
|
(component: { title: string; id: string }) =>
|
|
90
103
|
component.title.toLowerCase().includes(query) ||
|
|
91
104
|
component.id.toLowerCase().includes(query),
|
|
@@ -108,7 +121,7 @@ const itemsForTreeView = computed<CollectionTreeItem[]>(() => {
|
|
|
108
121
|
...category,
|
|
109
122
|
id: categoryId,
|
|
110
123
|
children: sortAndFormatItems(
|
|
111
|
-
|
|
124
|
+
cache.value?.[categoryId],
|
|
112
125
|
sortType.value,
|
|
113
126
|
) as unknown as CollectionTreeItem[],
|
|
114
127
|
});
|
|
@@ -118,12 +131,16 @@ const itemsForTreeView = computed<CollectionTreeItem[]>(() => {
|
|
|
118
131
|
|
|
119
132
|
function showContextMenu(event: unknown, item: CollectionTreeItem): void {
|
|
120
133
|
const actualItem = item.raw || item;
|
|
134
|
+
const typeId = actualItem.category || actualItem.id;
|
|
135
|
+
const typeItem = itemsForTreeView.value.find((type) => type.id === typeId);
|
|
136
|
+
const targetComponentIds = typeItem?.children?.map((child) => child.id);
|
|
121
137
|
emit("show-menu", {
|
|
122
138
|
event,
|
|
123
139
|
itemId: actualItem.category ? actualItem.id : id,
|
|
124
140
|
context_type: actualItem.category ? "model_component" : "model_component_type",
|
|
125
141
|
modelId: id,
|
|
126
142
|
modelComponentType: actualItem.category ? undefined : actualItem.id,
|
|
143
|
+
targetComponentIds,
|
|
127
144
|
});
|
|
128
145
|
}
|
|
129
146
|
|
|
@@ -151,7 +168,6 @@ function handleHoverEnter({
|
|
|
151
168
|
}
|
|
152
169
|
|
|
153
170
|
const viewerIdsToHover = extractIds(actualItem);
|
|
154
|
-
|
|
155
171
|
onHoverEnter(id, () => viewerIdsToHover, "model", immediate);
|
|
156
172
|
}
|
|
157
173
|
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from "./polyhedron";
|
|
5
5
|
import { isModelBlocksVertexAttributeValid, useModelBlocksVertexAttribute } from "./vertex";
|
|
6
6
|
import type { StyleValues } from "@ogw_internal/stores/data_style/types.js";
|
|
7
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
7
8
|
import { useModelBlocksCommonStyle } from "./common";
|
|
8
9
|
import { useModelCommonStyle } from "@ogw_internal/stores/data_style/model/common";
|
|
9
10
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
@@ -26,6 +27,7 @@ export function useModelBlocksColor(): {
|
|
|
26
27
|
activeColoring: string,
|
|
27
28
|
) => Promise<void>;
|
|
28
29
|
} {
|
|
30
|
+
const dataStore = useDataStore();
|
|
29
31
|
const modelCommonStyle = useModelCommonStyle();
|
|
30
32
|
const modelBlocksCommonStyle = useModelBlocksCommonStyle();
|
|
31
33
|
const modelBlocksVertexAttribute = useModelBlocksVertexAttribute();
|
|
@@ -65,7 +67,8 @@ export function useModelBlocksColor(): {
|
|
|
65
67
|
blocks_ids: string[],
|
|
66
68
|
activeColoring: string,
|
|
67
69
|
): Promise<void> {
|
|
68
|
-
|
|
70
|
+
const totalBlockIds = await dataStore.getBlocksGeodeIds(modelId);
|
|
71
|
+
if (blocks_ids.length === totalBlockIds.length) {
|
|
69
72
|
await modelBlocksCommonStyle.mutateModelBlocksTypeColoring(modelId, {
|
|
70
73
|
active: activeColoring,
|
|
71
74
|
});
|
|
@@ -137,7 +137,8 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
137
137
|
polyhedron: values,
|
|
138
138
|
}),
|
|
139
139
|
];
|
|
140
|
-
|
|
140
|
+
const totalBlockIds = await dataStore.getBlocksGeodeIds(modelId);
|
|
141
|
+
if (blockIds.length === totalBlockIds.length) {
|
|
141
142
|
tasks.push(
|
|
142
143
|
modelBlocksCommonStyle.mutateModelBlocksTypeColoring(modelId, {
|
|
143
144
|
polyhedron: values,
|
|
@@ -136,7 +136,8 @@ function useModelBlocksVertexAttribute(): UseModelBlocksVertexAttributeReturn {
|
|
|
136
136
|
vertex: values,
|
|
137
137
|
}),
|
|
138
138
|
];
|
|
139
|
-
|
|
139
|
+
const totalBlockIds = await dataStore.getBlocksGeodeIds(modelId);
|
|
140
|
+
if (blockIds.length === totalBlockIds.length) {
|
|
140
141
|
tasks.push(
|
|
141
142
|
modelBlocksCommonStyle.mutateModelBlocksTypeColoring(modelId, {
|
|
142
143
|
vertex: values,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isModelCornersVertexAttributeValid, useModelCornersVertexAttribute } from "./vertex";
|
|
2
2
|
import type { StyleValues } from "@ogw_internal/stores/data_style/types.js";
|
|
3
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
3
4
|
import { useModelCommonStyle } from "@ogw_internal/stores/data_style/model/common";
|
|
4
5
|
import { useModelCornersCommonStyle } from "./common";
|
|
5
6
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
@@ -24,6 +25,7 @@ interface ModelCornersColorApi {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export function useModelCornersColor(): ModelCornersColorApi {
|
|
28
|
+
const dataStore = useDataStore();
|
|
27
29
|
const modelCommonStyle = useModelCommonStyle();
|
|
28
30
|
const modelCornersCommonStyle = useModelCornersCommonStyle();
|
|
29
31
|
const modelCornersVertexAttribute = useModelCornersVertexAttribute();
|
|
@@ -62,7 +64,8 @@ export function useModelCornersColor(): ModelCornersColorApi {
|
|
|
62
64
|
corners_ids: string[],
|
|
63
65
|
activeColoring: string,
|
|
64
66
|
): Promise<unknown> {
|
|
65
|
-
|
|
67
|
+
const totalCornerIds = await dataStore.getCornersGeodeIds(modelId);
|
|
68
|
+
if (corners_ids.length === totalCornerIds.length) {
|
|
66
69
|
await modelCornersCommonStyle.mutateModelCornersTypeColoring(modelId, {
|
|
67
70
|
active: activeColoring,
|
|
68
71
|
});
|
|
@@ -122,7 +122,8 @@ function useModelCornersVertexAttribute(): ModelCornersVertexAttributeApi {
|
|
|
122
122
|
vertex: values,
|
|
123
123
|
}),
|
|
124
124
|
];
|
|
125
|
-
|
|
125
|
+
const totalCornerIds = await dataStore.getCornersGeodeIds(modelId);
|
|
126
|
+
if (cornerIds.length === totalCornerIds.length) {
|
|
126
127
|
tasks.push(
|
|
127
128
|
modelCornersCommonStyle.mutateModelCornersTypeColoring(modelId, { vertex: values }),
|
|
128
129
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isModelLinesEdgeAttributeValid, useModelLinesEdgeAttribute } from "./edge";
|
|
2
2
|
import { isModelLinesVertexAttributeValid, useModelLinesVertexAttribute } from "./vertex";
|
|
3
3
|
import type { StyleValues } from "@ogw_internal/stores/data_style/types.js";
|
|
4
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
4
5
|
import { useModelCommonStyle } from "@ogw_internal/stores/data_style/model/common";
|
|
5
6
|
import { useModelLinesCommonStyle } from "./common";
|
|
6
7
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
@@ -23,6 +24,7 @@ export function useModelLinesColor(): {
|
|
|
23
24
|
activeColoring: string,
|
|
24
25
|
) => Promise<unknown>;
|
|
25
26
|
} {
|
|
27
|
+
const dataStore = useDataStore();
|
|
26
28
|
const modelCommonStyle = useModelCommonStyle();
|
|
27
29
|
const modelLinesCommonStyle = useModelLinesCommonStyle();
|
|
28
30
|
const modelLinesVertexAttribute = useModelLinesVertexAttribute();
|
|
@@ -62,7 +64,8 @@ export function useModelLinesColor(): {
|
|
|
62
64
|
lines_ids: string[],
|
|
63
65
|
activeColoring: string,
|
|
64
66
|
): Promise<unknown> {
|
|
65
|
-
|
|
67
|
+
const totalLineIds = await dataStore.getLinesGeodeIds(modelId);
|
|
68
|
+
if (lines_ids.length === totalLineIds.length) {
|
|
66
69
|
await modelLinesCommonStyle.mutateModelLinesTypeColoring(modelId, {
|
|
67
70
|
active: activeColoring,
|
|
68
71
|
});
|
|
@@ -136,7 +136,8 @@ function useModelLinesEdgeAttribute(): UseModelLinesEdgeAttributeReturn {
|
|
|
136
136
|
edge: values,
|
|
137
137
|
}),
|
|
138
138
|
];
|
|
139
|
-
|
|
139
|
+
const totalLineIds = await dataStore.getLinesGeodeIds(modelId);
|
|
140
|
+
if (lineIds.length === totalLineIds.length) {
|
|
140
141
|
tasks.push(
|
|
141
142
|
modelLinesCommonStyle.mutateModelLinesTypeColoring(modelId, {
|
|
142
143
|
edge: values,
|
|
@@ -136,7 +136,8 @@ function useModelLinesVertexAttribute(): UseModelLinesVertexAttributeReturn {
|
|
|
136
136
|
vertex: values,
|
|
137
137
|
}),
|
|
138
138
|
];
|
|
139
|
-
|
|
139
|
+
const totalLineIds = await dataStore.getLinesGeodeIds(modelId);
|
|
140
|
+
if (lineIds.length === totalLineIds.length) {
|
|
140
141
|
tasks.push(
|
|
141
142
|
modelLinesCommonStyle.mutateModelLinesTypeColoring(modelId, {
|
|
142
143
|
vertex: values,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isModelSurfacesPolygonAttributeValid, useModelSurfacesPolygonAttribute } from "./polygon";
|
|
2
2
|
import { isModelSurfacesVertexAttributeValid, useModelSurfacesVertexAttribute } from "./vertex";
|
|
3
3
|
import type { StyleValues } from "@ogw_internal/stores/data_style/types.js";
|
|
4
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
4
5
|
import { useModelCommonStyle } from "@ogw_internal/stores/data_style/model/common";
|
|
5
6
|
import { useModelSurfacesCommonStyle } from "./common";
|
|
6
7
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
@@ -23,6 +24,7 @@ export function useModelSurfacesColor(): {
|
|
|
23
24
|
activeColoring: string,
|
|
24
25
|
) => Promise<unknown>;
|
|
25
26
|
} {
|
|
27
|
+
const dataStore = useDataStore();
|
|
26
28
|
const modelCommonStyle = useModelCommonStyle();
|
|
27
29
|
const modelSurfacesCommonStyle = useModelSurfacesCommonStyle();
|
|
28
30
|
const modelSurfacesVertexAttribute = useModelSurfacesVertexAttribute();
|
|
@@ -62,7 +64,8 @@ export function useModelSurfacesColor(): {
|
|
|
62
64
|
surfaces_ids: string[],
|
|
63
65
|
activeColoring: string,
|
|
64
66
|
): Promise<unknown> {
|
|
65
|
-
|
|
67
|
+
const totalSurfaceIds = await dataStore.getSurfacesGeodeIds(modelId);
|
|
68
|
+
if (surfaces_ids.length === totalSurfaceIds.length) {
|
|
66
69
|
await modelSurfacesCommonStyle.mutateModelSurfacesTypeColoring(modelId, {
|
|
67
70
|
active: activeColoring,
|
|
68
71
|
});
|
|
@@ -143,7 +143,8 @@ function useModelSurfacesPolygonAttribute(): UseModelSurfacesPolygonAttributeRet
|
|
|
143
143
|
polygon: values,
|
|
144
144
|
}),
|
|
145
145
|
];
|
|
146
|
-
|
|
146
|
+
const totalSurfaceIds = await dataStore.getSurfacesGeodeIds(modelId);
|
|
147
|
+
if (surfaceIds.length === totalSurfaceIds.length) {
|
|
147
148
|
tasks.push(
|
|
148
149
|
modelSurfacesCommonStyle.mutateModelSurfacesTypeColoring(modelId, { polygon: values }),
|
|
149
150
|
);
|
|
@@ -140,7 +140,8 @@ function useModelSurfacesVertexAttribute(): UseModelSurfacesVertexAttributeRetur
|
|
|
140
140
|
vertex: values,
|
|
141
141
|
}),
|
|
142
142
|
];
|
|
143
|
-
|
|
143
|
+
const totalSurfaceIds = await dataStore.getSurfacesGeodeIds(modelId);
|
|
144
|
+
if (surfaceIds.length === totalSurfaceIds.length) {
|
|
144
145
|
tasks.push(
|
|
145
146
|
modelSurfacesCommonStyle.mutateModelSurfacesTypeColoring(modelId, { vertex: values }),
|
|
146
147
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geode/opengeodeweb-front",
|
|
3
|
-
"version": "10.34.0-rc.
|
|
3
|
+
"version": "10.34.0-rc.17",
|
|
4
4
|
"description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
|
|
5
5
|
"homepage": "https://github.com/Geode-solutions/OpenGeodeWeb-Front",
|
|
6
6
|
"bugs": {
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { sortAndFormatItems, useTreeFilter } from "@ogw_front/composables/tree_filter";
|
|
3
|
-
import CommonTreeView from "@ogw_front/components/Viewer/ObjectTree/Base/CommonTreeView.vue";
|
|
4
|
-
import type { DisplayItem } from "@ogw_front/composables/virtual_tree";
|
|
5
|
-
import FetchingData from "@ogw_front/components/FetchingData.vue";
|
|
6
|
-
import ObjectTreeControls from "@ogw_front/components/Viewer/ObjectTree/Base/Controls.vue";
|
|
7
|
-
import ObjectTreeItemLabel from "@ogw_front/components/Viewer/ObjectTree/Base/ItemLabel.vue";
|
|
8
|
-
import { useHoverhighlight } from "@ogw_front/composables/hover_highlight";
|
|
9
|
-
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
10
|
-
import { useModelComponents } from "@ogw_front/composables/model_components";
|
|
11
|
-
import { useTreeviewStore } from "@ogw_front/stores/treeview";
|
|
12
|
-
|
|
13
|
-
interface Props {
|
|
14
|
-
id: string;
|
|
15
|
-
viewId?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const { id, viewId = undefined } = defineProps<Props>();
|
|
19
|
-
const actualViewId = viewId || id;
|
|
20
|
-
|
|
21
|
-
interface TreeViewItem {
|
|
22
|
-
raw?: TreeViewItem;
|
|
23
|
-
id: string;
|
|
24
|
-
category?: string;
|
|
25
|
-
children?: TreeViewItem[];
|
|
26
|
-
viewer_id?: string;
|
|
27
|
-
title?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const { onHoverEnter, onHoverLeave } = useHoverhighlight();
|
|
31
|
-
const hybridViewerStore = useHybridViewerStore();
|
|
32
|
-
|
|
33
|
-
interface Emits {
|
|
34
|
-
"show-menu": [
|
|
35
|
-
payload: {
|
|
36
|
-
event: unknown;
|
|
37
|
-
itemId: string;
|
|
38
|
-
context_type: "model_component" | "model_component_type";
|
|
39
|
-
modelId: string;
|
|
40
|
-
modelComponentType?: string;
|
|
41
|
-
targetComponentIds?: string[];
|
|
42
|
-
},
|
|
43
|
-
];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const emit = defineEmits<Emits>();
|
|
47
|
-
|
|
48
|
-
const treeviewStore = useTreeviewStore();
|
|
49
|
-
const {
|
|
50
|
-
items: rawItems,
|
|
51
|
-
componentsCache,
|
|
52
|
-
localCategories,
|
|
53
|
-
selection: visibleComponents,
|
|
54
|
-
updateVisibility,
|
|
55
|
-
} = useModelComponents(id);
|
|
56
|
-
|
|
57
|
-
const currentView = computed<TreeViewItem | undefined>(() =>
|
|
58
|
-
treeviewStore.opened_views.find((view) => view.id === actualViewId),
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const opened = computed<string[]>({
|
|
62
|
-
get: () => currentView.value?.opened || [],
|
|
63
|
-
set: (val) => treeviewStore.setOpened(actualViewId, val),
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const {
|
|
67
|
-
search,
|
|
68
|
-
sortType,
|
|
69
|
-
filterOptions,
|
|
70
|
-
processedItems: filteredCategories,
|
|
71
|
-
availableFilterOptions,
|
|
72
|
-
toggleSort,
|
|
73
|
-
customFilter,
|
|
74
|
-
applySearchFilter,
|
|
75
|
-
} = useTreeFilter(localCategories);
|
|
76
|
-
|
|
77
|
-
function onUpdateSelection(newSelection: string[]): void {
|
|
78
|
-
const finalSelection = applySearchFilter(newSelection, visibleComponents.value);
|
|
79
|
-
updateVisibility(finalSelection as string[]);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const visibleSelection = computed<string[]>(() => applySearchFilter(visibleComponents.value, []));
|
|
83
|
-
|
|
84
|
-
const itemsForTreeView = computed<TreeViewItem[]>(() => {
|
|
85
|
-
if (search.value && componentsCache.value) {
|
|
86
|
-
const query = search.value.toLowerCase();
|
|
87
|
-
const result: TreeViewItem[] = [];
|
|
88
|
-
for (const type of Object.keys(componentsCache.value)) {
|
|
89
|
-
const matches = (componentsCache.value[type] ?? []).filter(
|
|
90
|
-
(component: { title: string; id: string }) =>
|
|
91
|
-
component.title.toLowerCase().includes(query) ||
|
|
92
|
-
component.id.toLowerCase().includes(query),
|
|
93
|
-
);
|
|
94
|
-
if (matches.length > 0) {
|
|
95
|
-
result.push({
|
|
96
|
-
id: type,
|
|
97
|
-
title: `${type}s (${matches.length})`,
|
|
98
|
-
children: sortAndFormatItems(matches, sortType.value) as unknown as TreeViewItem[],
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return result;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const result: TreeViewItem[] = [];
|
|
106
|
-
for (const category of filteredCategories.value) {
|
|
107
|
-
const categoryId = category.id as string;
|
|
108
|
-
result.push({
|
|
109
|
-
...category,
|
|
110
|
-
id: categoryId,
|
|
111
|
-
children: sortAndFormatItems(
|
|
112
|
-
componentsCache.value?.[categoryId],
|
|
113
|
-
sortType.value,
|
|
114
|
-
) as unknown as TreeViewItem[],
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
return result;
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
function showContextMenu(event: unknown, item: TreeViewItem): void {
|
|
121
|
-
const actualItem = item.raw || item;
|
|
122
|
-
const typeId = actualItem.category || actualItem.id;
|
|
123
|
-
const typeItem = itemsForTreeView.value.find((type) => type.id === typeId);
|
|
124
|
-
const targetComponentIds = typeItem
|
|
125
|
-
? (typeItem.children ?? []).map((child) => child.id)
|
|
126
|
-
: undefined;
|
|
127
|
-
emit("show-menu", {
|
|
128
|
-
event,
|
|
129
|
-
itemId: actualItem.category ? actualItem.id : id,
|
|
130
|
-
context_type: actualItem.category ? "model_component" : "model_component_type",
|
|
131
|
-
modelId: id,
|
|
132
|
-
modelComponentType: actualItem.category ? undefined : actualItem.id,
|
|
133
|
-
targetComponentIds,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function handleHoverEnter({
|
|
138
|
-
item,
|
|
139
|
-
immediate = false,
|
|
140
|
-
}: {
|
|
141
|
-
item: TreeViewItem;
|
|
142
|
-
immediate?: boolean;
|
|
143
|
-
}): void {
|
|
144
|
-
const actualItem = item.raw || item;
|
|
145
|
-
|
|
146
|
-
if (!actualItem.category && (!actualItem.children || actualItem.children.length === 0)) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
onHoverEnter(
|
|
151
|
-
id,
|
|
152
|
-
() =>
|
|
153
|
-
actualItem.category
|
|
154
|
-
? [Number(actualItem.viewer_id)]
|
|
155
|
-
: (actualItem.children ?? []).map((child) => Number(child.viewer_id)),
|
|
156
|
-
"model",
|
|
157
|
-
immediate,
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function handleHoverLeave(): void {
|
|
162
|
-
onHoverLeave(id);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// CommonTreeView's #title/#append slots hand back the generic tree item it renders internally (a TreeItem); this view's tree is always built from TreeViewItem nodes (see itemsForTreeView above), so it's safe to view the slot item through that lens here.
|
|
166
|
-
function asTreeViewItem(item: unknown): TreeViewItem {
|
|
167
|
-
return item as unknown as TreeViewItem;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// The focusCameraOnObject composable's block_ids parameter is declared as string[], but this view (like the sibling ModelCollections view) has always focused the camera using the raw viewer_id values collected here; that pre-dates this typing pass, so the ids are passed through as-is rather than changed here.
|
|
171
|
-
function getFocusBlockIds(item: TreeViewItem): string[] {
|
|
172
|
-
const ids = item.category
|
|
173
|
-
? [item.viewer_id]
|
|
174
|
-
: (item.children ?? []).map((child) => child.viewer_id);
|
|
175
|
-
return ids as unknown as string[];
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function expandAll(): void {
|
|
179
|
-
const allIds: string[] = [];
|
|
180
|
-
function traverse(itemsList: TreeViewItem[]): void {
|
|
181
|
-
for (const item of itemsList) {
|
|
182
|
-
if (item.children && item.children.length > 0) {
|
|
183
|
-
allIds.push(item.id);
|
|
184
|
-
traverse(item.children);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
traverse(itemsForTreeView.value);
|
|
189
|
-
opened.value = allIds;
|
|
190
|
-
}
|
|
191
|
-
</script>
|
|
192
|
-
|
|
193
|
-
<template>
|
|
194
|
-
<div class="tree-view-container">
|
|
195
|
-
<ObjectTreeControls
|
|
196
|
-
v-model:search="search"
|
|
197
|
-
:sort-type="sortType"
|
|
198
|
-
:filter-options="filterOptions"
|
|
199
|
-
:available-filter-options="availableFilterOptions"
|
|
200
|
-
:is-collapsed="opened.length === 0"
|
|
201
|
-
@toggle-sort="toggleSort"
|
|
202
|
-
@collapse-all="opened = []"
|
|
203
|
-
@expand-all="expandAll"
|
|
204
|
-
/>
|
|
205
|
-
|
|
206
|
-
<FetchingData v-if="rawItems === undefined" :size="48" :width="4" text="" />
|
|
207
|
-
|
|
208
|
-
<CommonTreeView
|
|
209
|
-
:selected="visibleSelection"
|
|
210
|
-
v-model:opened="opened"
|
|
211
|
-
v-model:active="treeviewStore.activeItems"
|
|
212
|
-
:items="itemsForTreeView"
|
|
213
|
-
:options="{
|
|
214
|
-
selection: { selectable: true, strategy: 'classic' },
|
|
215
|
-
search,
|
|
216
|
-
customFilter,
|
|
217
|
-
}"
|
|
218
|
-
:scroll-top="currentView?.scrollTop || 0"
|
|
219
|
-
class="transparent-treeview virtual-tree-height"
|
|
220
|
-
@update:selected="(val) => onUpdateSelection(val as string[])"
|
|
221
|
-
@click:item="onUpdateSelection([$event.id as string, ...visibleComponents])"
|
|
222
|
-
@update:scroll-top="treeviewStore.setScrollTop(actualViewId, $event)"
|
|
223
|
-
@hover:enter="({ item }) => handleHoverEnter({ item: item as unknown as TreeViewItem })"
|
|
224
|
-
@hover:leave="handleHoverLeave"
|
|
225
|
-
@contextmenu="showContextMenu($event.event, $event.item as unknown as TreeViewItem)"
|
|
226
|
-
>
|
|
227
|
-
<template #title="{ item, isLeaf }">
|
|
228
|
-
<ObjectTreeItemLabel
|
|
229
|
-
:item="item as unknown as DisplayItem"
|
|
230
|
-
:is-leaf="isLeaf"
|
|
231
|
-
show-tooltip
|
|
232
|
-
class="text-body-1"
|
|
233
|
-
@contextmenu="showContextMenu($event, item as unknown as TreeViewItem)"
|
|
234
|
-
/>
|
|
235
|
-
</template>
|
|
236
|
-
|
|
237
|
-
<template #append="{ item: rawItem }">
|
|
238
|
-
<v-btn
|
|
239
|
-
v-if="
|
|
240
|
-
asTreeViewItem(rawItem).category ||
|
|
241
|
-
(asTreeViewItem(rawItem).children && asTreeViewItem(rawItem).children!.length > 0)
|
|
242
|
-
"
|
|
243
|
-
icon="mdi-target"
|
|
244
|
-
size="medium"
|
|
245
|
-
variant="text"
|
|
246
|
-
v-tooltip="'Focus camera on object'"
|
|
247
|
-
@click.stop="
|
|
248
|
-
hybridViewerStore.focusCameraOnObject(id, getFocusBlockIds(asTreeViewItem(rawItem)))
|
|
249
|
-
"
|
|
250
|
-
/>
|
|
251
|
-
</template>
|
|
252
|
-
</CommonTreeView>
|
|
253
|
-
</div>
|
|
254
|
-
</template>
|
|
255
|
-
|
|
256
|
-
<style scoped>
|
|
257
|
-
.tree-view-container {
|
|
258
|
-
height: 100%;
|
|
259
|
-
display: flex;
|
|
260
|
-
flex-direction: column;
|
|
261
|
-
overflow: hidden;
|
|
262
|
-
min-height: 0;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
.virtual-tree-height {
|
|
266
|
-
flex-grow: 1;
|
|
267
|
-
min-height: 0;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
.transparent-treeview {
|
|
271
|
-
background-color: transparent;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
:deep(.v-list-item__overlay) {
|
|
275
|
-
display: none !important;
|
|
276
|
-
}
|
|
277
|
-
</style>
|