@ifc-lite/viewer 1.1.6 → 1.5.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.
- package/LICENSE +373 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/assets/Arrow.dom-B0e15b_b.js +20 -0
- package/dist/assets/arrow2-bb-jcVEo.js +2 -0
- package/dist/assets/arrow2_bg-4Y7xYo54.wasm +0 -0
- package/dist/assets/arrow2_bg-BlXl-cSQ.js +1 -0
- package/dist/assets/arrow2_bg-BoXCojjR.wasm +0 -0
- package/dist/assets/desktop-cache-oPzaWXYE.js +1 -0
- package/dist/assets/event-DIOks52T.js +1 -0
- package/dist/assets/ifc-cache-BAN4vcd4.js +1 -0
- package/dist/assets/ifc-lite_bg-C6kblxf9.wasm +0 -0
- package/dist/assets/index-Dgd6vzw_.js +65252 -0
- package/dist/assets/index-v3mcCUPN.css +1 -0
- package/dist/assets/native-bridge-Ci7NLjlZ.js +111 -0
- package/dist/assets/wasm-bridge-Dc82YpdZ.js +1 -0
- package/dist/favicon-16x16-cropped.png +0 -0
- package/dist/favicon-16x16.png +0 -0
- package/dist/favicon-192x192-cropped.png +0 -0
- package/dist/favicon-192x192.png +0 -0
- package/dist/favicon-32x32-cropped.png +0 -0
- package/dist/favicon-32x32.png +0 -0
- package/dist/favicon-48x48-cropped.png +0 -0
- package/dist/favicon-48x48.png +0 -0
- package/dist/favicon-512x512-cropped.png +0 -0
- package/dist/favicon-512x512.png +0 -0
- package/dist/favicon-64x64-cropped.png +0 -0
- package/dist/favicon-64x64.png +0 -0
- package/dist/favicon-96x96-cropped.png +0 -0
- package/dist/favicon-96x96.png +0 -0
- package/dist/favicon-square-512.png +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +3 -0
- package/dist/index.html +44 -0
- package/dist/logo.png +0 -0
- package/dist/manifest.json +48 -0
- package/index.html +33 -2
- package/package.json +34 -17
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16-cropped.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-192x192-cropped.png +0 -0
- package/public/favicon-192x192.png +0 -0
- package/public/favicon-32x32-cropped.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon-48x48-cropped.png +0 -0
- package/public/favicon-48x48.png +0 -0
- package/public/favicon-512x512-cropped.png +0 -0
- package/public/favicon-512x512.png +0 -0
- package/public/favicon-64x64-cropped.png +0 -0
- package/public/favicon-64x64.png +0 -0
- package/public/favicon-96x96-cropped.png +0 -0
- package/public/favicon-96x96.png +0 -0
- package/public/favicon-square-512.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.png +0 -0
- package/public/favicon.svg +3 -0
- package/public/logo.png +0 -0
- package/public/manifest.json +48 -0
- package/src/App.tsx +2 -0
- package/src/components/ui/alert.tsx +62 -0
- package/src/components/ui/badge.tsx +39 -0
- package/src/components/ui/dialog.tsx +120 -0
- package/src/components/ui/label.tsx +27 -0
- package/src/components/ui/select.tsx +151 -0
- package/src/components/ui/switch.tsx +30 -0
- package/src/components/ui/table.tsx +120 -0
- package/src/components/ui/tabs.tsx +1 -1
- package/src/components/viewer/BCFPanel.tsx +1164 -0
- package/src/components/viewer/BulkPropertyEditor.tsx +875 -0
- package/src/components/viewer/DataConnector.tsx +840 -0
- package/src/components/viewer/DrawingSettingsPanel.tsx +536 -0
- package/src/components/viewer/EntityContextMenu.tsx +45 -17
- package/src/components/viewer/ExportChangesButton.tsx +195 -0
- package/src/components/viewer/ExportDialog.tsx +402 -0
- package/src/components/viewer/HierarchyPanel.tsx +1132 -218
- package/src/components/viewer/IDSPanel.tsx +661 -0
- package/src/components/viewer/KeyboardShortcutsDialog.tsx +245 -39
- package/src/components/viewer/MainToolbar.tsx +418 -94
- package/src/components/viewer/PropertiesPanel.tsx +1355 -91
- package/src/components/viewer/PropertyEditor.tsx +611 -0
- package/src/components/viewer/Section2DPanel.tsx +3313 -0
- package/src/components/viewer/SheetSetupPanel.tsx +502 -0
- package/src/components/viewer/StatusBar.tsx +27 -16
- package/src/components/viewer/TitleBlockEditor.tsx +437 -0
- package/src/components/viewer/ToolOverlays.tsx +935 -127
- package/src/components/viewer/ViewerLayout.tsx +40 -11
- package/src/components/viewer/Viewport.tsx +1276 -336
- package/src/components/viewer/ViewportContainer.tsx +554 -18
- package/src/components/viewer/ViewportOverlays.tsx +24 -7
- package/src/hooks/useBCF.ts +504 -0
- package/src/hooks/useIDS.ts +1065 -0
- package/src/hooks/useIfc.ts +1534 -205
- package/src/hooks/useIfcCache.ts +279 -0
- package/src/hooks/useKeyboardShortcuts.ts +50 -8
- package/src/hooks/useModelSelection.ts +61 -0
- package/src/hooks/useViewerSelectors.ts +218 -0
- package/src/hooks/useWebGPU.ts +80 -0
- package/src/index.css +265 -27
- package/src/lib/platform.ts +23 -0
- package/src/services/cacheService.ts +142 -0
- package/src/services/desktop-cache.ts +143 -0
- package/src/services/fs-cache.ts +212 -0
- package/src/services/ifc-cache.ts +14 -6
- package/src/store/constants.ts +85 -0
- package/src/store/index.ts +214 -0
- package/src/store/slices/bcfSlice.ts +372 -0
- package/src/store/slices/cameraSlice.ts +63 -0
- package/src/store/slices/dataSlice.test.ts +226 -0
- package/src/store/slices/dataSlice.ts +112 -0
- package/src/store/slices/drawing2DSlice.ts +340 -0
- package/src/store/slices/hoverSlice.ts +40 -0
- package/src/store/slices/idsSlice.ts +310 -0
- package/src/store/slices/loadingSlice.ts +33 -0
- package/src/store/slices/measurementSlice.test.ts +217 -0
- package/src/store/slices/measurementSlice.ts +293 -0
- package/src/store/slices/modelSlice.test.ts +271 -0
- package/src/store/slices/modelSlice.ts +211 -0
- package/src/store/slices/mutationSlice.ts +502 -0
- package/src/store/slices/sectionSlice.test.ts +125 -0
- package/src/store/slices/sectionSlice.ts +58 -0
- package/src/store/slices/selectionSlice.test.ts +286 -0
- package/src/store/slices/selectionSlice.ts +263 -0
- package/src/store/slices/sheetSlice.ts +565 -0
- package/src/store/slices/uiSlice.ts +58 -0
- package/src/store/slices/visibilitySlice.test.ts +304 -0
- package/src/store/slices/visibilitySlice.ts +277 -0
- package/src/store/types.test.ts +135 -0
- package/src/store/types.ts +248 -0
- package/src/store.ts +40 -515
- package/src/utils/ifcConfig.ts +82 -0
- package/src/utils/localParsingUtils.ts +287 -0
- package/src/utils/serverDataModel.ts +783 -0
- package/src/utils/spatialHierarchy.ts +283 -0
- package/src/utils/viewportUtils.ts +334 -0
- package/src/vite-env.d.ts +23 -0
- package/src/webgpu-types.d.ts +128 -0
- package/src-tauri/Cargo.toml +29 -0
- package/src-tauri/build.rs +7 -0
- package/src-tauri/capabilities/default.json +18 -0
- package/src-tauri/icons/128x128.png +0 -0
- package/src-tauri/icons/128x128@2x.png +0 -0
- package/src-tauri/icons/32x32.png +0 -0
- package/src-tauri/icons/Square107x107Logo.png +0 -0
- package/src-tauri/icons/Square142x142Logo.png +0 -0
- package/src-tauri/icons/Square150x150Logo.png +0 -0
- package/src-tauri/icons/Square284x284Logo.png +0 -0
- package/src-tauri/icons/Square30x30Logo.png +0 -0
- package/src-tauri/icons/Square310x310Logo.png +0 -0
- package/src-tauri/icons/Square44x44Logo.png +0 -0
- package/src-tauri/icons/Square71x71Logo.png +0 -0
- package/src-tauri/icons/Square89x89Logo.png +0 -0
- package/src-tauri/icons/StoreLogo.png +0 -0
- package/src-tauri/icons/icon.icns +0 -0
- package/src-tauri/icons/icon.ico +0 -0
- package/src-tauri/icons/icon.png +0 -0
- package/src-tauri/src/lib.rs +21 -0
- package/src-tauri/src/main.rs +10 -0
- package/src-tauri/tauri.conf.json +39 -0
- package/vite.config.ts +174 -26
- package/public/ifc-lite_bg.wasm +0 -0
- package/public/web-ifc.wasm +0 -0
- package/src/components/Viewport.tsx +0 -723
- package/src/components/viewer/BoxSelectionOverlay.tsx +0 -53
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Selection state slice
|
|
7
|
+
*
|
|
8
|
+
* Supports both single-model (legacy) and multi-model selection.
|
|
9
|
+
* Multi-model selection uses compound EntityRef identifiers.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { StateCreator } from 'zustand';
|
|
13
|
+
import type { EntityRef } from '../types.js';
|
|
14
|
+
import { entityRefToString, stringToEntityRef } from '../types.js';
|
|
15
|
+
|
|
16
|
+
export interface SelectionSlice {
|
|
17
|
+
// State (legacy - single model)
|
|
18
|
+
selectedEntityId: number | null;
|
|
19
|
+
selectedEntityIds: Set<number>;
|
|
20
|
+
selectedStoreys: Set<number>;
|
|
21
|
+
|
|
22
|
+
// State (multi-model)
|
|
23
|
+
/** Primary selected entity with model context */
|
|
24
|
+
selectedEntity: EntityRef | null;
|
|
25
|
+
/** Multi-selection across models: serialized EntityRef strings */
|
|
26
|
+
selectedEntitiesSet: Set<string>;
|
|
27
|
+
/** Array of selected entities for property panel display (e.g., unified storeys) */
|
|
28
|
+
selectedEntities: EntityRef[];
|
|
29
|
+
/** Selected model ID for metadata display (when clicking top-level model in hierarchy) */
|
|
30
|
+
selectedModelId: string | null;
|
|
31
|
+
|
|
32
|
+
// Actions (legacy - single model, maintained for backward compatibility)
|
|
33
|
+
setSelectedEntityId: (id: number | null) => void;
|
|
34
|
+
toggleStoreySelection: (id: number) => void;
|
|
35
|
+
setStoreySelection: (id: number) => void;
|
|
36
|
+
setStoreysSelection: (ids: number[]) => void;
|
|
37
|
+
clearStoreySelection: () => void;
|
|
38
|
+
addToSelection: (id: number) => void;
|
|
39
|
+
removeFromSelection: (id: number) => void;
|
|
40
|
+
toggleSelection: (id: number) => void;
|
|
41
|
+
setSelectedEntityIds: (ids: number[]) => void;
|
|
42
|
+
clearSelection: () => void;
|
|
43
|
+
|
|
44
|
+
// Actions (multi-model)
|
|
45
|
+
/** Set primary selection with model context */
|
|
46
|
+
setSelectedEntity: (ref: EntityRef | null) => void;
|
|
47
|
+
/** Add entity to multi-selection */
|
|
48
|
+
addEntityToSelection: (ref: EntityRef) => void;
|
|
49
|
+
/** Remove entity from multi-selection */
|
|
50
|
+
removeEntityFromSelection: (ref: EntityRef) => void;
|
|
51
|
+
/** Toggle entity in multi-selection */
|
|
52
|
+
toggleEntitySelection: (ref: EntityRef) => void;
|
|
53
|
+
/** Clear all entity selection (both single and multi) */
|
|
54
|
+
clearEntitySelection: () => void;
|
|
55
|
+
/** Check if entity is selected */
|
|
56
|
+
isEntitySelected: (ref: EntityRef) => boolean;
|
|
57
|
+
/** Get all selected entities for a specific model */
|
|
58
|
+
getSelectedEntitiesForModel: (modelId: string) => number[];
|
|
59
|
+
/** Set multiple entities for property panel display (e.g., unified storeys) */
|
|
60
|
+
setSelectedEntities: (refs: EntityRef[]) => void;
|
|
61
|
+
/** Set selected model for metadata display */
|
|
62
|
+
setSelectedModelId: (modelId: string | null) => void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const createSelectionSlice: StateCreator<SelectionSlice, [], [], SelectionSlice> = (set, get) => ({
|
|
66
|
+
// Initial state (legacy)
|
|
67
|
+
selectedEntityId: null,
|
|
68
|
+
selectedEntityIds: new Set(),
|
|
69
|
+
selectedStoreys: new Set(),
|
|
70
|
+
|
|
71
|
+
// Initial state (multi-model)
|
|
72
|
+
selectedEntity: null,
|
|
73
|
+
selectedEntitiesSet: new Set(),
|
|
74
|
+
selectedEntities: [],
|
|
75
|
+
selectedModelId: null,
|
|
76
|
+
|
|
77
|
+
// Actions (legacy - maintained for backward compatibility)
|
|
78
|
+
setSelectedEntityId: (selectedEntityId) => set((state) => ({
|
|
79
|
+
selectedEntityId,
|
|
80
|
+
// Clear model selection when an entity is selected (but not when clearing selection)
|
|
81
|
+
selectedModelId: selectedEntityId !== null ? null : state.selectedModelId,
|
|
82
|
+
})),
|
|
83
|
+
|
|
84
|
+
toggleStoreySelection: (id) => set((state) => {
|
|
85
|
+
const newSelection = new Set(state.selectedStoreys);
|
|
86
|
+
if (newSelection.has(id)) {
|
|
87
|
+
newSelection.delete(id);
|
|
88
|
+
} else {
|
|
89
|
+
newSelection.add(id);
|
|
90
|
+
}
|
|
91
|
+
return { selectedStoreys: newSelection };
|
|
92
|
+
}),
|
|
93
|
+
|
|
94
|
+
setStoreySelection: (id) => set((state) => {
|
|
95
|
+
// If already the only selected storey, deselect it (toggle behavior)
|
|
96
|
+
if (state.selectedStoreys.size === 1 && state.selectedStoreys.has(id)) {
|
|
97
|
+
return { selectedStoreys: new Set() };
|
|
98
|
+
}
|
|
99
|
+
// Otherwise, select only this storey
|
|
100
|
+
return { selectedStoreys: new Set([id]) };
|
|
101
|
+
}),
|
|
102
|
+
|
|
103
|
+
setStoreysSelection: (ids) => set({ selectedStoreys: new Set(ids) }),
|
|
104
|
+
|
|
105
|
+
clearStoreySelection: () => set({ selectedStoreys: new Set() }),
|
|
106
|
+
|
|
107
|
+
addToSelection: (id) => set((state) => {
|
|
108
|
+
const newSelection = new Set(state.selectedEntityIds);
|
|
109
|
+
newSelection.add(id);
|
|
110
|
+
return { selectedEntityIds: newSelection, selectedEntityId: id };
|
|
111
|
+
}),
|
|
112
|
+
|
|
113
|
+
removeFromSelection: (id) => set((state) => {
|
|
114
|
+
const newSelection = new Set(state.selectedEntityIds);
|
|
115
|
+
newSelection.delete(id);
|
|
116
|
+
const remaining = Array.from(newSelection);
|
|
117
|
+
return {
|
|
118
|
+
selectedEntityIds: newSelection,
|
|
119
|
+
selectedEntityId: remaining.length > 0 ? remaining[remaining.length - 1] : null,
|
|
120
|
+
};
|
|
121
|
+
}),
|
|
122
|
+
|
|
123
|
+
toggleSelection: (id) => set((state) => {
|
|
124
|
+
const newSelection = new Set(state.selectedEntityIds);
|
|
125
|
+
if (newSelection.has(id)) {
|
|
126
|
+
newSelection.delete(id);
|
|
127
|
+
} else {
|
|
128
|
+
newSelection.add(id);
|
|
129
|
+
}
|
|
130
|
+
const remaining = Array.from(newSelection);
|
|
131
|
+
return {
|
|
132
|
+
selectedEntityIds: newSelection,
|
|
133
|
+
selectedEntityId: remaining.length > 0 ? remaining[remaining.length - 1] : null,
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
136
|
+
|
|
137
|
+
setSelectedEntityIds: (ids) => set({
|
|
138
|
+
selectedEntityIds: new Set(ids),
|
|
139
|
+
selectedEntityId: ids.length > 0 ? ids[ids.length - 1] : null,
|
|
140
|
+
}),
|
|
141
|
+
|
|
142
|
+
clearSelection: () => set({
|
|
143
|
+
selectedEntityIds: new Set(),
|
|
144
|
+
selectedEntityId: null,
|
|
145
|
+
}),
|
|
146
|
+
|
|
147
|
+
// Actions (multi-model)
|
|
148
|
+
// NOTE: This ONLY sets selectedEntity, NOT selectedEntityId.
|
|
149
|
+
// In multi-model mode, selectedEntityId is the GLOBAL ID (for renderer highlighting)
|
|
150
|
+
// and selectedEntity.expressId is the ORIGINAL express ID (for property lookup).
|
|
151
|
+
// The caller should use setSelectedEntityId(globalId) separately for highlighting.
|
|
152
|
+
setSelectedEntity: (ref) => set({
|
|
153
|
+
selectedEntity: ref,
|
|
154
|
+
selectedEntities: [], // Clear multi-entity selection when setting single entity
|
|
155
|
+
// NOTE: Don't clear selectedModelId here - it's cleared by setSelectedEntityId
|
|
156
|
+
// when an entity is actually selected. This prevents race conditions with
|
|
157
|
+
// useModelSelection which calls setSelectedEntity when selectedEntityId changes.
|
|
158
|
+
// DO NOT update selectedEntityId here - it would overwrite the globalId with expressId!
|
|
159
|
+
// The renderer needs the globalId in selectedEntityId for highlighting.
|
|
160
|
+
}),
|
|
161
|
+
|
|
162
|
+
addEntityToSelection: (ref) => set((state) => {
|
|
163
|
+
const key = entityRefToString(ref);
|
|
164
|
+
const newSet = new Set(state.selectedEntitiesSet);
|
|
165
|
+
newSet.add(key);
|
|
166
|
+
return {
|
|
167
|
+
selectedEntitiesSet: newSet,
|
|
168
|
+
selectedEntity: ref,
|
|
169
|
+
// NOTE: Don't update selectedEntityId here - caller should use setSelectedEntityId(globalId)
|
|
170
|
+
};
|
|
171
|
+
}),
|
|
172
|
+
|
|
173
|
+
removeEntityFromSelection: (ref) => set((state) => {
|
|
174
|
+
const key = entityRefToString(ref);
|
|
175
|
+
const newSet = new Set(state.selectedEntitiesSet);
|
|
176
|
+
newSet.delete(key);
|
|
177
|
+
|
|
178
|
+
// Update primary selection if needed
|
|
179
|
+
let newPrimary: EntityRef | null = state.selectedEntity;
|
|
180
|
+
if (state.selectedEntity?.modelId === ref.modelId && state.selectedEntity?.expressId === ref.expressId) {
|
|
181
|
+
// Primary was removed, pick another if available
|
|
182
|
+
const remaining = Array.from(newSet);
|
|
183
|
+
newPrimary = remaining.length > 0 ? stringToEntityRef(remaining[remaining.length - 1]) : null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
selectedEntitiesSet: newSet,
|
|
188
|
+
selectedEntity: newPrimary,
|
|
189
|
+
// NOTE: Don't update selectedEntityId here - caller should manage it separately
|
|
190
|
+
// Clear it only if nothing is selected
|
|
191
|
+
selectedEntityId: newPrimary ? state.selectedEntityId : null,
|
|
192
|
+
};
|
|
193
|
+
}),
|
|
194
|
+
|
|
195
|
+
toggleEntitySelection: (ref) => set((state) => {
|
|
196
|
+
const key = entityRefToString(ref);
|
|
197
|
+
const newSet = new Set(state.selectedEntitiesSet);
|
|
198
|
+
|
|
199
|
+
if (newSet.has(key)) {
|
|
200
|
+
newSet.delete(key);
|
|
201
|
+
// Update primary if this was it
|
|
202
|
+
let newPrimary: EntityRef | null = state.selectedEntity;
|
|
203
|
+
if (state.selectedEntity?.modelId === ref.modelId && state.selectedEntity?.expressId === ref.expressId) {
|
|
204
|
+
const remaining = Array.from(newSet);
|
|
205
|
+
newPrimary = remaining.length > 0 ? stringToEntityRef(remaining[remaining.length - 1]) : null;
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
selectedEntitiesSet: newSet,
|
|
209
|
+
selectedEntity: newPrimary,
|
|
210
|
+
// NOTE: Don't update selectedEntityId here - caller should manage it separately
|
|
211
|
+
selectedEntityId: newPrimary ? state.selectedEntityId : null,
|
|
212
|
+
};
|
|
213
|
+
} else {
|
|
214
|
+
newSet.add(key);
|
|
215
|
+
return {
|
|
216
|
+
selectedEntitiesSet: newSet,
|
|
217
|
+
selectedEntity: ref,
|
|
218
|
+
// NOTE: Don't update selectedEntityId here - caller should use setSelectedEntityId(globalId)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}),
|
|
222
|
+
|
|
223
|
+
clearEntitySelection: () => set({
|
|
224
|
+
selectedEntity: null,
|
|
225
|
+
selectedEntitiesSet: new Set(),
|
|
226
|
+
selectedEntities: [],
|
|
227
|
+
selectedEntityId: null,
|
|
228
|
+
selectedEntityIds: new Set(),
|
|
229
|
+
selectedModelId: null,
|
|
230
|
+
}),
|
|
231
|
+
|
|
232
|
+
isEntitySelected: (ref) => {
|
|
233
|
+
const key = entityRefToString(ref);
|
|
234
|
+
return get().selectedEntitiesSet.has(key);
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
getSelectedEntitiesForModel: (modelId) => {
|
|
238
|
+
const state = get();
|
|
239
|
+
const result: number[] = [];
|
|
240
|
+
for (const key of state.selectedEntitiesSet) {
|
|
241
|
+
const ref = stringToEntityRef(key);
|
|
242
|
+
if (ref.modelId === modelId) {
|
|
243
|
+
result.push(ref.expressId);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return result;
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
setSelectedEntities: (refs) => set({
|
|
250
|
+
selectedEntities: refs,
|
|
251
|
+
// Also set the primary selected entity to the first one
|
|
252
|
+
selectedEntity: refs.length > 0 ? refs[0] : null,
|
|
253
|
+
selectedModelId: null, // Clear model selection when selecting entities
|
|
254
|
+
}),
|
|
255
|
+
|
|
256
|
+
setSelectedModelId: (modelId) => set({
|
|
257
|
+
selectedModelId: modelId,
|
|
258
|
+
// Clear other selection when selecting a model
|
|
259
|
+
selectedEntity: null,
|
|
260
|
+
selectedEntities: [],
|
|
261
|
+
selectedEntityId: null,
|
|
262
|
+
}),
|
|
263
|
+
});
|