@collabdt/core 0.0.47 → 0.0.49
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/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +13 -2
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SettingsTab/src/GridManagement.js +2 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SettingsTab/src/GridManagement.js.map +1 -1
- package/dist/core/components/viewers/bim/src/IfcToFragments.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/IfcToFragments.js +1 -1
- package/dist/core/components/viewers/bim/src/IfcToFragments.js.map +1 -1
- package/dist/core/components/viewers/bim/src/LoadIfcAsFragments.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/LoadIfcAsFragments.js +1 -1
- package/dist/core/components/viewers/bim/src/LoadIfcAsFragments.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js +2 -4
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js.map +1 -1
- package/package.json +1 -1
package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilesSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,OAAO,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,uCAAuC,CAAA;AAQvE,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAUD,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,iBAAiB,qBA+
|
|
1
|
+
{"version":3,"file":"FilesSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,OAAO,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,uCAAuC,CAAA;AAQvE,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAUD,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,iBAAiB,qBA+jBpE"}
|
|
@@ -74,9 +74,20 @@ function FilesSection({ files, query = "" }) {
|
|
|
74
74
|
return [f.id, (_a = f.isVisible) != null ? _a : false];
|
|
75
75
|
})
|
|
76
76
|
);
|
|
77
|
+
const isFileInScene = (file) => {
|
|
78
|
+
var _a, _b;
|
|
79
|
+
if (file.extension === "ids") return activeIDSFileId === file.id;
|
|
80
|
+
if (file.extension === "dxf") {
|
|
81
|
+
return ((_a = dxfGroupsRef.current.get(file.id.toString())) == null ? void 0 : _a.visible) === true;
|
|
82
|
+
}
|
|
83
|
+
if (is3DFile(file.extension)) {
|
|
84
|
+
const info = (_b = modelManagerRef.current) == null ? void 0 : _b.getModelByName(file.name);
|
|
85
|
+
return info ? info.model.visible !== false : false;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
};
|
|
77
89
|
return files.filter((file) => file.tag !== "user").filter((file) => file.type !== "map-file").map((file) => {
|
|
78
|
-
|
|
79
|
-
let isVisible = visibilityMap.has(file.id) ? visibilityMap.get(file.id) : (_a = file.isVisible) != null ? _a : false;
|
|
90
|
+
let isVisible = visibilityMap.has(file.id) ? visibilityMap.get(file.id) : isFileInScene(file);
|
|
80
91
|
if (file.extension === "ids" && activeIDSFileId === file.id) {
|
|
81
92
|
isVisible = true;
|
|
82
93
|
} else if (file.extension === "ids" && activeIDSFileId !== null && activeIDSFileId !== file.id) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.tsx"],"sourcesContent":["import * as React from 'react'\r\nimport * as LR from 'lucide-react'\r\nimport { BimContext, BuildingsContext, MenusContext } from '../../../../../../../../store'\r\nimport { ModelManager } from '../../../../ModelManager'\r\nimport { DXFManager } from '../../../../DXFLoader'\r\nimport * as THREE from 'three'\r\nimport { GizmoController } from '../../../../../utils/GizmoController'\r\nimport { CurrentWorld } from '../../../../CurrentWorld'\r\nimport { Cursor } from '../../../../Cursor'\r\nimport { Highlighter } from '../../../../Highlighter'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useTranslations } from 'next-intl'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { useUploadFileToBuilding, useDeleteFile, useFile } from '../../../../../../../../hooks/files/files'\r\nimport { useFileUploadHandler, useFileDeleteHandler, FileItemComponent, useFileActions, useCommonFileUpload } from '../../../../../../../ui/FilesManager'\r\nimport { IDSManager } from '../../../../IDSManager'\r\nimport { BCFTopicsManager } from '../../../../BCFTopicsManager'\r\nimport { createFileMarker, removeMarker, type AddedFile } from '../../../../tools/AddToBim/src/FileMarkerUtils'\r\nimport type { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'\r\nimport { DbFile as IFile } from '../../../../../../../../types/dbTypes'\r\n\r\n// Hoist options arrays so the array identity is stable across renders.\r\n// Inline `options={[...]}` defeats React.memo on FileItemComponent.\r\ntype FileAction = import('../../../../../../../../types/global').FileAction\r\nconst OPTIONS_3D: FileAction[] = ['download', 'view', 'move', 'info', 'delete']\r\nconst OPTIONS_NON_3D: FileAction[] = ['download', 'view', 'delete']\r\n\r\ninterface FilesSectionProps {\r\n files: IFile[]\r\n query?: string\r\n}\r\n\r\nconst is3DFile = (ext?: string | null): boolean => {\r\n if (!ext) return false\r\n return ['glb', 'gltf', 'fbx', 'obj', 'collada'].includes(ext.toLowerCase())\r\n}\r\n\r\n// Files that live in the 3D scene and can be moved/scaled (3D models + DXF drawings).\r\nconst isPlaceable = (ext?: string | null): boolean => is3DFile(ext) || ext?.toLowerCase() === 'dxf'\r\n\r\nexport function FilesSection({ files, query = '' }: FilesSectionProps) {\r\n const t = useTranslations('FileSelection')\r\n\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimComponents, fragments } = bimState.bim\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { building } = buildingsState.buildings\r\n const buildingId = building?.id || -1\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext)\r\n\r\n const { uploadFile } = useUploadFileToBuilding(buildingId)\r\n const { deleteFile } = useDeleteFile(buildingId)\r\n\r\n const { handleFileUpload } = useFileUploadHandler({\r\n buildingId,\r\n tag: 'file',\r\n uploadFile,\r\n })\r\n\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {\r\n console.log('File deleted successfully')\r\n },\r\n })\r\n\r\n // Local state for file management with isVisible property\r\n const [localFiles, setLocalFiles] = React.useState<(IFile & { isVisible?: boolean })[]>([])\r\n const [activeIDSFileId, setActiveIDSFileId] = React.useState<number | null>(null)\r\n\r\n // Initialize and sync files\r\n React.useEffect(() => {\r\n setLocalFiles(prevFiles => {\r\n const visibilityMap = new Map(\r\n prevFiles.map(f => [f.id, f.isVisible ?? false])\r\n )\r\n return files\r\n .filter(file => file.tag !== 'user')\r\n .filter(file => (file as any).type !== 'map-file')\r\n .map(file => {\r\n // Preserve the user's toggle state for already-tracked files; otherwise honor\r\n // the persisted visibility so files added in-session show as added (not disabled).\r\n let isVisible = visibilityMap.has(file.id) ? visibilityMap.get(file.id)! : (file.isVisible ?? false)\r\n if (file.extension === 'ids' && activeIDSFileId === file.id) {\r\n isVisible = true\r\n } else if (file.extension === 'ids' && activeIDSFileId !== null && activeIDSFileId !== file.id) {\r\n isVisible = false\r\n }\r\n return { ...file, isVisible }\r\n })\r\n .sort((a, b) => a.name.localeCompare(b.name))\r\n })\r\n }, [files, activeIDSFileId])\r\n\r\n // Listen to IDS reset events\r\n React.useEffect(() => {\r\n if (!bimComponents) return\r\n try {\r\n const idsManager = bimComponents.get(IDSManager)\r\n const handleIDSReset = () => {\r\n setActiveIDSFileId(null)\r\n setLocalFiles(prevFiles =>\r\n prevFiles.map(file =>\r\n file.extension === 'ids' ? { ...file, isVisible: false } : file\r\n )\r\n )\r\n }\r\n idsManager.onReset.add(handleIDSReset)\r\n return () => { idsManager.onReset.remove(handleIDSReset) }\r\n } catch {\r\n return\r\n }\r\n }, [bimComponents])\r\n\r\n const modelManager = React.useMemo(() => {\r\n if (!bimComponents) return null\r\n try { return bimComponents.get(ModelManager) } catch { return null }\r\n }, [bimComponents])\r\n const modelManagerRef = React.useRef(modelManager)\r\n React.useEffect(() => { modelManagerRef.current = modelManager }, [modelManager])\r\n\r\n const dxfManager = React.useMemo(() => {\r\n if (!bimComponents) return null\r\n try { return bimComponents.get(DXFManager) } catch { return null }\r\n }, [bimComponents])\r\n // Loaded DXF groups keyed by file id, so visibility toggles can show/hide them.\r\n const dxfGroupsRef = React.useRef<Map<string, THREE.Group>>(new Map())\r\n\r\n // Floating scene markers (pin + actions card) for visible placeable files.\r\n const markersRef = React.useRef<Map<string, { marker: CSS2DObject; file: IFile }>>(new Map())\r\n // Bumped after an object finishes loading so the marker reconcile effect re-runs.\r\n const [loadedTick, setLoadedTick] = React.useState(0)\r\n\r\n const toggleDxfVisibility = React.useCallback(async (file: IFile, visible: boolean) => {\r\n if (!dxfManager || !bimComponents) return\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n\r\n const key = file.id.toString()\r\n const existing = dxfGroupsRef.current.get(key)\r\n if (visible) {\r\n if (existing) { existing.visible = true; return }\r\n try {\r\n const res = await fetch(`/api/presignedUrlDownload/${file.id}`)\r\n if (!res.ok) throw new Error(`Failed to get download URL: ${res.status}`)\r\n const { presignedUrl } = await res.json()\r\n const group = await dxfManager.parse(presignedUrl)\r\n group.name = key\r\n const placed = file.x != null && file.y != null && file.z != null\r\n group.position.copy(placed\r\n ? new THREE.Vector3(file.x as number, file.y as number, file.z as number)\r\n : new THREE.Vector3())\r\n group.scale.setScalar(0.001)\r\n if (file.rotation != null) group.rotation.y = file.rotation as number\r\n world.scene.three.add(group)\r\n dxfGroupsRef.current.set(key, group)\r\n setLoadedTick(t => t + 1)\r\n } catch (err) {\r\n console.error(`[FilesSection] Failed to load DXF \"${file.name}\":`, err)\r\n }\r\n } else if (existing) {\r\n existing.visible = false\r\n }\r\n }, [dxfManager, bimComponents])\r\n\r\n // Gizmo controllers keyed by file name (one gizmo per file at most)\r\n const gizmoControllersRef = React.useRef<Map<string, GizmoController>>(new Map())\r\n\r\n // Track the file ID currently being repositioned so useFile can provide updateFile\r\n const [moveFileId, setMoveFileId] = React.useState<number | null>(null)\r\n const { updateFile } = useFile(moveFileId)\r\n const updateFileRef = React.useRef(updateFile)\r\n React.useEffect(() => { updateFileRef.current = updateFile }, [updateFile])\r\n\r\n const fetchDbFileAsFile = async (file: IFile): Promise<globalThis.File> => {\r\n const response = await fetch(file.url)\r\n const blob = await response.blob()\r\n const mimeType = file.extension === 'ids' ? 'application/xml' : 'application/octet-stream'\r\n return new globalThis.File([blob], file.name, { type: mimeType })\r\n }\r\n\r\n // View handler: IDS, BCF, and 3D file visibility\r\n const handleBimView = React.useCallback(async (file: IFile & { isVisible?: boolean }, newVisibility: boolean) => {\r\n // IDS files\r\n if (file.extension === 'ids') {\r\n const idsManager = bimComponents?.get(IDSManager)\r\n if (!idsManager) return\r\n idsManager.enabled = newVisibility\r\n if (newVisibility) {\r\n setActiveIDSFileId(file.id)\r\n try {\r\n const dbFile = await fetchDbFileAsFile(file)\r\n await idsManager.loadFromFile(dbFile)\r\n await idsManager.loadAndTestIDS()\r\n } catch (error) {\r\n console.error('Error loading IDS file:', error)\r\n }\r\n } else {\r\n setActiveIDSFileId(null)\r\n await idsManager.reset()\r\n }\r\n }\r\n\r\n // BCF files\r\n if (file.extension === 'bcf') {\r\n menusDispatch({ type: 'SET_SIDEBAR_SELECTED_TAB', payload: { selectedTab: 'communication' } })\r\n const bcfManager = bimComponents?.get(BCFTopicsManager)\r\n if (!bcfManager) return\r\n try {\r\n const { topics } = await bcfManager.loadBCFFromUrl(file.url)\r\n if (topics?.length) {\r\n topics.forEach((topic) => {\r\n const exists = bimState.bim.bcfTopics.find(t => t.guid === topic.guid)\r\n if (!exists) {\r\n bimDispatch({ type: 'ADD_BCF_TOPIC', payload: { bcfTopic: topic } })\r\n }\r\n })\r\n }\r\n } catch (error) {\r\n console.error('Failed to load BCF from URL:', error)\r\n }\r\n }\r\n\r\n // 3D model files (GLB/GLTF/FBX/OBJ) managed by ModelManager\r\n if (is3DFile(file.extension) && modelManager) {\r\n const existingModel = modelManager.getModelByName(file.name)\r\n if (newVisibility) {\r\n if (existingModel) {\r\n // Already in scene — just show it\r\n existingModel.model.visible = true\r\n } else {\r\n // Not yet loaded — get a fresh presigned download URL then load\r\n try {\r\n const res = await fetch(`/api/presignedUrlDownload/${file.id}`)\r\n if (!res.ok) throw new Error(`Failed to get download URL: ${res.status}`)\r\n const { presignedUrl } = await res.json()\r\n const position = (file.x != null && file.y != null && file.z != null)\r\n ? new THREE.Vector3(file.x as number, file.y as number, file.z as number)\r\n : new THREE.Vector3(0, 0, 0)\r\n const rotation = file.rotation != null\r\n ? new THREE.Euler(0, file.rotation, 0)\r\n : undefined\r\n await modelManager.load(presignedUrl, file.id.toString(), file.name, {\r\n position,\r\n rotation,\r\n extension: file.extension ?? undefined,\r\n })\r\n } catch (err) {\r\n console.error(`[FilesSection] Failed to load model \"${file.name}\":`, err)\r\n }\r\n }\r\n } else {\r\n if (existingModel) {\r\n existingModel.model.visible = false\r\n }\r\n }\r\n if (fragments) fragments.core.update(true)\r\n }\r\n\r\n // DXF files managed via DXFManager\r\n if (file.extension === 'dxf') {\r\n await toggleDxfVisibility(file, newVisibility)\r\n if (fragments) fragments.core.update(true)\r\n }\r\n setLoadedTick(t => t + 1)\r\n }, [bimComponents, menusDispatch, bimState, bimDispatch, modelManager, fragments, toggleDxfVisibility])\r\n\r\n const highlighter = React.useMemo(() => {\r\n if (!bimComponents) return null\r\n try { return bimComponents.get(Highlighter) } catch { return null }\r\n }, [bimComponents])\r\n\r\n // Raycast into fragments (same logic as useFilePlacement)\r\n const raycast = React.useCallback(async (data: {\r\n camera: THREE.PerspectiveCamera | THREE.OrthographicCamera\r\n mouse: THREE.Vector2\r\n dom: HTMLCanvasElement\r\n }) => {\r\n if (!fragments || !highlighter) return null\r\n const results = []\r\n for (const [modelName, model] of fragments.core.models.list) {\r\n if (highlighter.isModelDisabled(modelName)) continue\r\n const result = await model.raycast(data)\r\n if (result) results.push(result)\r\n }\r\n await Promise.all(results)\r\n if (results.length === 0) return null\r\n let closest = results[0]\r\n for (let i = 1; i < results.length; i++) {\r\n if (results[i].distance < closest.distance) closest = results[i]\r\n }\r\n return closest\r\n }, [fragments, highlighter])\r\n\r\n // Track the file currently being placed (unplaced file → click-to-place)\r\n const [placingFile, setPlacingFile] = React.useState<IFile | null>(null)\r\n\r\n // Click-to-place effect: crosshair + double-click raycast for unplaced files\r\n React.useEffect(() => {\r\n if (!placingFile || !bimComponents) return\r\n\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n\r\n const cursor = bimComponents.get(Cursor)\r\n if (cursor) cursor.cursor = 'crosshair'\r\n\r\n const mouse = new THREE.Vector2()\r\n\r\n const handleDblClick = async (e: MouseEvent) => {\r\n mouse.x = e.clientX\r\n mouse.y = e.clientY\r\n\r\n const result = await raycast({\r\n camera: world.camera.three,\r\n mouse,\r\n dom: world.renderer!.three.domElement!,\r\n })\r\n\r\n if (result?.point && (result.point.x !== 0 || result.point.y !== 0 || result.point.z !== 0)) {\r\n const { x, y, z } = result.point\r\n setMoveFileId(placingFile.id)\r\n // Save coordinates to DB\r\n setTimeout(() => {\r\n updateFileRef.current({ x, y, z } as any)\r\n .catch((err: unknown) => console.error(`Failed to save placement for \"${placingFile.name}\":`, err))\r\n }, 50)\r\n // Load model into scene at the placed position (for 3D files)\r\n if (is3DFile(placingFile.extension) && modelManagerRef.current) {\r\n const existing = modelManagerRef.current.getModelByName(placingFile.name)\r\n if (!existing) {\r\n fetch(`/api/presignedUrlDownload/${placingFile.id}`)\r\n .then(res => res.ok ? res.json() : Promise.reject(res.status))\r\n .then(({ presignedUrl }) =>\r\n modelManagerRef.current!.load(\r\n presignedUrl,\r\n placingFile.id.toString(),\r\n placingFile.name,\r\n { position: new THREE.Vector3(x, y, z), extension: placingFile.extension ?? undefined },\r\n )\r\n )\r\n .catch((err: unknown) => console.error(`Failed to load model \"${placingFile.name}\":`, err))\r\n } else {\r\n existing.model.position.set(x, y, z)\r\n existing.model.visible = true\r\n }\r\n }\r\n // Update local state so it shows as placed and visible\r\n placingFile.x = x\r\n placingFile.y = y\r\n placingFile.z = z\r\n setLocalFiles(prev => prev.map(f => f.id === placingFile.id ? { ...f, x, y, z, isVisible: true } : f))\r\n setPlacingFile(null)\r\n if (cursor) cursor.cursor = ''\r\n }\r\n }\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') {\r\n setPlacingFile(null)\r\n if (cursor) cursor.cursor = ''\r\n }\r\n }\r\n\r\n document.addEventListener('dblclick', handleDblClick)\r\n document.addEventListener('keydown', handleKeyDown)\r\n\r\n return () => {\r\n document.removeEventListener('dblclick', handleDblClick)\r\n document.removeEventListener('keydown', handleKeyDown)\r\n if (cursor) cursor.cursor = ''\r\n }\r\n }, [placingFile, bimComponents, raycast])\r\n\r\n // Resolve the scene object for a file (loaded 3D model or DXF group), if present.\r\n const getSceneObject = React.useCallback((file: IFile): THREE.Object3D | null => {\r\n if (file.extension === 'dxf') return dxfGroupsRef.current.get(file.id.toString()) ?? null\r\n return modelManager?.getModelByName(file.name)?.model ?? null\r\n }, [modelManager])\r\n\r\n // Attach a transform gizmo to a placed object (or re-set its mode); saves on accept.\r\n const editObject = React.useCallback((file: IFile, mode: 'translate' | 'rotate' | 'scale' = 'translate') => {\r\n if (!bimComponents) return\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n const obj = getSceneObject(file)\r\n if (!obj) return\r\n\r\n const key = file.id.toString()\r\n const existing = gizmoControllersRef.current.get(key)\r\n if (existing) { existing.setMode(mode); return }\r\n\r\n const gizmo = new GizmoController(world)\r\n const cleanup = (save: boolean) => {\r\n if (save) {\r\n const { x, y, z } = obj.position\r\n const rotation = obj.rotation.y\r\n updateFileRef.current({ x, y, z, rotation } as any)\r\n .catch((err: unknown) => console.error(`Failed to save position for \"${file.name}\":`, err))\r\n file.x = x; file.y = y; file.z = z; file.rotation = rotation\r\n }\r\n gizmoControllersRef.current.delete(key)\r\n setMoveFileId(null)\r\n }\r\n gizmo.onAccept = () => cleanup(true)\r\n gizmo.onCancel = () => cleanup(false)\r\n gizmo.setMode(mode)\r\n setMoveFileId(file.id)\r\n gizmo.attach(obj)\r\n gizmoControllersRef.current.set(key, gizmo)\r\n }, [bimComponents, getSceneObject])\r\n\r\n // Move handler: unplaced files → click-to-place; placed files → gizmo (load DXF first if needed)\r\n const handleBimMove = React.useCallback((file: IFile) => {\r\n const isPlaced = file.x != null && file.y != null && file.z != null\r\n if (!isPlaced) {\r\n setPlacingFile(file)\r\n setMoveFileId(file.id)\r\n return\r\n }\r\n if (file.extension === 'dxf' && !dxfGroupsRef.current.has(file.id.toString())) {\r\n void toggleDxfVisibility(file, true).then(() => editObject(file, 'translate'))\r\n return\r\n }\r\n editObject(file, 'translate')\r\n }, [editObject, toggleDxfVisibility])\r\n\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: localFiles,\r\n setFiles: setLocalFiles,\r\n buildingId,\r\n handleDeleteFile,\r\n onView: handleBimView,\r\n onMove: handleBimMove,\r\n })\r\n\r\n const { handleAddFile } = useCommonFileUpload({\r\n buildingId,\r\n acceptedFileTypes: '*',\r\n handleFileUpload: async (domFile: globalThis.File) => {\r\n await handleFileUpload(domFile)\r\n },\r\n onUploadSuccess: () => {\r\n console.log('File uploaded successfully')\r\n },\r\n onUploadError: (error) => {\r\n console.error('Error uploading file:', error)\r\n },\r\n })\r\n\r\n const filteredFiles = React.useMemo(() => {\r\n if (!query.trim()) return localFiles\r\n return localFiles.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [localFiles, query])\r\n\r\n const areAllHidden = localFiles.every(f => !f.isVisible)\r\n\r\n const handleSwitchVariant = () => ({\r\n checked: !areAllHidden,\r\n onCheckedChange: async (checked: boolean) => {\r\n setLocalFiles(prev => prev.map(f => ({ ...f, isVisible: checked })))\r\n for (const f of localFiles) {\r\n if (is3DFile(f.extension) && modelManager) {\r\n const existingModel = modelManager.getModelByName(f.name)\r\n if (checked) {\r\n if (existingModel) {\r\n existingModel.model.visible = true\r\n } else {\r\n try {\r\n const res = await fetch(`/api/presignedUrlDownload/${f.id}`)\r\n if (res.ok) {\r\n const { presignedUrl } = await res.json()\r\n const position = (f.x != null && f.y != null && f.z != null)\r\n ? new THREE.Vector3(f.x as number, f.y as number, f.z as number)\r\n : new THREE.Vector3(0, 0, 0)\r\n await modelManager.load(presignedUrl, f.id.toString(), f.name, {\r\n position,\r\n extension: f.extension ?? undefined,\r\n })\r\n }\r\n } catch (err) {\r\n console.error(`[FilesSection] Failed to load model \"${f.name}\":`, err)\r\n }\r\n }\r\n } else if (existingModel) {\r\n existingModel.model.visible = false\r\n }\r\n } else if (f.extension === 'dxf') {\r\n await toggleDxfVisibility(f, checked)\r\n }\r\n }\r\n if (fragments) fragments.core.update(true)\r\n setLoadedTick(t => t + 1)\r\n },\r\n })\r\n\r\n // createFileMarker expects an AddedFile; build a lightweight one from the DB file.\r\n const makeMarkerInput = React.useCallback((file: IFile, position: THREE.Vector3): AddedFile => ({\r\n id: file.id.toString(),\r\n file: new File([], file.name, { type: (file as any).mimeType ?? '' }),\r\n position,\r\n }), [])\r\n\r\n // Reconcile floating markers with the visible + loaded placeable files.\r\n React.useEffect(() => {\r\n if (!bimComponents) return\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n\r\n const wanted = new Map(\r\n localFiles\r\n .filter(f => f.isVisible && isPlaceable(f.extension))\r\n .map(f => [f.id.toString(), f] as const),\r\n )\r\n\r\n for (const [key, entry] of markersRef.current) {\r\n if (!wanted.has(key)) {\r\n removeMarker(entry.marker, world)\r\n markersRef.current.delete(key)\r\n }\r\n }\r\n\r\n for (const [key, file] of wanted) {\r\n if (markersRef.current.has(key)) continue\r\n const obj = getSceneObject(file)\r\n if (!obj) continue // not loaded yet — picked up once loadedTick bumps\r\n const marker = createFileMarker(makeMarkerInput(file, obj.position.clone()), obj, world, (action) => {\r\n if (action === 'delete') { handleAction('delete', file); return }\r\n editObject(file, action === 'move' ? 'translate' : action)\r\n })\r\n if (marker) markersRef.current.set(key, { marker, file })\r\n }\r\n }, [localFiles, loadedTick, bimComponents, getSceneObject, editObject, handleAction, makeMarkerInput])\r\n\r\n // Markers follow their object each frame and hide while that object's gizmo is active.\r\n React.useEffect(() => {\r\n if (!bimComponents) return\r\n let raf = 0\r\n const worldPos = new THREE.Vector3()\r\n const tick = () => {\r\n markersRef.current.forEach(({ marker, file }, key) => {\r\n const obj = getSceneObject(file)\r\n if (!obj) { marker.visible = false; return }\r\n obj.getWorldPosition(worldPos)\r\n marker.position.set(worldPos.x, worldPos.y + 0.2, worldPos.z)\r\n marker.visible = !gizmoControllersRef.current.has(key)\r\n })\r\n raf = requestAnimationFrame(tick)\r\n }\r\n raf = requestAnimationFrame(tick)\r\n return () => cancelAnimationFrame(raf)\r\n }, [bimComponents, getSceneObject])\r\n\r\n // Clean up all markers on unmount so their DOM/React roots don't leak.\r\n const markersCleanupRef = React.useRef(markersRef.current)\r\n React.useEffect(() => {\r\n const markers = markersCleanupRef.current\r\n return () => {\r\n markers.forEach(({ marker }) => removeMarker(marker))\r\n markers.clear()\r\n }\r\n }, [])\r\n\r\n return (\r\n <>\r\n <CollapsibleSection\r\n title={t('filesTitle')}\r\n icon={LR.FileText}\r\n className=\"max-h-40 overflow-y-auto\"\r\n itemCount={filteredFiles.length}\r\n switchVariant={handleSwitchVariant()}\r\n onAddItem={handleAddFile}\r\n addItemTitle={t('addFileTitle')}\r\n >\r\n <div className=\"space-y-1\">\r\n {filteredFiles.map((item) => (\r\n <FileItemComponent\r\n key={item.id}\r\n file={item}\r\n onAction={handleAction}\r\n options={isPlaceable(item.extension) ? OPTIONS_3D : OPTIONS_NON_3D}\r\n translationKey=\"FileSelection\"\r\n confirmDelete={false}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":["t"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.tsx"],"sourcesContent":["import * as React from 'react'\r\nimport * as LR from 'lucide-react'\r\nimport { BimContext, BuildingsContext, MenusContext } from '../../../../../../../../store'\r\nimport { ModelManager } from '../../../../ModelManager'\r\nimport { DXFManager } from '../../../../DXFLoader'\r\nimport * as THREE from 'three'\r\nimport { GizmoController } from '../../../../../utils/GizmoController'\r\nimport { CurrentWorld } from '../../../../CurrentWorld'\r\nimport { Cursor } from '../../../../Cursor'\r\nimport { Highlighter } from '../../../../Highlighter'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useTranslations } from 'next-intl'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { useUploadFileToBuilding, useDeleteFile, useFile } from '../../../../../../../../hooks/files/files'\r\nimport { useFileUploadHandler, useFileDeleteHandler, FileItemComponent, useFileActions, useCommonFileUpload } from '../../../../../../../ui/FilesManager'\r\nimport { IDSManager } from '../../../../IDSManager'\r\nimport { BCFTopicsManager } from '../../../../BCFTopicsManager'\r\nimport { createFileMarker, removeMarker, type AddedFile } from '../../../../tools/AddToBim/src/FileMarkerUtils'\r\nimport type { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'\r\nimport { DbFile as IFile } from '../../../../../../../../types/dbTypes'\r\n\r\n// Hoist options arrays so the array identity is stable across renders.\r\n// Inline `options={[...]}` defeats React.memo on FileItemComponent.\r\ntype FileAction = import('../../../../../../../../types/global').FileAction\r\nconst OPTIONS_3D: FileAction[] = ['download', 'view', 'move', 'info', 'delete']\r\nconst OPTIONS_NON_3D: FileAction[] = ['download', 'view', 'delete']\r\n\r\ninterface FilesSectionProps {\r\n files: IFile[]\r\n query?: string\r\n}\r\n\r\nconst is3DFile = (ext?: string | null): boolean => {\r\n if (!ext) return false\r\n return ['glb', 'gltf', 'fbx', 'obj', 'collada'].includes(ext.toLowerCase())\r\n}\r\n\r\n// Files that live in the 3D scene and can be moved/scaled (3D models + DXF drawings).\r\nconst isPlaceable = (ext?: string | null): boolean => is3DFile(ext) || ext?.toLowerCase() === 'dxf'\r\n\r\nexport function FilesSection({ files, query = '' }: FilesSectionProps) {\r\n const t = useTranslations('FileSelection')\r\n\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimComponents, fragments } = bimState.bim\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { building } = buildingsState.buildings\r\n const buildingId = building?.id || -1\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext)\r\n\r\n const { uploadFile } = useUploadFileToBuilding(buildingId)\r\n const { deleteFile } = useDeleteFile(buildingId)\r\n\r\n const { handleFileUpload } = useFileUploadHandler({\r\n buildingId,\r\n tag: 'file',\r\n uploadFile,\r\n })\r\n\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {\r\n console.log('File deleted successfully')\r\n },\r\n })\r\n\r\n // Local state for file management with isVisible property\r\n const [localFiles, setLocalFiles] = React.useState<(IFile & { isVisible?: boolean })[]>([])\r\n const [activeIDSFileId, setActiveIDSFileId] = React.useState<number | null>(null)\r\n\r\n // Initialize and sync files\r\n React.useEffect(() => {\r\n setLocalFiles(prevFiles => {\r\n const visibilityMap = new Map(\r\n prevFiles.map(f => [f.id, f.isVisible ?? false])\r\n )\r\n // A file is \"visible\" only if it's actually present and shown in the 3D scene\r\n // (a loaded model, a loaded DXF group, or the active IDS). This mirrors the Map\r\n // viewer, which derives visibility from on-scene state (mapFileIds) rather than\r\n // from the persisted `file.isVisible` flag — so nothing shows as visible on open\r\n // unless it has been toggled on or just placed/added into the scene.\r\n const isFileInScene = (file: IFile): boolean => {\r\n if (file.extension === 'ids') return activeIDSFileId === file.id\r\n if (file.extension === 'dxf') {\r\n return dxfGroupsRef.current.get(file.id.toString())?.visible === true\r\n }\r\n if (is3DFile(file.extension)) {\r\n const info = modelManagerRef.current?.getModelByName(file.name)\r\n return info ? info.model.visible !== false : false\r\n }\r\n return false\r\n }\r\n return files\r\n .filter(file => file.tag !== 'user')\r\n .filter(file => (file as any).type !== 'map-file')\r\n .map(file => {\r\n // Preserve the user's in-session toggle for already-tracked files; for files\r\n // seen for the first time, derive visibility from the actual scene state.\r\n let isVisible = visibilityMap.has(file.id) ? visibilityMap.get(file.id)! : isFileInScene(file)\r\n if (file.extension === 'ids' && activeIDSFileId === file.id) {\r\n isVisible = true\r\n } else if (file.extension === 'ids' && activeIDSFileId !== null && activeIDSFileId !== file.id) {\r\n isVisible = false\r\n }\r\n return { ...file, isVisible }\r\n })\r\n .sort((a, b) => a.name.localeCompare(b.name))\r\n })\r\n }, [files, activeIDSFileId])\r\n\r\n // Listen to IDS reset events\r\n React.useEffect(() => {\r\n if (!bimComponents) return\r\n try {\r\n const idsManager = bimComponents.get(IDSManager)\r\n const handleIDSReset = () => {\r\n setActiveIDSFileId(null)\r\n setLocalFiles(prevFiles =>\r\n prevFiles.map(file =>\r\n file.extension === 'ids' ? { ...file, isVisible: false } : file\r\n )\r\n )\r\n }\r\n idsManager.onReset.add(handleIDSReset)\r\n return () => { idsManager.onReset.remove(handleIDSReset) }\r\n } catch {\r\n return\r\n }\r\n }, [bimComponents])\r\n\r\n const modelManager = React.useMemo(() => {\r\n if (!bimComponents) return null\r\n try { return bimComponents.get(ModelManager) } catch { return null }\r\n }, [bimComponents])\r\n const modelManagerRef = React.useRef(modelManager)\r\n React.useEffect(() => { modelManagerRef.current = modelManager }, [modelManager])\r\n\r\n const dxfManager = React.useMemo(() => {\r\n if (!bimComponents) return null\r\n try { return bimComponents.get(DXFManager) } catch { return null }\r\n }, [bimComponents])\r\n // Loaded DXF groups keyed by file id, so visibility toggles can show/hide them.\r\n const dxfGroupsRef = React.useRef<Map<string, THREE.Group>>(new Map())\r\n\r\n // Floating scene markers (pin + actions card) for visible placeable files.\r\n const markersRef = React.useRef<Map<string, { marker: CSS2DObject; file: IFile }>>(new Map())\r\n // Bumped after an object finishes loading so the marker reconcile effect re-runs.\r\n const [loadedTick, setLoadedTick] = React.useState(0)\r\n\r\n const toggleDxfVisibility = React.useCallback(async (file: IFile, visible: boolean) => {\r\n if (!dxfManager || !bimComponents) return\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n\r\n const key = file.id.toString()\r\n const existing = dxfGroupsRef.current.get(key)\r\n if (visible) {\r\n if (existing) { existing.visible = true; return }\r\n try {\r\n const res = await fetch(`/api/presignedUrlDownload/${file.id}`)\r\n if (!res.ok) throw new Error(`Failed to get download URL: ${res.status}`)\r\n const { presignedUrl } = await res.json()\r\n const group = await dxfManager.parse(presignedUrl)\r\n group.name = key\r\n const placed = file.x != null && file.y != null && file.z != null\r\n group.position.copy(placed\r\n ? new THREE.Vector3(file.x as number, file.y as number, file.z as number)\r\n : new THREE.Vector3())\r\n group.scale.setScalar(0.001)\r\n if (file.rotation != null) group.rotation.y = file.rotation as number\r\n world.scene.three.add(group)\r\n dxfGroupsRef.current.set(key, group)\r\n setLoadedTick(t => t + 1)\r\n } catch (err) {\r\n console.error(`[FilesSection] Failed to load DXF \"${file.name}\":`, err)\r\n }\r\n } else if (existing) {\r\n existing.visible = false\r\n }\r\n }, [dxfManager, bimComponents])\r\n\r\n // Gizmo controllers keyed by file name (one gizmo per file at most)\r\n const gizmoControllersRef = React.useRef<Map<string, GizmoController>>(new Map())\r\n\r\n // Track the file ID currently being repositioned so useFile can provide updateFile\r\n const [moveFileId, setMoveFileId] = React.useState<number | null>(null)\r\n const { updateFile } = useFile(moveFileId)\r\n const updateFileRef = React.useRef(updateFile)\r\n React.useEffect(() => { updateFileRef.current = updateFile }, [updateFile])\r\n\r\n const fetchDbFileAsFile = async (file: IFile): Promise<globalThis.File> => {\r\n const response = await fetch(file.url)\r\n const blob = await response.blob()\r\n const mimeType = file.extension === 'ids' ? 'application/xml' : 'application/octet-stream'\r\n return new globalThis.File([blob], file.name, { type: mimeType })\r\n }\r\n\r\n // View handler: IDS, BCF, and 3D file visibility\r\n const handleBimView = React.useCallback(async (file: IFile & { isVisible?: boolean }, newVisibility: boolean) => {\r\n // IDS files\r\n if (file.extension === 'ids') {\r\n const idsManager = bimComponents?.get(IDSManager)\r\n if (!idsManager) return\r\n idsManager.enabled = newVisibility\r\n if (newVisibility) {\r\n setActiveIDSFileId(file.id)\r\n try {\r\n const dbFile = await fetchDbFileAsFile(file)\r\n await idsManager.loadFromFile(dbFile)\r\n await idsManager.loadAndTestIDS()\r\n } catch (error) {\r\n console.error('Error loading IDS file:', error)\r\n }\r\n } else {\r\n setActiveIDSFileId(null)\r\n await idsManager.reset()\r\n }\r\n }\r\n\r\n // BCF files\r\n if (file.extension === 'bcf') {\r\n menusDispatch({ type: 'SET_SIDEBAR_SELECTED_TAB', payload: { selectedTab: 'communication' } })\r\n const bcfManager = bimComponents?.get(BCFTopicsManager)\r\n if (!bcfManager) return\r\n try {\r\n const { topics } = await bcfManager.loadBCFFromUrl(file.url)\r\n if (topics?.length) {\r\n topics.forEach((topic) => {\r\n const exists = bimState.bim.bcfTopics.find(t => t.guid === topic.guid)\r\n if (!exists) {\r\n bimDispatch({ type: 'ADD_BCF_TOPIC', payload: { bcfTopic: topic } })\r\n }\r\n })\r\n }\r\n } catch (error) {\r\n console.error('Failed to load BCF from URL:', error)\r\n }\r\n }\r\n\r\n // 3D model files (GLB/GLTF/FBX/OBJ) managed by ModelManager\r\n if (is3DFile(file.extension) && modelManager) {\r\n const existingModel = modelManager.getModelByName(file.name)\r\n if (newVisibility) {\r\n if (existingModel) {\r\n // Already in scene — just show it\r\n existingModel.model.visible = true\r\n } else {\r\n // Not yet loaded — get a fresh presigned download URL then load\r\n try {\r\n const res = await fetch(`/api/presignedUrlDownload/${file.id}`)\r\n if (!res.ok) throw new Error(`Failed to get download URL: ${res.status}`)\r\n const { presignedUrl } = await res.json()\r\n const position = (file.x != null && file.y != null && file.z != null)\r\n ? new THREE.Vector3(file.x as number, file.y as number, file.z as number)\r\n : new THREE.Vector3(0, 0, 0)\r\n const rotation = file.rotation != null\r\n ? new THREE.Euler(0, file.rotation, 0)\r\n : undefined\r\n await modelManager.load(presignedUrl, file.id.toString(), file.name, {\r\n position,\r\n rotation,\r\n extension: file.extension ?? undefined,\r\n })\r\n } catch (err) {\r\n console.error(`[FilesSection] Failed to load model \"${file.name}\":`, err)\r\n }\r\n }\r\n } else {\r\n if (existingModel) {\r\n existingModel.model.visible = false\r\n }\r\n }\r\n if (fragments) fragments.core.update(true)\r\n }\r\n\r\n // DXF files managed via DXFManager\r\n if (file.extension === 'dxf') {\r\n await toggleDxfVisibility(file, newVisibility)\r\n if (fragments) fragments.core.update(true)\r\n }\r\n setLoadedTick(t => t + 1)\r\n }, [bimComponents, menusDispatch, bimState, bimDispatch, modelManager, fragments, toggleDxfVisibility])\r\n\r\n const highlighter = React.useMemo(() => {\r\n if (!bimComponents) return null\r\n try { return bimComponents.get(Highlighter) } catch { return null }\r\n }, [bimComponents])\r\n\r\n // Raycast into fragments (same logic as useFilePlacement)\r\n const raycast = React.useCallback(async (data: {\r\n camera: THREE.PerspectiveCamera | THREE.OrthographicCamera\r\n mouse: THREE.Vector2\r\n dom: HTMLCanvasElement\r\n }) => {\r\n if (!fragments || !highlighter) return null\r\n const results = []\r\n for (const [modelName, model] of fragments.core.models.list) {\r\n if (highlighter.isModelDisabled(modelName)) continue\r\n const result = await model.raycast(data)\r\n if (result) results.push(result)\r\n }\r\n await Promise.all(results)\r\n if (results.length === 0) return null\r\n let closest = results[0]\r\n for (let i = 1; i < results.length; i++) {\r\n if (results[i].distance < closest.distance) closest = results[i]\r\n }\r\n return closest\r\n }, [fragments, highlighter])\r\n\r\n // Track the file currently being placed (unplaced file → click-to-place)\r\n const [placingFile, setPlacingFile] = React.useState<IFile | null>(null)\r\n\r\n // Click-to-place effect: crosshair + double-click raycast for unplaced files\r\n React.useEffect(() => {\r\n if (!placingFile || !bimComponents) return\r\n\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n\r\n const cursor = bimComponents.get(Cursor)\r\n if (cursor) cursor.cursor = 'crosshair'\r\n\r\n const mouse = new THREE.Vector2()\r\n\r\n const handleDblClick = async (e: MouseEvent) => {\r\n mouse.x = e.clientX\r\n mouse.y = e.clientY\r\n\r\n const result = await raycast({\r\n camera: world.camera.three,\r\n mouse,\r\n dom: world.renderer!.three.domElement!,\r\n })\r\n\r\n if (result?.point && (result.point.x !== 0 || result.point.y !== 0 || result.point.z !== 0)) {\r\n const { x, y, z } = result.point\r\n setMoveFileId(placingFile.id)\r\n // Save coordinates to DB\r\n setTimeout(() => {\r\n updateFileRef.current({ x, y, z } as any)\r\n .catch((err: unknown) => console.error(`Failed to save placement for \"${placingFile.name}\":`, err))\r\n }, 50)\r\n // Load model into scene at the placed position (for 3D files)\r\n if (is3DFile(placingFile.extension) && modelManagerRef.current) {\r\n const existing = modelManagerRef.current.getModelByName(placingFile.name)\r\n if (!existing) {\r\n fetch(`/api/presignedUrlDownload/${placingFile.id}`)\r\n .then(res => res.ok ? res.json() : Promise.reject(res.status))\r\n .then(({ presignedUrl }) =>\r\n modelManagerRef.current!.load(\r\n presignedUrl,\r\n placingFile.id.toString(),\r\n placingFile.name,\r\n { position: new THREE.Vector3(x, y, z), extension: placingFile.extension ?? undefined },\r\n )\r\n )\r\n .catch((err: unknown) => console.error(`Failed to load model \"${placingFile.name}\":`, err))\r\n } else {\r\n existing.model.position.set(x, y, z)\r\n existing.model.visible = true\r\n }\r\n }\r\n // Update local state so it shows as placed and visible\r\n placingFile.x = x\r\n placingFile.y = y\r\n placingFile.z = z\r\n setLocalFiles(prev => prev.map(f => f.id === placingFile.id ? { ...f, x, y, z, isVisible: true } : f))\r\n setPlacingFile(null)\r\n if (cursor) cursor.cursor = ''\r\n }\r\n }\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') {\r\n setPlacingFile(null)\r\n if (cursor) cursor.cursor = ''\r\n }\r\n }\r\n\r\n document.addEventListener('dblclick', handleDblClick)\r\n document.addEventListener('keydown', handleKeyDown)\r\n\r\n return () => {\r\n document.removeEventListener('dblclick', handleDblClick)\r\n document.removeEventListener('keydown', handleKeyDown)\r\n if (cursor) cursor.cursor = ''\r\n }\r\n }, [placingFile, bimComponents, raycast])\r\n\r\n // Resolve the scene object for a file (loaded 3D model or DXF group), if present.\r\n const getSceneObject = React.useCallback((file: IFile): THREE.Object3D | null => {\r\n if (file.extension === 'dxf') return dxfGroupsRef.current.get(file.id.toString()) ?? null\r\n return modelManager?.getModelByName(file.name)?.model ?? null\r\n }, [modelManager])\r\n\r\n // Attach a transform gizmo to a placed object (or re-set its mode); saves on accept.\r\n const editObject = React.useCallback((file: IFile, mode: 'translate' | 'rotate' | 'scale' = 'translate') => {\r\n if (!bimComponents) return\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n const obj = getSceneObject(file)\r\n if (!obj) return\r\n\r\n const key = file.id.toString()\r\n const existing = gizmoControllersRef.current.get(key)\r\n if (existing) { existing.setMode(mode); return }\r\n\r\n const gizmo = new GizmoController(world)\r\n const cleanup = (save: boolean) => {\r\n if (save) {\r\n const { x, y, z } = obj.position\r\n const rotation = obj.rotation.y\r\n updateFileRef.current({ x, y, z, rotation } as any)\r\n .catch((err: unknown) => console.error(`Failed to save position for \"${file.name}\":`, err))\r\n file.x = x; file.y = y; file.z = z; file.rotation = rotation\r\n }\r\n gizmoControllersRef.current.delete(key)\r\n setMoveFileId(null)\r\n }\r\n gizmo.onAccept = () => cleanup(true)\r\n gizmo.onCancel = () => cleanup(false)\r\n gizmo.setMode(mode)\r\n setMoveFileId(file.id)\r\n gizmo.attach(obj)\r\n gizmoControllersRef.current.set(key, gizmo)\r\n }, [bimComponents, getSceneObject])\r\n\r\n // Move handler: unplaced files → click-to-place; placed files → gizmo (load DXF first if needed)\r\n const handleBimMove = React.useCallback((file: IFile) => {\r\n const isPlaced = file.x != null && file.y != null && file.z != null\r\n if (!isPlaced) {\r\n setPlacingFile(file)\r\n setMoveFileId(file.id)\r\n return\r\n }\r\n if (file.extension === 'dxf' && !dxfGroupsRef.current.has(file.id.toString())) {\r\n void toggleDxfVisibility(file, true).then(() => editObject(file, 'translate'))\r\n return\r\n }\r\n editObject(file, 'translate')\r\n }, [editObject, toggleDxfVisibility])\r\n\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: localFiles,\r\n setFiles: setLocalFiles,\r\n buildingId,\r\n handleDeleteFile,\r\n onView: handleBimView,\r\n onMove: handleBimMove,\r\n })\r\n\r\n const { handleAddFile } = useCommonFileUpload({\r\n buildingId,\r\n acceptedFileTypes: '*',\r\n handleFileUpload: async (domFile: globalThis.File) => {\r\n await handleFileUpload(domFile)\r\n },\r\n onUploadSuccess: () => {\r\n console.log('File uploaded successfully')\r\n },\r\n onUploadError: (error) => {\r\n console.error('Error uploading file:', error)\r\n },\r\n })\r\n\r\n const filteredFiles = React.useMemo(() => {\r\n if (!query.trim()) return localFiles\r\n return localFiles.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [localFiles, query])\r\n\r\n const areAllHidden = localFiles.every(f => !f.isVisible)\r\n\r\n const handleSwitchVariant = () => ({\r\n checked: !areAllHidden,\r\n onCheckedChange: async (checked: boolean) => {\r\n setLocalFiles(prev => prev.map(f => ({ ...f, isVisible: checked })))\r\n for (const f of localFiles) {\r\n if (is3DFile(f.extension) && modelManager) {\r\n const existingModel = modelManager.getModelByName(f.name)\r\n if (checked) {\r\n if (existingModel) {\r\n existingModel.model.visible = true\r\n } else {\r\n try {\r\n const res = await fetch(`/api/presignedUrlDownload/${f.id}`)\r\n if (res.ok) {\r\n const { presignedUrl } = await res.json()\r\n const position = (f.x != null && f.y != null && f.z != null)\r\n ? new THREE.Vector3(f.x as number, f.y as number, f.z as number)\r\n : new THREE.Vector3(0, 0, 0)\r\n await modelManager.load(presignedUrl, f.id.toString(), f.name, {\r\n position,\r\n extension: f.extension ?? undefined,\r\n })\r\n }\r\n } catch (err) {\r\n console.error(`[FilesSection] Failed to load model \"${f.name}\":`, err)\r\n }\r\n }\r\n } else if (existingModel) {\r\n existingModel.model.visible = false\r\n }\r\n } else if (f.extension === 'dxf') {\r\n await toggleDxfVisibility(f, checked)\r\n }\r\n }\r\n if (fragments) fragments.core.update(true)\r\n setLoadedTick(t => t + 1)\r\n },\r\n })\r\n\r\n // createFileMarker expects an AddedFile; build a lightweight one from the DB file.\r\n const makeMarkerInput = React.useCallback((file: IFile, position: THREE.Vector3): AddedFile => ({\r\n id: file.id.toString(),\r\n file: new File([], file.name, { type: (file as any).mimeType ?? '' }),\r\n position,\r\n }), [])\r\n\r\n // Reconcile floating markers with the visible + loaded placeable files.\r\n React.useEffect(() => {\r\n if (!bimComponents) return\r\n const world = bimComponents.get(CurrentWorld).world\r\n if (!world) return\r\n\r\n const wanted = new Map(\r\n localFiles\r\n .filter(f => f.isVisible && isPlaceable(f.extension))\r\n .map(f => [f.id.toString(), f] as const),\r\n )\r\n\r\n for (const [key, entry] of markersRef.current) {\r\n if (!wanted.has(key)) {\r\n removeMarker(entry.marker, world)\r\n markersRef.current.delete(key)\r\n }\r\n }\r\n\r\n for (const [key, file] of wanted) {\r\n if (markersRef.current.has(key)) continue\r\n const obj = getSceneObject(file)\r\n if (!obj) continue // not loaded yet — picked up once loadedTick bumps\r\n const marker = createFileMarker(makeMarkerInput(file, obj.position.clone()), obj, world, (action) => {\r\n if (action === 'delete') { handleAction('delete', file); return }\r\n editObject(file, action === 'move' ? 'translate' : action)\r\n })\r\n if (marker) markersRef.current.set(key, { marker, file })\r\n }\r\n }, [localFiles, loadedTick, bimComponents, getSceneObject, editObject, handleAction, makeMarkerInput])\r\n\r\n // Markers follow their object each frame and hide while that object's gizmo is active.\r\n React.useEffect(() => {\r\n if (!bimComponents) return\r\n let raf = 0\r\n const worldPos = new THREE.Vector3()\r\n const tick = () => {\r\n markersRef.current.forEach(({ marker, file }, key) => {\r\n const obj = getSceneObject(file)\r\n if (!obj) { marker.visible = false; return }\r\n obj.getWorldPosition(worldPos)\r\n marker.position.set(worldPos.x, worldPos.y + 0.2, worldPos.z)\r\n marker.visible = !gizmoControllersRef.current.has(key)\r\n })\r\n raf = requestAnimationFrame(tick)\r\n }\r\n raf = requestAnimationFrame(tick)\r\n return () => cancelAnimationFrame(raf)\r\n }, [bimComponents, getSceneObject])\r\n\r\n // Clean up all markers on unmount so their DOM/React roots don't leak.\r\n const markersCleanupRef = React.useRef(markersRef.current)\r\n React.useEffect(() => {\r\n const markers = markersCleanupRef.current\r\n return () => {\r\n markers.forEach(({ marker }) => removeMarker(marker))\r\n markers.clear()\r\n }\r\n }, [])\r\n\r\n return (\r\n <>\r\n <CollapsibleSection\r\n title={t('filesTitle')}\r\n icon={LR.FileText}\r\n className=\"max-h-40 overflow-y-auto\"\r\n itemCount={filteredFiles.length}\r\n switchVariant={handleSwitchVariant()}\r\n onAddItem={handleAddFile}\r\n addItemTitle={t('addFileTitle')}\r\n >\r\n <div className=\"space-y-1\">\r\n {filteredFiles.map((item) => (\r\n <FileItemComponent\r\n key={item.id}\r\n file={item}\r\n onAction={handleAction}\r\n options={isPlaceable(item.extension) ? OPTIONS_3D : OPTIONS_NON_3D}\r\n translationKey=\"FileSelection\"\r\n confirmDelete={false}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":["t"]}
|
package/dist/core/components/viewers/bim/src/BimSidebar/src/SettingsTab/src/GridManagement.js
CHANGED
|
@@ -16,7 +16,8 @@ function GridManagement() {
|
|
|
16
16
|
return (_b = (_a = grid == null ? void 0 : grid.config) == null ? void 0 : _a.visible) != null ? _b : true;
|
|
17
17
|
});
|
|
18
18
|
const [gridColor, setGridColor] = React.useState(() => {
|
|
19
|
-
|
|
19
|
+
var _a;
|
|
20
|
+
return ((_a = grid == null ? void 0 : grid.config) == null ? void 0 : _a.color) ? `#${grid.config.color.getHexString()}` : "#bbbbbb";
|
|
20
21
|
});
|
|
21
22
|
const [primarySize, setPrimarySize] = React.useState(() => {
|
|
22
23
|
var _a, _b;
|
package/dist/core/components/viewers/bim/src/BimSidebar/src/SettingsTab/src/GridManagement.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/SettingsTab/src/GridManagement.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { SliderWithInput } from '../../../../../../../ui/Slider'\r\nimport { ColorInput } from '../../../../../../../ui/Input'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { BimContext } from '../../../../../../../../store'\r\nimport * as THREE from 'three'\r\n\r\nexport function GridManagement() {\r\n // Translation\r\n const t = useTranslations('GridManagement')\r\n\r\n const { dispatch: bimDispatch, state: bimState } = React.useContext(BimContext)\r\n const { grid } = bimState.bim\r\n\r\n // Use lazy initialization to get values from grid\r\n const [gridVisible, setGridVisible] = React.useState(() => {\r\n return grid?.config?.visible ?? true\r\n })\r\n const [gridColor, setGridColor] = React.useState(() => {\r\n return grid.config.color ? `#${grid.config.color.getHexString()}` : '#bbbbbb'\r\n })\r\n const [primarySize, setPrimarySize] = React.useState(() => {\r\n return [grid?.config?.primarySize ?? 1]\r\n })\r\n const [secondarySize, setSecondarySize] = React.useState(() => {\r\n return [grid?.config?.secondarySize ?? 10]\r\n })\r\n const [elevation, setElevation] = React.useState(() => {\r\n return [grid?.three?.position?.y ?? 0]\r\n })\r\n const [rotationY, setRotationZ] = React.useState(() => {\r\n const rotationDegrees = grid?.three?.rotation?.y ? (grid.three.rotation.y * 180) / Math.PI : 0\r\n return [rotationDegrees]\r\n })\r\n\r\n // Track if we've initialized to prevent re-initialization\r\n const [initialized, setInitialized] = React.useState(false)\r\n\r\n // Initialize state with current grid values (only once)\r\n React.useEffect(() => {\r\n if (!grid || initialized) return\r\n\r\n // Load all values from grid in one go\r\n if (grid.config) {\r\n setGridVisible(grid.config.visible ?? true)\r\n setPrimarySize([grid.config.primarySize ?? 1])\r\n setSecondarySize([grid.config.secondarySize ?? 10])\r\n if (grid.config.color) {\r\n setGridColor(`#${grid.config.color.getHexString()}`)\r\n }\r\n }\r\n\r\n if (grid.three) {\r\n if (grid.three.position) {\r\n setElevation([grid.three.position.y ?? 0])\r\n }\r\n if (grid.three.rotation) {\r\n const rotationDegrees = (grid.three.rotation.y * 180) / Math.PI\r\n setRotationZ([rotationDegrees ?? 0])\r\n }\r\n }\r\n\r\n setInitialized(true)\r\n }, [grid, initialized])\r\n\r\n // Update grid visibility when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentVisible = grid.config.visible ?? true\r\n if (currentVisible !== gridVisible) {\r\n grid.config.visible = gridVisible\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [gridVisible, grid, initialized, bimDispatch])\r\n\r\n // Update grid color when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentColor = grid.config.color ? `#${grid.config.color.getHexString()}` : '#bbbbbb'\r\n if (currentColor !== gridColor) {\r\n grid.config.color = new THREE.Color(gridColor)\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [gridColor, grid, initialized, bimDispatch])\r\n\r\n // Update grid primary size when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentPrimarySize = grid.config.primarySize ?? 1\r\n if (currentPrimarySize !== primarySize[0]) {\r\n grid.config.primarySize = primarySize[0]\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [primarySize, grid, initialized, bimDispatch])\r\n\r\n // Update grid secondary size when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentSecondarySize = grid.config.secondarySize ?? 10\r\n if (currentSecondarySize !== secondarySize[0]) {\r\n grid.config.secondarySize = secondarySize[0]\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [secondarySize, grid, initialized, bimDispatch])\r\n\r\n // Update grid elevation when changed\r\n React.useEffect(() => {\r\n if (!grid?.three?.position || !initialized) return\r\n\r\n const currentElevation = grid.three.position.y ?? 0\r\n if (currentElevation !== elevation[0]) {\r\n grid.three.position.y = elevation[0]\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [elevation, grid, initialized, bimDispatch])\r\n\r\n // Update grid rotation when changed\r\n React.useEffect(() => {\r\n if (!grid?.three?.rotation || !initialized) return\r\n\r\n const currentRotationDegrees = (grid.three.rotation.y * 180) / Math.PI\r\n if (Math.abs(currentRotationDegrees - rotationY[0]) > 0.001) { // Use small tolerance for floating point comparison\r\n grid.three.rotation.y = (rotationY[0] * Math.PI) / 180\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [rotationY, grid, initialized, bimDispatch])\r\n\r\n return (\r\n <CollapsibleSection\r\n title={t('gridTitle')}\r\n chevronPosition=\"left\"\r\n switchVariant={{\r\n checked: gridVisible,\r\n onCheckedChange: setGridVisible,\r\n disabled: false,\r\n }}\r\n defaultOpen={false}\r\n >\r\n <div className=\"space-y-4\">\r\n {/* Grid Color */}\r\n <div className=\"space-y-2\">\r\n <label className={`text-sm font-medium ${gridVisible ? '' : 'text-gray-400'}`}>Grid Color</label>\r\n <div className={`p-2 border rounded-md ${gridVisible ? 'bg-white' : 'bg-gray-100'}`}>\r\n <ColorInput\r\n value={gridColor}\r\n onChange={e => setGridColor(e.target.value)}\r\n disabled={!gridVisible}\r\n defaultColor=\"#bbbbbb\"\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Grid Primary Size */}\r\n <SliderWithInput\r\n label={t('primaryLabel')}\r\n value={primarySize}\r\n onValueChange={setPrimarySize}\r\n min={0}\r\n max={10}\r\n step={0.1}\r\n disabled={!gridVisible}\r\n />\r\n\r\n {/* Grid Secondary Size */}\r\n <SliderWithInput\r\n label={t('secondaryLabel')}\r\n value={secondarySize}\r\n onValueChange={setSecondarySize}\r\n min={0}\r\n max={20}\r\n step={0.1}\r\n disabled={!gridVisible}\r\n />\r\n\r\n {/* Grid Elevation */}\r\n <SliderWithInput\r\n label={t('elevationLabel')}\r\n value={elevation}\r\n onValueChange={setElevation}\r\n min={-50}\r\n max={50}\r\n step={0.5}\r\n unit=\"m\"\r\n disabled={!gridVisible}\r\n />\r\n\r\n {/* Grid Rotation */}\r\n <SliderWithInput\r\n label={t('rotationLabel')}\r\n value={rotationY}\r\n onValueChange={setRotationZ}\r\n min={-360}\r\n max={360}\r\n step={1}\r\n unit=\"°\"\r\n disabled={!gridVisible}\r\n />\r\n </div>\r\n </CollapsibleSection>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/SettingsTab/src/GridManagement.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { SliderWithInput } from '../../../../../../../ui/Slider'\r\nimport { ColorInput } from '../../../../../../../ui/Input'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { BimContext } from '../../../../../../../../store'\r\nimport * as THREE from 'three'\r\n\r\nexport function GridManagement() {\r\n // Translation\r\n const t = useTranslations('GridManagement')\r\n\r\n const { dispatch: bimDispatch, state: bimState } = React.useContext(BimContext)\r\n const { grid } = bimState.bim\r\n\r\n // Use lazy initialization to get values from grid\r\n const [gridVisible, setGridVisible] = React.useState(() => {\r\n return grid?.config?.visible ?? true\r\n })\r\n const [gridColor, setGridColor] = React.useState(() => {\r\n return grid?.config?.color ? `#${grid.config.color.getHexString()}` : '#bbbbbb'\r\n })\r\n const [primarySize, setPrimarySize] = React.useState(() => {\r\n return [grid?.config?.primarySize ?? 1]\r\n })\r\n const [secondarySize, setSecondarySize] = React.useState(() => {\r\n return [grid?.config?.secondarySize ?? 10]\r\n })\r\n const [elevation, setElevation] = React.useState(() => {\r\n return [grid?.three?.position?.y ?? 0]\r\n })\r\n const [rotationY, setRotationZ] = React.useState(() => {\r\n const rotationDegrees = grid?.three?.rotation?.y ? (grid.three.rotation.y * 180) / Math.PI : 0\r\n return [rotationDegrees]\r\n })\r\n\r\n // Track if we've initialized to prevent re-initialization\r\n const [initialized, setInitialized] = React.useState(false)\r\n\r\n // Initialize state with current grid values (only once)\r\n React.useEffect(() => {\r\n if (!grid || initialized) return\r\n\r\n // Load all values from grid in one go\r\n if (grid.config) {\r\n setGridVisible(grid.config.visible ?? true)\r\n setPrimarySize([grid.config.primarySize ?? 1])\r\n setSecondarySize([grid.config.secondarySize ?? 10])\r\n if (grid.config.color) {\r\n setGridColor(`#${grid.config.color.getHexString()}`)\r\n }\r\n }\r\n\r\n if (grid.three) {\r\n if (grid.three.position) {\r\n setElevation([grid.three.position.y ?? 0])\r\n }\r\n if (grid.three.rotation) {\r\n const rotationDegrees = (grid.three.rotation.y * 180) / Math.PI\r\n setRotationZ([rotationDegrees ?? 0])\r\n }\r\n }\r\n\r\n setInitialized(true)\r\n }, [grid, initialized])\r\n\r\n // Update grid visibility when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentVisible = grid.config.visible ?? true\r\n if (currentVisible !== gridVisible) {\r\n grid.config.visible = gridVisible\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [gridVisible, grid, initialized, bimDispatch])\r\n\r\n // Update grid color when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentColor = grid.config.color ? `#${grid.config.color.getHexString()}` : '#bbbbbb'\r\n if (currentColor !== gridColor) {\r\n grid.config.color = new THREE.Color(gridColor)\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [gridColor, grid, initialized, bimDispatch])\r\n\r\n // Update grid primary size when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentPrimarySize = grid.config.primarySize ?? 1\r\n if (currentPrimarySize !== primarySize[0]) {\r\n grid.config.primarySize = primarySize[0]\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [primarySize, grid, initialized, bimDispatch])\r\n\r\n // Update grid secondary size when changed\r\n React.useEffect(() => {\r\n if (!grid?.config || !initialized) return\r\n\r\n const currentSecondarySize = grid.config.secondarySize ?? 10\r\n if (currentSecondarySize !== secondarySize[0]) {\r\n grid.config.secondarySize = secondarySize[0]\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [secondarySize, grid, initialized, bimDispatch])\r\n\r\n // Update grid elevation when changed\r\n React.useEffect(() => {\r\n if (!grid?.three?.position || !initialized) return\r\n\r\n const currentElevation = grid.three.position.y ?? 0\r\n if (currentElevation !== elevation[0]) {\r\n grid.three.position.y = elevation[0]\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [elevation, grid, initialized, bimDispatch])\r\n\r\n // Update grid rotation when changed\r\n React.useEffect(() => {\r\n if (!grid?.three?.rotation || !initialized) return\r\n\r\n const currentRotationDegrees = (grid.three.rotation.y * 180) / Math.PI\r\n if (Math.abs(currentRotationDegrees - rotationY[0]) > 0.001) { // Use small tolerance for floating point comparison\r\n grid.three.rotation.y = (rotationY[0] * Math.PI) / 180\r\n bimDispatch({\r\n type: 'SET_GRID',\r\n payload: { grid },\r\n })\r\n }\r\n }, [rotationY, grid, initialized, bimDispatch])\r\n\r\n return (\r\n <CollapsibleSection\r\n title={t('gridTitle')}\r\n chevronPosition=\"left\"\r\n switchVariant={{\r\n checked: gridVisible,\r\n onCheckedChange: setGridVisible,\r\n disabled: false,\r\n }}\r\n defaultOpen={false}\r\n >\r\n <div className=\"space-y-4\">\r\n {/* Grid Color */}\r\n <div className=\"space-y-2\">\r\n <label className={`text-sm font-medium ${gridVisible ? '' : 'text-gray-400'}`}>Grid Color</label>\r\n <div className={`p-2 border rounded-md ${gridVisible ? 'bg-white' : 'bg-gray-100'}`}>\r\n <ColorInput\r\n value={gridColor}\r\n onChange={e => setGridColor(e.target.value)}\r\n disabled={!gridVisible}\r\n defaultColor=\"#bbbbbb\"\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Grid Primary Size */}\r\n <SliderWithInput\r\n label={t('primaryLabel')}\r\n value={primarySize}\r\n onValueChange={setPrimarySize}\r\n min={0}\r\n max={10}\r\n step={0.1}\r\n disabled={!gridVisible}\r\n />\r\n\r\n {/* Grid Secondary Size */}\r\n <SliderWithInput\r\n label={t('secondaryLabel')}\r\n value={secondarySize}\r\n onValueChange={setSecondarySize}\r\n min={0}\r\n max={20}\r\n step={0.1}\r\n disabled={!gridVisible}\r\n />\r\n\r\n {/* Grid Elevation */}\r\n <SliderWithInput\r\n label={t('elevationLabel')}\r\n value={elevation}\r\n onValueChange={setElevation}\r\n min={-50}\r\n max={50}\r\n step={0.5}\r\n unit=\"m\"\r\n disabled={!gridVisible}\r\n />\r\n\r\n {/* Grid Rotation */}\r\n <SliderWithInput\r\n label={t('rotationLabel')}\r\n value={rotationY}\r\n onValueChange={setRotationZ}\r\n min={-360}\r\n max={360}\r\n step={1}\r\n unit=\"°\"\r\n disabled={!gridVisible}\r\n />\r\n </div>\r\n </CollapsibleSection>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IfcToFragments.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/bim/src/IfcToFragments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAA;AAG3C,qBAAa,cAAe,SAAQ,GAAG,CAAC,SAAS;IAC/C,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAG,sCAAsC,CAAS;IAEtE,OAAO,UAAO;IAGd,qBAAqB;mBAA8B,OAAO;iBAAW,MAAM;OAAK;IAEhF,OAAO,CAAC,UAAU,CAAiC;gBAEvC,UAAU,EAAE,GAAG,CAAC,UAAU;YAMxB,oBAAoB;
|
|
1
|
+
{"version":3,"file":"IfcToFragments.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/bim/src/IfcToFragments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAA;AAG3C,qBAAa,cAAe,SAAQ,GAAG,CAAC,SAAS;IAC/C,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAG,sCAAsC,CAAS;IAEtE,OAAO,UAAO;IAGd,qBAAqB;mBAA8B,OAAO;iBAAW,MAAM;OAAK;IAEhF,OAAO,CAAC,UAAU,CAAiC;gBAEvC,UAAU,EAAE,GAAG,CAAC,UAAU;YAMxB,oBAAoB;IAY5B,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;CAqCpD"}
|
|
@@ -13,7 +13,7 @@ const _IfcToFragments = class _IfcToFragments extends OBC.Component {
|
|
|
13
13
|
async initializeSerializer() {
|
|
14
14
|
try {
|
|
15
15
|
this.serializer = new FRAGS.IfcImporter();
|
|
16
|
-
this.serializer.wasm = { absolute: true, path: "https://unpkg.com/web-ifc@0.0.
|
|
16
|
+
this.serializer.wasm = { absolute: true, path: "https://unpkg.com/web-ifc@0.0.77/" };
|
|
17
17
|
} catch (error) {
|
|
18
18
|
console.warn("Could not initialize IFC serializer:", error);
|
|
19
19
|
this.serializer = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/components/viewers/bim/src/IfcToFragments.ts"],"sourcesContent":["import * as OBC from '@thatopen/components'\r\nimport * as FRAGS from '@thatopen/fragments'\r\n\r\nexport class IfcToFragments extends OBC.Component {\r\n static readonly uuid = 'ef6bd7b0-0903-4621-bc35-b0c7516576f9' as const\r\n\r\n enabled = true\r\n\r\n // Events for loading states\r\n onLoadingStateChanged = new OBC.Event<{ isLoading: boolean, message: string }>()\r\n\r\n private serializer: FRAGS.IfcImporter | null = null\r\n\r\n constructor(components: OBC.Components) {\r\n super(components)\r\n components.add(IfcToFragments.uuid, this)\r\n this.initializeSerializer()\r\n }\r\n\r\n private async initializeSerializer() {\r\n try {\r\n this.serializer = new FRAGS.IfcImporter()\r\n this.serializer.wasm = { absolute: true, path: 'https://unpkg.com/web-ifc@0.0.
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/bim/src/IfcToFragments.ts"],"sourcesContent":["import * as OBC from '@thatopen/components'\r\nimport * as FRAGS from '@thatopen/fragments'\r\n\r\nexport class IfcToFragments extends OBC.Component {\r\n static readonly uuid = 'ef6bd7b0-0903-4621-bc35-b0c7516576f9' as const\r\n\r\n enabled = true\r\n\r\n // Events for loading states\r\n onLoadingStateChanged = new OBC.Event<{ isLoading: boolean, message: string }>()\r\n\r\n private serializer: FRAGS.IfcImporter | null = null\r\n\r\n constructor(components: OBC.Components) {\r\n super(components)\r\n components.add(IfcToFragments.uuid, this)\r\n this.initializeSerializer()\r\n }\r\n\r\n private async initializeSerializer() {\r\n try {\r\n this.serializer = new FRAGS.IfcImporter()\r\n // ⚠️⚠️ IMPORTANT: keep this web-ifc version in sync with the `web-ifc` version\r\n this.serializer.wasm = { absolute: true, path: 'https://unpkg.com/web-ifc@0.0.77/' }\r\n }\r\n catch (error) {\r\n console.warn('Could not initialize IFC serializer:', error)\r\n this.serializer = null\r\n }\r\n }\r\n\r\n async loadFromFile(file: File): Promise<Uint8Array> {\r\n\r\n try {\r\n const fileBuffer = await file.arrayBuffer()\r\n\r\n // Handle only IFC files - convert to fragments first\r\n this.onLoadingStateChanged.trigger({ isLoading: true, message: 'Converting IFC to fragments...' })\r\n\r\n if (this.serializer) {\r\n const ifcBytes = new Uint8Array(fileBuffer)\r\n const fragmentBytes = await this.serializer.process({ bytes: ifcBytes })\r\n\r\n if (fragmentBytes) {\r\n // Update loading message\r\n this.onLoadingStateChanged.trigger({ isLoading: true, message: 'Loading BIM Model...' })\r\n\r\n // Convert Uint8Array to ArrayBuffer\r\n const fragmentBuffer = new ArrayBuffer(fragmentBytes.byteLength)\r\n // Return the bytes so the caller can upload a .frag file\r\n return fragmentBytes\r\n }\r\n else {\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n throw new Error('Failed to serialize IFC to fragments')\r\n }\r\n }\r\n else {\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n throw new Error('IFC serializer not available')\r\n }\r\n }\r\n catch (error) {\r\n // Make sure to clear loading state on error\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n throw new Error(`Error loading file: ${error}`)\r\n }\r\n }\r\n}\r\n"],"mappings":"AAAA,YAAY,SAAS;AACrB,YAAY,WAAW;AAEhB,MAAM,kBAAN,MAAM,wBAAuB,IAAI,UAAU;AAAA,EAUhD,YAAY,YAA4B;AACtC,UAAM,UAAU;AARlB,mBAAU;AAGV;AAAA,iCAAwB,IAAI,IAAI,MAA+C;AAE/E,SAAQ,aAAuC;AAI7C,eAAW,IAAI,gBAAe,MAAM,IAAI;AACxC,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEA,MAAc,uBAAuB;AACnC,QAAI;AACF,WAAK,aAAa,IAAI,MAAM,YAAY;AAExC,WAAK,WAAW,OAAO,EAAE,UAAU,MAAM,MAAM,oCAAoC;AAAA,IACrF,SACO,OAAO;AACZ,cAAQ,KAAK,wCAAwC,KAAK;AAC1D,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,MAAiC;AAElD,QAAI;AACF,YAAM,aAAa,MAAM,KAAK,YAAY;AAG1C,WAAK,sBAAsB,QAAQ,EAAE,WAAW,MAAM,SAAS,iCAAiC,CAAC;AAEjG,UAAI,KAAK,YAAY;AACnB,cAAM,WAAW,IAAI,WAAW,UAAU;AAC1C,cAAM,gBAAgB,MAAM,KAAK,WAAW,QAAQ,EAAE,OAAO,SAAS,CAAC;AAEvE,YAAI,eAAe;AAEjB,eAAK,sBAAsB,QAAQ,EAAE,WAAW,MAAM,SAAS,uBAAuB,CAAC;AAGvF,gBAAM,iBAAiB,IAAI,YAAY,cAAc,UAAU;AAE/D,iBAAO;AAAA,QACT,OACK;AACH,eAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AACpE,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QACxD;AAAA,MACF,OACK;AACH,aAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AACpE,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAAA,IACF,SACO,OAAO;AAEZ,WAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AACpE,YAAM,IAAI,MAAM,uBAAuB,KAAK,EAAE;AAAA,IAChD;AAAA,EACF;AACF;AAjEa,gBACK,OAAO;AADlB,IAAM,iBAAN;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadIfcAsFragments.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/bim/src/LoadIfcAsFragments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAA;AAK3C,qBAAa,kBAAmB,SAAQ,GAAG,CAAC,SAAS;IACnD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAG,sCAAsC,CAAS;IAEtE,OAAO,UAAO;IAGd,qBAAqB;mBAA8B,OAAO;iBAAW,MAAM;OAAK;IAEhF,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,UAAU,CAAiC;gBAEvC,UAAU,EAAE,GAAG,CAAC,UAAU;YASxB,oBAAoB;
|
|
1
|
+
{"version":3,"file":"LoadIfcAsFragments.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/bim/src/LoadIfcAsFragments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,sBAAsB,CAAA;AAK3C,qBAAa,kBAAmB,SAAQ,GAAG,CAAC,SAAS;IACnD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAG,sCAAsC,CAAS;IAEtE,OAAO,UAAO;IAGd,qBAAqB;mBAA8B,OAAO;iBAAW,MAAM;OAAK;IAEhF,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,UAAU,CAAiC;gBAEvC,UAAU,EAAE,GAAG,CAAC,UAAU;YASxB,oBAAoB;IAY5B,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CA+CrE"}
|
|
@@ -21,7 +21,7 @@ const _LoadIfcAsFragments = class _LoadIfcAsFragments extends OBC.Component {
|
|
|
21
21
|
async initializeSerializer() {
|
|
22
22
|
try {
|
|
23
23
|
this.serializer = new FRAGS.IfcImporter();
|
|
24
|
-
this.serializer.wasm = { absolute: true, path: "https://unpkg.com/web-ifc@0.0.
|
|
24
|
+
this.serializer.wasm = { absolute: true, path: "https://unpkg.com/web-ifc@0.0.77/" };
|
|
25
25
|
} catch (error) {
|
|
26
26
|
console.warn("Could not initialize IFC serializer:", error);
|
|
27
27
|
this.serializer = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/components/viewers/bim/src/LoadIfcAsFragments.ts"],"sourcesContent":["import * as OBC from '@thatopen/components'\r\nimport * as FRAGS from '@thatopen/fragments'\r\nimport { CurrentWorld } from './CurrentWorld'\r\nimport { LoadModels } from './LoadModels'\r\n\r\nexport class LoadIfcAsFragments extends OBC.Component {\r\n static readonly uuid = 'c1007187-c47b-47a5-8472-d2d06be83973' as const\r\n\r\n enabled = true\r\n\r\n // Events for loading states\r\n onLoadingStateChanged = new OBC.Event<{ isLoading: boolean, message: string }>()\r\n\r\n private world: OBC.World | null = null\r\n private fragments: OBC.FragmentsManager | null = null\r\n private loadModels: LoadModels | null = null\r\n private serializer: FRAGS.IfcImporter | null = null\r\n\r\n constructor(components: OBC.Components) {\r\n super(components)\r\n components.add(LoadIfcAsFragments.uuid, this)\r\n this.world = components.get(CurrentWorld).world\r\n this.fragments = components.get(OBC.FragmentsManager)\r\n this.loadModels = components.get(LoadModels)\r\n this.initializeSerializer()\r\n }\r\n\r\n private async initializeSerializer() {\r\n try {\r\n this.serializer = new FRAGS.IfcImporter()\r\n this.serializer.wasm = { absolute: true, path: 'https://unpkg.com/web-ifc@0.0.
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/bim/src/LoadIfcAsFragments.ts"],"sourcesContent":["import * as OBC from '@thatopen/components'\r\nimport * as FRAGS from '@thatopen/fragments'\r\nimport { CurrentWorld } from './CurrentWorld'\r\nimport { LoadModels } from './LoadModels'\r\n\r\nexport class LoadIfcAsFragments extends OBC.Component {\r\n static readonly uuid = 'c1007187-c47b-47a5-8472-d2d06be83973' as const\r\n\r\n enabled = true\r\n\r\n // Events for loading states\r\n onLoadingStateChanged = new OBC.Event<{ isLoading: boolean, message: string }>()\r\n\r\n private world: OBC.World | null = null\r\n private fragments: OBC.FragmentsManager | null = null\r\n private loadModels: LoadModels | null = null\r\n private serializer: FRAGS.IfcImporter | null = null\r\n\r\n constructor(components: OBC.Components) {\r\n super(components)\r\n components.add(LoadIfcAsFragments.uuid, this)\r\n this.world = components.get(CurrentWorld).world\r\n this.fragments = components.get(OBC.FragmentsManager)\r\n this.loadModels = components.get(LoadModels)\r\n this.initializeSerializer()\r\n }\r\n\r\n private async initializeSerializer() {\r\n try {\r\n this.serializer = new FRAGS.IfcImporter()\r\n // ⚠️⚠️ IMPORTANT: keep this web-ifc version in sync with the `web-ifc` version\r\n this.serializer.wasm = { absolute: true, path: 'https://unpkg.com/web-ifc@0.0.77/' }\r\n }\r\n catch (error) {\r\n console.warn('Could not initialize IFC serializer:', error)\r\n this.serializer = null\r\n }\r\n }\r\n\r\n async loadFromFile(file: File, modelId: string): Promise<Uint8Array> {\r\n if (!(this.fragments && this.world && this.loadModels)) {\r\n throw new Error('Missing required components.')\r\n }\r\n\r\n try {\r\n const fileBuffer = await file.arrayBuffer()\r\n\r\n // Handle only IFC files - convert to fragments first\r\n this.onLoadingStateChanged.trigger({ isLoading: true, message: 'Converting IFC to fragments...' })\r\n\r\n if (this.serializer) {\r\n const ifcBytes = new Uint8Array(fileBuffer)\r\n const fragmentBytes = await this.serializer.process({ bytes: ifcBytes })\r\n\r\n if (fragmentBytes) {\r\n // Update loading message\r\n this.onLoadingStateChanged.trigger({ isLoading: true, message: 'Loading BIM Model...' })\r\n\r\n // Convert Uint8Array to ArrayBuffer\r\n const fragmentBuffer = new ArrayBuffer(fragmentBytes.byteLength)\r\n new Uint8Array(fragmentBuffer).set(fragmentBytes)\r\n const model = await this.fragments.core.load(fragmentBuffer, { modelId })\r\n await this.loadModels.loadModel(model, modelId)\r\n\r\n // Conversion and loading complete\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n\r\n // Return the bytes so the caller can upload a .frag file\r\n return fragmentBytes\r\n }\r\n else {\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n throw new Error('Failed to serialize IFC to fragments')\r\n }\r\n }\r\n else {\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n throw new Error('IFC serializer not available')\r\n }\r\n }\r\n catch (error) {\r\n // Make sure to clear loading state on error\r\n this.onLoadingStateChanged.trigger({ isLoading: false, message: '' })\r\n throw new Error(`Error loading file: ${error}`)\r\n }\r\n }\r\n}\r\n"],"mappings":"AAAA,YAAY,SAAS;AACrB,YAAY,WAAW;AACvB,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAEpB,MAAM,sBAAN,MAAM,4BAA2B,IAAI,UAAU;AAAA,EAapD,YAAY,YAA4B;AACtC,UAAM,UAAU;AAXlB,mBAAU;AAGV;AAAA,iCAAwB,IAAI,IAAI,MAA+C;AAE/E,SAAQ,QAA0B;AAClC,SAAQ,YAAyC;AACjD,SAAQ,aAAgC;AACxC,SAAQ,aAAuC;AAI7C,eAAW,IAAI,oBAAmB,MAAM,IAAI;AAC5C,SAAK,QAAQ,WAAW,IAAI,YAAY,EAAE;AAC1C,SAAK,YAAY,WAAW,IAAI,IAAI,gBAAgB;AACpD,SAAK,aAAa,WAAW,IAAI,UAAU;AAC3C,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEA,MAAc,uBAAuB;AACnC,QAAI;AACF,WAAK,aAAa,IAAI,MAAM,YAAY;AAExC,WAAK,WAAW,OAAO,EAAE,UAAU,MAAM,MAAM,oCAAoC;AAAA,IACrF,SACO,OAAO;AACZ,cAAQ,KAAK,wCAAwC,KAAK;AAC1D,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,MAAY,SAAsC;AACnE,QAAI,EAAE,KAAK,aAAa,KAAK,SAAS,KAAK,aAAa;AACtD,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,QAAI;AACF,YAAM,aAAa,MAAM,KAAK,YAAY;AAG1C,WAAK,sBAAsB,QAAQ,EAAE,WAAW,MAAM,SAAS,iCAAiC,CAAC;AAEjG,UAAI,KAAK,YAAY;AACnB,cAAM,WAAW,IAAI,WAAW,UAAU;AAC1C,cAAM,gBAAgB,MAAM,KAAK,WAAW,QAAQ,EAAE,OAAO,SAAS,CAAC;AAEvE,YAAI,eAAe;AAEjB,eAAK,sBAAsB,QAAQ,EAAE,WAAW,MAAM,SAAS,uBAAuB,CAAC;AAGvF,gBAAM,iBAAiB,IAAI,YAAY,cAAc,UAAU;AAC/D,cAAI,WAAW,cAAc,EAAE,IAAI,aAAa;AAChD,gBAAM,QAAQ,MAAM,KAAK,UAAU,KAAK,KAAK,gBAAgB,EAAE,QAAQ,CAAC;AACxE,gBAAM,KAAK,WAAW,UAAU,OAAO,OAAO;AAG9C,eAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AAGpE,iBAAO;AAAA,QACT,OACK;AACH,eAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AACpE,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QACxD;AAAA,MACF,OACK;AACH,aAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AACpE,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAAA,IACF,SACO,OAAO;AAEZ,WAAK,sBAAsB,QAAQ,EAAE,WAAW,OAAO,SAAS,GAAG,CAAC;AACpE,YAAM,IAAI,MAAM,uBAAuB,KAAK,EAAE;AAAA,IAChD;AAAA,EACF;AACF;AAjFa,oBACK,OAAO;AADlB,IAAM,qBAAN;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BuildingsTools.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uCAAuC,CAAC;AAe9E,UAAU,kBAAkB;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,SAAS,EACT,OAAO,EACP,QAAQ,EACR,OAAO,EACP,aAAa,EACd,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"BuildingsTools.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uCAAuC,CAAC;AAe9E,UAAU,kBAAkB;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,SAAS,EACT,OAAO,EACP,QAAQ,EACR,OAAO,EACP,aAAa,EACd,EAAE,kBAAkB,qBA0WpB"}
|
|
@@ -114,14 +114,12 @@ function BuildingTools({
|
|
|
114
114
|
);
|
|
115
115
|
const bimFiles = React.useMemo(
|
|
116
116
|
() => buildingFiles.filter(
|
|
117
|
-
(file) => file.
|
|
117
|
+
(file) => file.type === "bim-file" || file.extension === "frag"
|
|
118
118
|
),
|
|
119
119
|
[buildingFiles]
|
|
120
120
|
);
|
|
121
121
|
const pcFiles = React.useMemo(
|
|
122
|
-
() => buildingFiles.filter(
|
|
123
|
-
(file) => file.name.toLowerCase().endsWith(".laz") || file.name.toLowerCase().endsWith(".las")
|
|
124
|
-
),
|
|
122
|
+
() => buildingFiles.filter((file) => file.type === "point-cloud-file" || ["laz", "las"].includes(file.extension || "")),
|
|
125
123
|
[buildingFiles]
|
|
126
124
|
);
|
|
127
125
|
const buildingButtons = React.useMemo(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React from \"react\";\r\nimport type { MapGeoJSONFeature } from \"maplibre-gl\";\r\nimport * as LR from \"lucide-react\";\r\nimport { useTranslations } from \"next-intl\";\r\nimport { usePermissions } from '../../../../../../../../store'\r\n\r\nimport { ViewerNames } from \"../../../../../../../../types/\";\r\nimport type { Tool } from \"../../../../../../../../types/tools\";\r\nimport type { Building, DbFile } from \"../../../../../../../../types/dbTypes\";\r\n\r\nimport { useFilesByBuildingId, useUploadFileToBuilding } from \"../../../../../../../../hooks/files/files\";\r\nimport { BuildingsContext, BimContext, MapContext, MenusContext, useMenusContext } from \"../../../../../../../../store\";\r\nimport { Button, Label, Skeleton, Switch, Checkbox } from \"../../../../../../../../components/ui/\";\r\nimport { useFileUploadHandler } from \"../../../../../../../../components/ui/FilesManager/src/useFileUploadHandler\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuTrigger,\r\n} from \"../../../../../../../../components/ui/DropdownMenu\";\r\nimport Compare from '../../../../compare';\r\nimport { toggleBimToMap as dispatchToggleBimToMap } from '../../../../../utils/toggleBimToMap';\r\n\r\ninterface BuildingToolsProps {\r\n isLoading: boolean;\r\n isError: boolean;\r\n building: Building | null;\r\n feature: MapGeoJSONFeature;\r\n onCloseAction: () => void;\r\n}\r\n\r\nexport default function BuildingTools({\r\n isLoading,\r\n isError,\r\n building,\r\n feature,\r\n onCloseAction\r\n}: BuildingToolsProps) {\r\n\r\n const t = useTranslations('BuildingTools')\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext);\r\n const { state: mapState, } = React.useContext(MapContext);\r\n const { dispatch: bimDispatch, state: bimState } = React.useContext(BimContext);\r\n const { bimModelsAddedToMap } = bimState.bim;\r\n const { dispatch: buildingsDispatch } = React.useContext(BuildingsContext);\r\n\r\n const fileInputRef = React.useRef<HTMLInputElement>(null);\r\n const { setView } = useMenusContext();\r\n const { setSelectedItem } = useMenusContext();\r\n\r\n const buildingId = React.useMemo(\r\n () => {\r\n\r\n const featureProps = feature?.properties || {};\r\n const id = Number(featureProps.dbId);\r\n return isNaN(id)\r\n ? null\r\n : id;\r\n\r\n },\r\n [feature?.properties],\r\n );\r\n\r\n const { files } = useFilesByBuildingId(buildingId);\r\n\r\n const bimAdded = React.useMemo(\r\n () => (buildingId\r\n ? mapState.map.bimModelsAddedToMap.includes(buildingId)\r\n : false),\r\n [\r\n mapState.map.bimModelsAddedToMap,\r\n buildingId,\r\n ],\r\n );\r\n\r\n const { uploadFile, isMutating: isUploadingFromHook } = useUploadFileToBuilding(building?.id || null);\r\n\r\n // Local state to track the entire upload process from file selection to completion\r\n const [\r\n isLocallyUploading,\r\n setIsLocallyUploading,\r\n ] = React.useState(false);\r\n\r\n // Combined uploading state\r\n const isUploading = isLocallyUploading || isUploadingFromHook;\r\n\r\n // Use the reusable upload handler without passing bimComponents\r\n const { handleFileUpload } = useFileUploadHandler({\r\n buildingId: buildingId || -1,\r\n uploadFile,\r\n onUploadStart: () => setIsLocallyUploading(true),\r\n onUploadEnd: () => setIsLocallyUploading(false),\r\n customMessages: {\r\n success: t('toastFIleUploadSuccess'),\r\n errorPrefix: t('toastFIleUploadError'),\r\n errorSuffix: t('toastUnknownError'),\r\n noIdError: t('buildingIdRequired')\r\n }\r\n });\r\n\r\n const changeViewer = React.useCallback(\r\n (viewer: ViewerNames) => {\r\n\r\n menusDispatch({\r\n type: \"SET_VIEWER\",\r\n payload: { \"currentViewer\": viewer },\r\n });\r\n\r\n buildingsDispatch({\r\n type: \"SET-CURRENT-BUILDING\",\r\n payload: { building },\r\n });\r\n onCloseAction();\r\n\r\n },\r\n [\r\n menusDispatch,\r\n buildingsDispatch,\r\n building,\r\n onCloseAction\r\n ]\r\n );\r\n\r\n const triggerFileInput = React.useCallback(\r\n () => {\r\n\r\n fileInputRef.current?.click();\r\n\r\n },\r\n [],\r\n );\r\n\r\n const toggleBimToMap = React.useCallback(\r\n (bimFile: DbFile) => {\r\n dispatchToggleBimToMap(bimDispatch, bimFile, building);\r\n\r\n },\r\n [\r\n building,\r\n bimDispatch\r\n ]\r\n );\r\n\r\n const onOpenBimViewer = () => {\r\n buildingsDispatch({type: \"SET-CURRENT-BUILDING\", payload: { building }});\r\n changeViewer(ViewerNames.bim);\r\n setSelectedItem(building);\r\n }\r\n\r\n const buildingFiles = React.useMemo(\r\n () => files || [],\r\n [files],\r\n );\r\n \r\n const bimFiles = React.useMemo(\r\n () => buildingFiles.filter((file: DbFile) => file.name.toLowerCase().endsWith(\".frag\")\r\n ),\r\n [buildingFiles],\r\n )\r\n\r\n const pcFiles = React.useMemo(\r\n () => buildingFiles.filter((file: DbFile) => file.name.toLowerCase().endsWith(\".laz\") ||\r\n file.name.toLowerCase().endsWith(\".las\")\r\n ),\r\n [buildingFiles],\r\n )\r\n\r\n const buildingButtons: Tool[] = React.useMemo(\r\n () => [\r\n {\r\n id: \"map-compare-buildings\",\r\n icon: LR.Columns3,\r\n title: t('compareTitle'),\r\n component: Compare,\r\n disabled: !ability.can('read', 'Building')\r\n },\r\n {\r\n id: \"open-building-page\",\r\n icon: LR.Building2,\r\n title: t('openBIMTitle'),\r\n onClick: () => {\r\n\r\n changeViewer(ViewerNames.buildings);\r\n setSelectedItem(building);\r\n setView(\"detail\");\r\n\r\n },\r\n disabled: !ability.can('read', 'Building')\r\n },\r\n {\r\n id: \"open-bim-viewer\",\r\n icon: LR.Box,\r\n title: t('OpenBIMViewerTitle'),\r\n onClick: onOpenBimViewer,\r\n disabled: !ability.can('read', 'File')\r\n },\r\n {\r\n id: 'open-pointcloud',\r\n title: t('openPointCloudTitle'),\r\n icon: LR.Grip,\r\n onClick: () => changeViewer(ViewerNames.pointcloud),\r\n disabled: pcFiles.length === 0 || !ability.can('read', 'File')\r\n },\r\n {\r\n id: \"map-add-file\",\r\n icon: isUploading\r\n ? LR.Loader\r\n : LR.FilePlus,\r\n title: t('addFileTitle'),\r\n onClick: triggerFileInput,\r\n disabled: !ability.can('create', 'File')\r\n },\r\n ],\r\n [\r\n changeViewer,\r\n building,\r\n setSelectedItem,\r\n setView,\r\n isUploading,\r\n triggerFileInput\r\n ]\r\n );\r\n\r\n const onLoadBIM = React.useCallback(\r\n (file: DbFile = null) => {\r\n if (bimFiles.length === 0) return;\r\n toggleBimToMap(bimFiles[0]);\r\n },\r\n [\r\n bimFiles,\r\n toggleBimToMap\r\n ]\r\n );\r\n\r\n const handleEditClick = (fileName: string) => {\r\n bimDispatch({\r\n type: \"EDIT_BIM_MODEL_BY_NAME\",\r\n payload: { editingBimModel: fileName }\r\n });\r\n\r\n onCloseAction();\r\n }\r\n\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n {/* Hidden file input */}\r\n <input\r\n onChange={(e) => handleFileUpload(e.target.files?.[0] || null)}\r\n ref={fileInputRef}\r\n style={{ \"display\": \"none\" }}\r\n type=\"file\"\r\n />\r\n\r\n {/* BIM Controls */}\r\n {!isError &&\r\n <div className=\"flex items-center space-x-2\">\r\n {isLoading\r\n ? <>\r\n <Skeleton className=\"h-4 w-20\" />\r\n\r\n <Skeleton className=\"h-6 w-10\" />\r\n </>\r\n : (\r\n <div className=\"flex items-center justify-between w-full\">\r\n {bimFiles.length > 1 ? (\r\n <div className=\"flex items-center space-x-2\">\r\n <Label className=\"font-semibold\" htmlFor=\"bim-file-dropdown\">\r\n {t('selectBimLabel')}\r\n </Label>\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button variant=\"outline\" size=\"sm\" id=\"bim-file-dropdown\">\r\n {bimModelsAddedToMap.length > 0\r\n ? `${bimModelsAddedToMap.filter(model => model.bimFile.attachedFilesBuildingId === buildingId).length} ${t('filesSelected')}`\r\n : t('selectFiles')\r\n }\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent>\r\n {bimFiles.map((file: DbFile) => {\r\n const isSelected = bimModelsAddedToMap.some(model => model.bimFile.name === file.name);\r\n return (\r\n <DropdownMenuItem\r\n key={file.name}\r\n onClick={(e) => {\r\n e.preventDefault();\r\n toggleBimToMap(file);\r\n }}\r\n className=\"flex items-center justify-between cursor-pointer\"\r\n >\r\n <div className=\"flex items-center space-x-2\">\r\n <Checkbox\r\n checked={isSelected}\r\n onClick={(e) => e.stopPropagation()}\r\n onCheckedChange={() => {\r\n toggleBimToMap(file);\r\n }}\r\n />\r\n <span>{file.name}</span>\r\n </div>\r\n {isSelected && (\r\n <Button \r\n onClick={(e) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n handleEditClick(file.name);\r\n }} \r\n variant=\"ghost\" \r\n size=\"sm\"\r\n className=\"h-6 w-6 p-0\"\r\n title={t('editBimButton')}\r\n >\r\n <LR.LocationEdit className=\"h-3 w-3\" />\r\n </Button>\r\n )}\r\n </DropdownMenuItem>\r\n );\r\n })}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n </div>\r\n ) : (\r\n <div className=\"flex items-center space-x-2\">\r\n <Label\r\n className={`font-semibold ${bimFiles.length === 0 ? 'text-muted-foreground' : ''}`}\r\n htmlFor=\"show-bim\"\r\n >\r\n {bimAdded ? t('hideBIM') : t('showBIM')}\r\n </Label>\r\n <Switch\r\n id=\"show-bim\"\r\n checked={bimFiles.length === 1 && bimModelsAddedToMap.some(model => model.bimFile.name === bimFiles[0]?.name)}\r\n disabled={bimFiles.length === 0 || !ability.can('read', 'File')}\r\n onCheckedChange={() => onLoadBIM()}\r\n />\r\n </div>\r\n )}\r\n {bimFiles.length === 1 && bimModelsAddedToMap.some(model => model.building.id === buildingId) && (() => {\r\n const selectedModel = bimModelsAddedToMap.find(model => model.building.id === buildingId);\r\n console.log('selectedModel', selectedModel);\r\n return true ? (\r\n <Button \r\n onClick={() => handleEditClick(selectedModel.bimFile.name)} \r\n variant=\"ghost\" \r\n size=\"sm\"\r\n title={t('editBimButton')}\r\n disabled={!ability.can('update', 'File')}\r\n >\r\n <LR.LocationEdit className=\"h-4 w-4\" />\r\n </Button>\r\n ) : null;\r\n })()}\r\n </div>\r\n ) \r\n }\r\n </div>}\r\n\r\n {/* Tool Buttons */}\r\n <div className=\"flex items-center gap-3\">\r\n {isLoading\r\n ? Array.from({ \"length\": 4 }).map((_, index) => (<Skeleton\r\n key={index}\r\n className=\"w-8 h-8 rounded-sm\"\r\n />),)\r\n : (!isError && building ? (\r\n buildingButtons.map((button) => {\r\n if (button.component) {\r\n const ButtonComponent = button.component\r\n const shouldAnimateSpin = button.id === 'map-add-file' && isUploading\r\n return (\r\n <div\r\n key={button.id}\r\n className={`w-8 h-8 rounded-sm border-2 border-gray-200 inline-flex justify-center items-center ${shouldAnimateSpin ? 'animate-spin' : ''}`}\r\n >\r\n <ButtonComponent tool={button} building={building} />\r\n </div>\r\n )\r\n }\r\n return (\r\n <Button\r\n key={button.id}\r\n variant=\"ghost\"\r\n className=\"w-8 h-8 rounded-sm border-2 border-gray-200 inline-flex justify-center items-center\"\r\n aria-label={button.title}\r\n onClick={button.onClick}\r\n title={button.title}\r\n disabled={button.disabled}\r\n >\r\n <button.icon className={`w-6 h-6 ${button.id === 'map-add-file' && isUploading ? 'animate-spin' : ''}`} />\r\n </Button>\r\n )\r\n })\r\n ) : null)}\r\n </div>\r\n </div>\r\n );\r\n\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React from \"react\";\r\nimport type { MapGeoJSONFeature } from \"maplibre-gl\";\r\nimport * as LR from \"lucide-react\";\r\nimport { useTranslations } from \"next-intl\";\r\nimport { usePermissions } from '../../../../../../../../store'\r\n\r\nimport { ViewerNames } from \"../../../../../../../../types/\";\r\nimport type { Tool } from \"../../../../../../../../types/tools\";\r\nimport type { Building, DbFile } from \"../../../../../../../../types/dbTypes\";\r\n\r\nimport { useFilesByBuildingId, useUploadFileToBuilding } from \"../../../../../../../../hooks/files/files\";\r\nimport { BuildingsContext, BimContext, MapContext, MenusContext, useMenusContext } from \"../../../../../../../../store\";\r\nimport { Button, Label, Skeleton, Switch, Checkbox } from \"../../../../../../../../components/ui/\";\r\nimport { useFileUploadHandler } from \"../../../../../../../../components/ui/FilesManager/src/useFileUploadHandler\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuTrigger,\r\n} from \"../../../../../../../../components/ui/DropdownMenu\";\r\nimport Compare from '../../../../compare';\r\nimport { toggleBimToMap as dispatchToggleBimToMap } from '../../../../../utils/toggleBimToMap';\r\n\r\ninterface BuildingToolsProps {\r\n isLoading: boolean;\r\n isError: boolean;\r\n building: Building | null;\r\n feature: MapGeoJSONFeature;\r\n onCloseAction: () => void;\r\n}\r\n\r\nexport default function BuildingTools({\r\n isLoading,\r\n isError,\r\n building,\r\n feature,\r\n onCloseAction\r\n}: BuildingToolsProps) {\r\n\r\n const t = useTranslations('BuildingTools')\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext);\r\n const { state: mapState, } = React.useContext(MapContext);\r\n const { dispatch: bimDispatch, state: bimState } = React.useContext(BimContext);\r\n const { bimModelsAddedToMap } = bimState.bim;\r\n const { dispatch: buildingsDispatch } = React.useContext(BuildingsContext);\r\n\r\n const fileInputRef = React.useRef<HTMLInputElement>(null);\r\n const { setView } = useMenusContext();\r\n const { setSelectedItem } = useMenusContext();\r\n\r\n const buildingId = React.useMemo(\r\n () => {\r\n\r\n const featureProps = feature?.properties || {};\r\n const id = Number(featureProps.dbId);\r\n return isNaN(id)\r\n ? null\r\n : id;\r\n\r\n },\r\n [feature?.properties],\r\n );\r\n\r\n const { files } = useFilesByBuildingId(buildingId);\r\n\r\n const bimAdded = React.useMemo(\r\n () => (buildingId\r\n ? mapState.map.bimModelsAddedToMap.includes(buildingId)\r\n : false),\r\n [\r\n mapState.map.bimModelsAddedToMap,\r\n buildingId,\r\n ],\r\n );\r\n\r\n const { uploadFile, isMutating: isUploadingFromHook } = useUploadFileToBuilding(building?.id || null);\r\n\r\n // Local state to track the entire upload process from file selection to completion\r\n const [\r\n isLocallyUploading,\r\n setIsLocallyUploading,\r\n ] = React.useState(false);\r\n\r\n // Combined uploading state\r\n const isUploading = isLocallyUploading || isUploadingFromHook;\r\n\r\n // Use the reusable upload handler without passing bimComponents\r\n const { handleFileUpload } = useFileUploadHandler({\r\n buildingId: buildingId || -1,\r\n uploadFile,\r\n onUploadStart: () => setIsLocallyUploading(true),\r\n onUploadEnd: () => setIsLocallyUploading(false),\r\n customMessages: {\r\n success: t('toastFIleUploadSuccess'),\r\n errorPrefix: t('toastFIleUploadError'),\r\n errorSuffix: t('toastUnknownError'),\r\n noIdError: t('buildingIdRequired')\r\n }\r\n });\r\n\r\n const changeViewer = React.useCallback(\r\n (viewer: ViewerNames) => {\r\n\r\n menusDispatch({\r\n type: \"SET_VIEWER\",\r\n payload: { \"currentViewer\": viewer },\r\n });\r\n\r\n buildingsDispatch({\r\n type: \"SET-CURRENT-BUILDING\",\r\n payload: { building },\r\n });\r\n onCloseAction();\r\n\r\n },\r\n [\r\n menusDispatch,\r\n buildingsDispatch,\r\n building,\r\n onCloseAction\r\n ]\r\n );\r\n\r\n const triggerFileInput = React.useCallback(\r\n () => {\r\n\r\n fileInputRef.current?.click();\r\n\r\n },\r\n [],\r\n );\r\n\r\n const toggleBimToMap = React.useCallback(\r\n (bimFile: DbFile) => {\r\n dispatchToggleBimToMap(bimDispatch, bimFile, building);\r\n\r\n },\r\n [\r\n building,\r\n bimDispatch\r\n ]\r\n );\r\n\r\n const onOpenBimViewer = () => {\r\n buildingsDispatch({ type: \"SET-CURRENT-BUILDING\", payload: { building } });\r\n changeViewer(ViewerNames.bim);\r\n setSelectedItem(building);\r\n }\r\n\r\n const buildingFiles = React.useMemo(\r\n () => files || [],\r\n [files],\r\n );\r\n\r\n const bimFiles = React.useMemo(\r\n () => buildingFiles.filter((file: DbFile) => file.type === \"bim-file\" || file.extension === \"frag\"\r\n ),\r\n [buildingFiles],\r\n )\r\n\r\n const pcFiles = React.useMemo(\r\n () => buildingFiles.filter((file: DbFile) => file.type === 'point-cloud-file' || ['laz', 'las'].includes(file.extension || '')),\r\n [buildingFiles],\r\n )\r\n\r\n const buildingButtons: Tool[] = React.useMemo(\r\n () => [\r\n {\r\n id: \"map-compare-buildings\",\r\n icon: LR.Columns3,\r\n title: t('compareTitle'),\r\n component: Compare,\r\n disabled: !ability.can('read', 'Building')\r\n },\r\n {\r\n id: \"open-building-page\",\r\n icon: LR.Building2,\r\n title: t('openBIMTitle'),\r\n onClick: () => {\r\n\r\n changeViewer(ViewerNames.buildings);\r\n setSelectedItem(building);\r\n setView(\"detail\");\r\n\r\n },\r\n disabled: !ability.can('read', 'Building')\r\n },\r\n {\r\n id: \"open-bim-viewer\",\r\n icon: LR.Box,\r\n title: t('OpenBIMViewerTitle'),\r\n onClick: onOpenBimViewer,\r\n disabled: !ability.can('read', 'File')\r\n },\r\n {\r\n id: 'open-pointcloud',\r\n title: t('openPointCloudTitle'),\r\n icon: LR.Grip,\r\n onClick: () => changeViewer(ViewerNames.pointcloud),\r\n disabled: pcFiles.length === 0 || !ability.can('read', 'File')\r\n },\r\n {\r\n id: \"map-add-file\",\r\n icon: isUploading\r\n ? LR.Loader\r\n : LR.FilePlus,\r\n title: t('addFileTitle'),\r\n onClick: triggerFileInput,\r\n disabled: !ability.can('create', 'File')\r\n },\r\n ],\r\n [\r\n changeViewer,\r\n building,\r\n setSelectedItem,\r\n setView,\r\n isUploading,\r\n triggerFileInput\r\n ]\r\n );\r\n\r\n const onLoadBIM = React.useCallback(\r\n (file: DbFile = null) => {\r\n if (bimFiles.length === 0) return;\r\n toggleBimToMap(bimFiles[0]);\r\n },\r\n [\r\n bimFiles,\r\n toggleBimToMap\r\n ]\r\n );\r\n\r\n const handleEditClick = (fileName: string) => {\r\n bimDispatch({\r\n type: \"EDIT_BIM_MODEL_BY_NAME\",\r\n payload: { editingBimModel: fileName }\r\n });\r\n\r\n onCloseAction();\r\n }\r\n\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n {/* Hidden file input */}\r\n <input\r\n onChange={(e) => handleFileUpload(e.target.files?.[0] || null)}\r\n ref={fileInputRef}\r\n style={{ \"display\": \"none\" }}\r\n type=\"file\"\r\n />\r\n\r\n {/* BIM Controls */}\r\n {!isError &&\r\n <div className=\"flex items-center space-x-2\">\r\n {isLoading\r\n ? <>\r\n <Skeleton className=\"h-4 w-20\" />\r\n\r\n <Skeleton className=\"h-6 w-10\" />\r\n </>\r\n : (\r\n <div className=\"flex items-center justify-between w-full\">\r\n {bimFiles.length > 1 ? (\r\n <div className=\"flex items-center space-x-2\">\r\n <Label className=\"font-semibold\" htmlFor=\"bim-file-dropdown\">\r\n {t('selectBimLabel')}\r\n </Label>\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button variant=\"outline\" size=\"sm\" id=\"bim-file-dropdown\">\r\n {bimModelsAddedToMap.length > 0\r\n ? `${bimModelsAddedToMap.filter(model => model.bimFile.attachedFilesBuildingId === buildingId).length} ${t('filesSelected')}`\r\n : t('selectFiles')\r\n }\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent>\r\n {bimFiles.map((file: DbFile) => {\r\n const isSelected = bimModelsAddedToMap.some(model => model.bimFile.name === file.name);\r\n return (\r\n <DropdownMenuItem\r\n key={file.name}\r\n onClick={(e) => {\r\n e.preventDefault();\r\n toggleBimToMap(file);\r\n }}\r\n className=\"flex items-center justify-between cursor-pointer\"\r\n >\r\n <div className=\"flex items-center space-x-2\">\r\n <Checkbox\r\n checked={isSelected}\r\n onClick={(e) => e.stopPropagation()}\r\n onCheckedChange={() => {\r\n toggleBimToMap(file);\r\n }}\r\n />\r\n <span>{file.name}</span>\r\n </div>\r\n {isSelected && (\r\n <Button\r\n onClick={(e) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n handleEditClick(file.name);\r\n }}\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className=\"h-6 w-6 p-0\"\r\n title={t('editBimButton')}\r\n >\r\n <LR.LocationEdit className=\"h-3 w-3\" />\r\n </Button>\r\n )}\r\n </DropdownMenuItem>\r\n );\r\n })}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n </div>\r\n ) : (\r\n <div className=\"flex items-center space-x-2\">\r\n <Label\r\n className={`font-semibold ${bimFiles.length === 0 ? 'text-muted-foreground' : ''}`}\r\n htmlFor=\"show-bim\"\r\n >\r\n {bimAdded ? t('hideBIM') : t('showBIM')}\r\n </Label>\r\n <Switch\r\n id=\"show-bim\"\r\n checked={bimFiles.length === 1 && bimModelsAddedToMap.some(model => model.bimFile.name === bimFiles[0]?.name)}\r\n disabled={bimFiles.length === 0 || !ability.can('read', 'File')}\r\n onCheckedChange={() => onLoadBIM()}\r\n />\r\n </div>\r\n )}\r\n {bimFiles.length === 1 && bimModelsAddedToMap.some(model => model.building.id === buildingId) && (() => {\r\n const selectedModel = bimModelsAddedToMap.find(model => model.building.id === buildingId);\r\n console.log('selectedModel', selectedModel);\r\n return true ? (\r\n <Button\r\n onClick={() => handleEditClick(selectedModel.bimFile.name)}\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n title={t('editBimButton')}\r\n disabled={!ability.can('update', 'File')}\r\n >\r\n <LR.LocationEdit className=\"h-4 w-4\" />\r\n </Button>\r\n ) : null;\r\n })()}\r\n </div>\r\n )\r\n }\r\n </div>}\r\n\r\n {/* Tool Buttons */}\r\n <div className=\"flex items-center gap-3\">\r\n {isLoading\r\n ? Array.from({ \"length\": 4 }).map((_, index) => (<Skeleton\r\n key={index}\r\n className=\"w-8 h-8 rounded-sm\"\r\n />),)\r\n : (!isError && building ? (\r\n buildingButtons.map((button) => {\r\n if (button.component) {\r\n const ButtonComponent = button.component\r\n const shouldAnimateSpin = button.id === 'map-add-file' && isUploading\r\n return (\r\n <div\r\n key={button.id}\r\n className={`w-8 h-8 rounded-sm border-2 border-gray-200 inline-flex justify-center items-center ${shouldAnimateSpin ? 'animate-spin' : ''}`}\r\n >\r\n <ButtonComponent tool={button} building={building} />\r\n </div>\r\n )\r\n }\r\n return (\r\n <Button\r\n key={button.id}\r\n variant=\"ghost\"\r\n className=\"w-8 h-8 rounded-sm border-2 border-gray-200 inline-flex justify-center items-center\"\r\n aria-label={button.title}\r\n onClick={button.onClick}\r\n title={button.title}\r\n disabled={button.disabled}\r\n >\r\n <button.icon className={`w-6 h-6 ${button.id === 'map-add-file' && isUploading ? 'animate-spin' : ''}`} />\r\n </Button>\r\n )\r\n })\r\n ) : null)}\r\n </div>\r\n </div>\r\n );\r\n\r\n}\r\n"],"mappings":"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","names":[]}
|