@ifc-lite/viewer 1.17.3 → 1.17.6
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/.turbo/turbo-build.log +39 -30
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +132 -0
- package/DESKTOP_CONTRACT_VERSION +1 -0
- package/dist/assets/arrow-CZ5kQ26f.js +20 -0
- package/dist/assets/basketViewActivator-86rgogji.js +1 -0
- package/dist/assets/{bcf-D5-QWGO9.js → bcf-DOG9_WPX.js} +1 -1
- package/dist/assets/{browser-CKs-FY1P.js → browser-C5TFR7sH.js} +1 -1
- package/dist/assets/cesium-ADbP7waU.css +1 -0
- package/dist/assets/cesium-DUOzBlqv.js +17817 -0
- package/dist/assets/drawing-2d-DoxKMqbO.js +257 -0
- package/dist/assets/{exporters-C_6J153K.js → exporters-CcPS9MK5.js} +2898 -2380
- package/dist/assets/geometry.worker-BFUYA08u.js +1 -0
- package/dist/assets/ids-DQ5jY0E8.js +1 -0
- package/dist/assets/ifc-lite_bg-BINvzoCP.wasm +0 -0
- package/dist/assets/{index-jhBr1wbn.js → index-Bfms9I4A.js} +41036 -34613
- package/dist/assets/index-_bfZsDCC.css +1 -0
- package/dist/assets/{maplibre-gl-BpvwNKKy.js → maplibre-gl-CGLcoNXc.js} +1 -1
- package/dist/assets/native-bridge-DUyLCMZS.js +429 -0
- package/dist/assets/{sandbox-B79eavQ3.js → sandbox-C8575tul.js} +4342 -4324
- package/dist/assets/{server-client-D3bUPJJc.js → server-client-BuZK7OST.js} +4 -4
- package/dist/assets/tauri-core-stub-D8Fa-u43.js +1 -0
- package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +1 -0
- package/dist/assets/tauri-fs-stub-BdeRC7aK.js +1 -0
- package/dist/assets/wasm-bridge-JsqEGDV8.js +1 -0
- package/dist/assets/{zip-B-jFFAGa.js → zip-DBEtpeu6.js} +3 -3
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_0.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_1.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_10.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_11.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_12.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_13.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_14.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_15.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_16.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_17.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_18.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_19.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_2.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_20.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_21.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_22.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_23.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_24.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_25.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_26.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_27.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_3.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_4.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_5.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_6.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_7.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_8.json +1 -0
- package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_9.json +1 -0
- package/dist/cesium/Assets/Images/bing_maps_credit.png +0 -0
- package/dist/cesium/Assets/Images/cesium_credit.png +0 -0
- package/dist/cesium/Assets/Images/google_earth_credit.png +0 -0
- package/dist/cesium/Assets/Images/ion-credit.png +0 -0
- package/dist/cesium/Assets/Textures/LensFlare/DirtMask.jpg +0 -0
- package/dist/cesium/Assets/Textures/LensFlare/StarBurst.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/0/0/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/0/1/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/0.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/1.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/2.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/3.jpg +0 -0
- package/dist/cesium/Assets/Textures/NaturalEarthII/tilemapresource.xml +14 -0
- package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
- package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
- package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
- package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
- package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
- package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
- package/dist/cesium/Assets/Textures/maki/airfield.png +0 -0
- package/dist/cesium/Assets/Textures/maki/airport.png +0 -0
- package/dist/cesium/Assets/Textures/maki/alcohol-shop.png +0 -0
- package/dist/cesium/Assets/Textures/maki/america-football.png +0 -0
- package/dist/cesium/Assets/Textures/maki/art-gallery.png +0 -0
- package/dist/cesium/Assets/Textures/maki/bakery.png +0 -0
- package/dist/cesium/Assets/Textures/maki/bank.png +0 -0
- package/dist/cesium/Assets/Textures/maki/bar.png +0 -0
- package/dist/cesium/Assets/Textures/maki/baseball.png +0 -0
- package/dist/cesium/Assets/Textures/maki/basketball.png +0 -0
- package/dist/cesium/Assets/Textures/maki/beer.png +0 -0
- package/dist/cesium/Assets/Textures/maki/bicycle.png +0 -0
- package/dist/cesium/Assets/Textures/maki/building.png +0 -0
- package/dist/cesium/Assets/Textures/maki/bus.png +0 -0
- package/dist/cesium/Assets/Textures/maki/cafe.png +0 -0
- package/dist/cesium/Assets/Textures/maki/camera.png +0 -0
- package/dist/cesium/Assets/Textures/maki/campsite.png +0 -0
- package/dist/cesium/Assets/Textures/maki/car.png +0 -0
- package/dist/cesium/Assets/Textures/maki/cemetery.png +0 -0
- package/dist/cesium/Assets/Textures/maki/cesium.png +0 -0
- package/dist/cesium/Assets/Textures/maki/chemist.png +0 -0
- package/dist/cesium/Assets/Textures/maki/cinema.png +0 -0
- package/dist/cesium/Assets/Textures/maki/circle-stroked.png +0 -0
- package/dist/cesium/Assets/Textures/maki/circle.png +0 -0
- package/dist/cesium/Assets/Textures/maki/city.png +0 -0
- package/dist/cesium/Assets/Textures/maki/clothing-store.png +0 -0
- package/dist/cesium/Assets/Textures/maki/college.png +0 -0
- package/dist/cesium/Assets/Textures/maki/commercial.png +0 -0
- package/dist/cesium/Assets/Textures/maki/cricket.png +0 -0
- package/dist/cesium/Assets/Textures/maki/cross.png +0 -0
- package/dist/cesium/Assets/Textures/maki/dam.png +0 -0
- package/dist/cesium/Assets/Textures/maki/danger.png +0 -0
- package/dist/cesium/Assets/Textures/maki/disability.png +0 -0
- package/dist/cesium/Assets/Textures/maki/dog-park.png +0 -0
- package/dist/cesium/Assets/Textures/maki/embassy.png +0 -0
- package/dist/cesium/Assets/Textures/maki/emergency-telephone.png +0 -0
- package/dist/cesium/Assets/Textures/maki/entrance.png +0 -0
- package/dist/cesium/Assets/Textures/maki/farm.png +0 -0
- package/dist/cesium/Assets/Textures/maki/fast-food.png +0 -0
- package/dist/cesium/Assets/Textures/maki/ferry.png +0 -0
- package/dist/cesium/Assets/Textures/maki/fire-station.png +0 -0
- package/dist/cesium/Assets/Textures/maki/fuel.png +0 -0
- package/dist/cesium/Assets/Textures/maki/garden.png +0 -0
- package/dist/cesium/Assets/Textures/maki/gift.png +0 -0
- package/dist/cesium/Assets/Textures/maki/golf.png +0 -0
- package/dist/cesium/Assets/Textures/maki/grocery.png +0 -0
- package/dist/cesium/Assets/Textures/maki/hairdresser.png +0 -0
- package/dist/cesium/Assets/Textures/maki/harbor.png +0 -0
- package/dist/cesium/Assets/Textures/maki/heart.png +0 -0
- package/dist/cesium/Assets/Textures/maki/heliport.png +0 -0
- package/dist/cesium/Assets/Textures/maki/hospital.png +0 -0
- package/dist/cesium/Assets/Textures/maki/ice-cream.png +0 -0
- package/dist/cesium/Assets/Textures/maki/industrial.png +0 -0
- package/dist/cesium/Assets/Textures/maki/land-use.png +0 -0
- package/dist/cesium/Assets/Textures/maki/laundry.png +0 -0
- package/dist/cesium/Assets/Textures/maki/library.png +0 -0
- package/dist/cesium/Assets/Textures/maki/lighthouse.png +0 -0
- package/dist/cesium/Assets/Textures/maki/lodging.png +0 -0
- package/dist/cesium/Assets/Textures/maki/logging.png +0 -0
- package/dist/cesium/Assets/Textures/maki/london-underground.png +0 -0
- package/dist/cesium/Assets/Textures/maki/marker-stroked.png +0 -0
- package/dist/cesium/Assets/Textures/maki/marker.png +0 -0
- package/dist/cesium/Assets/Textures/maki/minefield.png +0 -0
- package/dist/cesium/Assets/Textures/maki/mobilephone.png +0 -0
- package/dist/cesium/Assets/Textures/maki/monument.png +0 -0
- package/dist/cesium/Assets/Textures/maki/museum.png +0 -0
- package/dist/cesium/Assets/Textures/maki/music.png +0 -0
- package/dist/cesium/Assets/Textures/maki/oil-well.png +0 -0
- package/dist/cesium/Assets/Textures/maki/park.png +0 -0
- package/dist/cesium/Assets/Textures/maki/park2.png +0 -0
- package/dist/cesium/Assets/Textures/maki/parking-garage.png +0 -0
- package/dist/cesium/Assets/Textures/maki/parking.png +0 -0
- package/dist/cesium/Assets/Textures/maki/pharmacy.png +0 -0
- package/dist/cesium/Assets/Textures/maki/pitch.png +0 -0
- package/dist/cesium/Assets/Textures/maki/place-of-worship.png +0 -0
- package/dist/cesium/Assets/Textures/maki/playground.png +0 -0
- package/dist/cesium/Assets/Textures/maki/police.png +0 -0
- package/dist/cesium/Assets/Textures/maki/polling-place.png +0 -0
- package/dist/cesium/Assets/Textures/maki/post.png +0 -0
- package/dist/cesium/Assets/Textures/maki/prison.png +0 -0
- package/dist/cesium/Assets/Textures/maki/rail-above.png +0 -0
- package/dist/cesium/Assets/Textures/maki/rail-light.png +0 -0
- package/dist/cesium/Assets/Textures/maki/rail-metro.png +0 -0
- package/dist/cesium/Assets/Textures/maki/rail-underground.png +0 -0
- package/dist/cesium/Assets/Textures/maki/rail.png +0 -0
- package/dist/cesium/Assets/Textures/maki/religious-christian.png +0 -0
- package/dist/cesium/Assets/Textures/maki/religious-jewish.png +0 -0
- package/dist/cesium/Assets/Textures/maki/religious-muslim.png +0 -0
- package/dist/cesium/Assets/Textures/maki/restaurant.png +0 -0
- package/dist/cesium/Assets/Textures/maki/roadblock.png +0 -0
- package/dist/cesium/Assets/Textures/maki/rocket.png +0 -0
- package/dist/cesium/Assets/Textures/maki/school.png +0 -0
- package/dist/cesium/Assets/Textures/maki/scooter.png +0 -0
- package/dist/cesium/Assets/Textures/maki/shop.png +0 -0
- package/dist/cesium/Assets/Textures/maki/skiing.png +0 -0
- package/dist/cesium/Assets/Textures/maki/slaughterhouse.png +0 -0
- package/dist/cesium/Assets/Textures/maki/soccer.png +0 -0
- package/dist/cesium/Assets/Textures/maki/square-stroked.png +0 -0
- package/dist/cesium/Assets/Textures/maki/square.png +0 -0
- package/dist/cesium/Assets/Textures/maki/star-stroked.png +0 -0
- package/dist/cesium/Assets/Textures/maki/star.png +0 -0
- package/dist/cesium/Assets/Textures/maki/suitcase.png +0 -0
- package/dist/cesium/Assets/Textures/maki/swimming.png +0 -0
- package/dist/cesium/Assets/Textures/maki/telephone.png +0 -0
- package/dist/cesium/Assets/Textures/maki/tennis.png +0 -0
- package/dist/cesium/Assets/Textures/maki/theatre.png +0 -0
- package/dist/cesium/Assets/Textures/maki/toilets.png +0 -0
- package/dist/cesium/Assets/Textures/maki/town-hall.png +0 -0
- package/dist/cesium/Assets/Textures/maki/town.png +0 -0
- package/dist/cesium/Assets/Textures/maki/triangle-stroked.png +0 -0
- package/dist/cesium/Assets/Textures/maki/triangle.png +0 -0
- package/dist/cesium/Assets/Textures/maki/village.png +0 -0
- package/dist/cesium/Assets/Textures/maki/warehouse.png +0 -0
- package/dist/cesium/Assets/Textures/maki/waste-basket.png +0 -0
- package/dist/cesium/Assets/Textures/maki/water.png +0 -0
- package/dist/cesium/Assets/Textures/maki/wetland.png +0 -0
- package/dist/cesium/Assets/Textures/maki/zoo.png +0 -0
- package/dist/cesium/Assets/Textures/moonSmall.jpg +0 -0
- package/dist/cesium/Assets/Textures/pin.svg +1 -0
- package/dist/cesium/Assets/Textures/waterNormals.jpg +0 -0
- package/dist/cesium/Assets/Textures/waterNormalsSmall.jpg +0 -0
- package/dist/cesium/Assets/approximateTerrainHeights.json +1 -0
- package/dist/cesium/ThirdParty/Workers/package.json +1 -0
- package/dist/cesium/ThirdParty/Workers/zip-web-worker.js +1 -0
- package/dist/cesium/ThirdParty/basis_transcoder.wasm +0 -0
- package/dist/cesium/ThirdParty/draco_decoder.wasm +0 -0
- package/dist/cesium/ThirdParty/google-earth-dbroot-parser.js +1 -0
- package/dist/cesium/ThirdParty/wasm_splats_bg.wasm +0 -0
- package/dist/cesium/ThirdParty/zip-module.wasm +0 -0
- package/dist/cesium/Widgets/Animation/Animation.css +127 -0
- package/dist/cesium/Widgets/Animation/lighter.css +70 -0
- package/dist/cesium/Widgets/BaseLayerPicker/BaseLayerPicker.css +108 -0
- package/dist/cesium/Widgets/BaseLayerPicker/lighter.css +22 -0
- package/dist/cesium/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspector.css +102 -0
- package/dist/cesium/Widgets/CesiumInspector/CesiumInspector.css +113 -0
- package/dist/cesium/Widgets/CesiumWidget/CesiumWidget.css +119 -0
- package/dist/cesium/Widgets/CesiumWidget/lighter.css +14 -0
- package/dist/cesium/Widgets/FullscreenButton/FullscreenButton.css +8 -0
- package/dist/cesium/Widgets/Geocoder/Geocoder.css +70 -0
- package/dist/cesium/Widgets/Geocoder/lighter.css +17 -0
- package/dist/cesium/Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +27 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/azureAerial.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/azureRoads.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/bingAerial.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/bingAerialLabels.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/bingRoads.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/blueMarble.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/earthAtNight.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/googleContour.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/googleRoadmap.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/googleSatellite.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/mapboxSatellite.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/mapboxStreets.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/mapboxTerrain.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/naturalEarthII.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/openStreetMap.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/sentinel-2.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/stamenToner.png +0 -0
- package/dist/cesium/Widgets/Images/ImageryProviders/stamenWatercolor.png +0 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/Mouse.svg +84 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/MouseLeft.svg +76 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/MouseMiddle.svg +76 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/MouseRight.svg +76 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/Touch.svg +120 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/TouchDrag.svg +129 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/TouchRotate.svg +76 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/TouchTilt.svg +135 -0
- package/dist/cesium/Widgets/Images/NavigationHelp/TouchZoom.svg +74 -0
- package/dist/cesium/Widgets/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
- package/dist/cesium/Widgets/Images/TerrainProviders/Ellipsoid.png +0 -0
- package/dist/cesium/Widgets/Images/TimelineIcons.png +0 -0
- package/dist/cesium/Widgets/Images/info-loading.gif +0 -0
- package/dist/cesium/Widgets/InfoBox/InfoBox.css +92 -0
- package/dist/cesium/Widgets/InfoBox/InfoBoxDescription.css +178 -0
- package/dist/cesium/Widgets/NavigationHelpButton/NavigationHelpButton.css +93 -0
- package/dist/cesium/Widgets/NavigationHelpButton/lighter.css +38 -0
- package/dist/cesium/Widgets/PerformanceWatchdog/PerformanceWatchdog.css +15 -0
- package/dist/cesium/Widgets/ProjectionPicker/ProjectionPicker.css +38 -0
- package/dist/cesium/Widgets/SceneModePicker/SceneModePicker.css +56 -0
- package/dist/cesium/Widgets/SelectionIndicator/SelectionIndicator.css +20 -0
- package/dist/cesium/Widgets/Timeline/Timeline.css +103 -0
- package/dist/cesium/Widgets/Timeline/lighter.css +23 -0
- package/dist/cesium/Widgets/VRButton/VRButton.css +8 -0
- package/dist/cesium/Widgets/Viewer/Viewer.css +107 -0
- package/dist/cesium/Widgets/VoxelInspector/VoxelInspector.css +16 -0
- package/dist/cesium/Widgets/lighter.css +237 -0
- package/dist/cesium/Widgets/lighterShared.css +46 -0
- package/dist/cesium/Widgets/shared.css +103 -0
- package/dist/cesium/Widgets/widgets.css +1342 -0
- package/dist/cesium/Workers/chunk-23ZQ2IVV.js +29 -0
- package/dist/cesium/Workers/chunk-2EQO3Q56.js +26 -0
- package/dist/cesium/Workers/chunk-2MJIIVP4.js +26 -0
- package/dist/cesium/Workers/chunk-2TE5NTVD.js +26 -0
- package/dist/cesium/Workers/chunk-2ZBHLJST.js +26 -0
- package/dist/cesium/Workers/chunk-5TJMAQVL.js +26 -0
- package/dist/cesium/Workers/chunk-6BD4U3VO.js +26 -0
- package/dist/cesium/Workers/chunk-7TVGLKQF.js +26 -0
- package/dist/cesium/Workers/chunk-BTSYJ5XU.js +26 -0
- package/dist/cesium/Workers/chunk-BXMEEOCS.js +63 -0
- package/dist/cesium/Workers/chunk-BYLCY7GP.js +29 -0
- package/dist/cesium/Workers/chunk-CTHM3W6I.js +26 -0
- package/dist/cesium/Workers/chunk-CUUSNIVQ.js +26 -0
- package/dist/cesium/Workers/chunk-E3JOOS3S.js +26 -0
- package/dist/cesium/Workers/chunk-E7KYDCM5.js +26 -0
- package/dist/cesium/Workers/chunk-EDVBB7SS.js +27 -0
- package/dist/cesium/Workers/chunk-EFBN7QNX.js +26 -0
- package/dist/cesium/Workers/chunk-EQ4YRVWL.js +26 -0
- package/dist/cesium/Workers/chunk-F6PRE7D6.js +26 -0
- package/dist/cesium/Workers/chunk-FC4ZZ65J.js +26 -0
- package/dist/cesium/Workers/chunk-FFBVWF2L.js +26 -0
- package/dist/cesium/Workers/chunk-GBAA6GVX.js +26 -0
- package/dist/cesium/Workers/chunk-ICALLYLG.js +26 -0
- package/dist/cesium/Workers/chunk-ILRYTWTP.js +26 -0
- package/dist/cesium/Workers/chunk-IRNLBSEJ.js +26 -0
- package/dist/cesium/Workers/chunk-IX4VMHEV.js +26 -0
- package/dist/cesium/Workers/chunk-L6QHHACZ.js +26 -0
- package/dist/cesium/Workers/chunk-LI2ZSORM.js +26 -0
- package/dist/cesium/Workers/chunk-LSLE2RL4.js +26 -0
- package/dist/cesium/Workers/chunk-M4HLDBCG.js +26 -0
- package/dist/cesium/Workers/chunk-MJHHSGEH.js +26 -0
- package/dist/cesium/Workers/chunk-NMVKML6W.js +26 -0
- package/dist/cesium/Workers/chunk-OCWJRAXS.js +26 -0
- package/dist/cesium/Workers/chunk-OIRKANTH.js +26 -0
- package/dist/cesium/Workers/chunk-OIT7J4IC.js +26 -0
- package/dist/cesium/Workers/chunk-OLZ3FYUM.js +26 -0
- package/dist/cesium/Workers/chunk-Q5BPHJQF.js +26 -0
- package/dist/cesium/Workers/chunk-QFM5DCMQ.js +26 -0
- package/dist/cesium/Workers/chunk-QKUIYMGC.js +28 -0
- package/dist/cesium/Workers/chunk-S44JILQT.js +26 -0
- package/dist/cesium/Workers/chunk-SLT4J352.js +26 -0
- package/dist/cesium/Workers/chunk-SQMIIXB7.js +26 -0
- package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +26 -0
- package/dist/cesium/Workers/chunk-TNSUQXWK.js +27 -0
- package/dist/cesium/Workers/chunk-UBOGZS7F.js +26 -0
- package/dist/cesium/Workers/chunk-V3OSTMM6.js +26 -0
- package/dist/cesium/Workers/chunk-V7QEYVP3.js +26 -0
- package/dist/cesium/Workers/chunk-VUKYSU4H.js +26 -0
- package/dist/cesium/Workers/chunk-W37FE5GR.js +26 -0
- package/dist/cesium/Workers/chunk-WBOV35NL.js +26 -0
- package/dist/cesium/Workers/chunk-WPMZLB3Y.js +26 -0
- package/dist/cesium/Workers/chunk-WWWZVEEH.js +26 -0
- package/dist/cesium/Workers/chunk-XFIQ5DEQ.js +28 -0
- package/dist/cesium/Workers/chunk-XQHLGIO7.js +26 -0
- package/dist/cesium/Workers/chunk-XUSCFAVF.js +26 -0
- package/dist/cesium/Workers/chunk-YP7I5QBZ.js +26 -0
- package/dist/cesium/Workers/chunk-Z3QF2EHT.js +26 -0
- package/dist/cesium/Workers/combineGeometry.js +26 -0
- package/dist/cesium/Workers/createBoxGeometry.js +26 -0
- package/dist/cesium/Workers/createBoxOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createCircleGeometry.js +26 -0
- package/dist/cesium/Workers/createCircleOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createCoplanarPolygonGeometry.js +26 -0
- package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createCorridorGeometry.js +26 -0
- package/dist/cesium/Workers/createCorridorOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createCylinderGeometry.js +26 -0
- package/dist/cesium/Workers/createCylinderOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createEllipseGeometry.js +26 -0
- package/dist/cesium/Workers/createEllipseOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createEllipsoidGeometry.js +26 -0
- package/dist/cesium/Workers/createEllipsoidOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createFrustumGeometry.js +26 -0
- package/dist/cesium/Workers/createFrustumOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createGeometry.js +26 -0
- package/dist/cesium/Workers/createGroundPolylineGeometry.js +26 -0
- package/dist/cesium/Workers/createPlaneGeometry.js +26 -0
- package/dist/cesium/Workers/createPlaneOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createPolygonGeometry.js +26 -0
- package/dist/cesium/Workers/createPolygonOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createPolylineGeometry.js +26 -0
- package/dist/cesium/Workers/createPolylineVolumeGeometry.js +26 -0
- package/dist/cesium/Workers/createPolylineVolumeOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createRectangleGeometry.js +26 -0
- package/dist/cesium/Workers/createRectangleOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createSimplePolylineGeometry.js +26 -0
- package/dist/cesium/Workers/createSphereGeometry.js +26 -0
- package/dist/cesium/Workers/createSphereOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/createTaskProcessorWorker.js +26 -0
- package/dist/cesium/Workers/createVectorTileClampedPolylines.js +26 -0
- package/dist/cesium/Workers/createVectorTileGeometries.js +26 -0
- package/dist/cesium/Workers/createVectorTilePoints.js +26 -0
- package/dist/cesium/Workers/createVectorTilePolygons.js +26 -0
- package/dist/cesium/Workers/createVectorTilePolylines.js +26 -0
- package/dist/cesium/Workers/createVerticesFromCesium3DTilesTerrain.js +26 -0
- package/dist/cesium/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -0
- package/dist/cesium/Workers/createVerticesFromHeightmap.js +26 -0
- package/dist/cesium/Workers/createVerticesFromQuantizedTerrainMesh.js +26 -0
- package/dist/cesium/Workers/createWallGeometry.js +26 -0
- package/dist/cesium/Workers/createWallOutlineGeometry.js +26 -0
- package/dist/cesium/Workers/decodeDraco.js +26 -0
- package/dist/cesium/Workers/decodeGoogleEarthEnterprisePacket.js +26 -0
- package/dist/cesium/Workers/decodeI3S.js +26 -0
- package/dist/cesium/Workers/gaussianSplatSorter.js +26 -0
- package/dist/cesium/Workers/gaussianSplatTextureGenerator.js +26 -0
- package/dist/cesium/Workers/incrementallyBuildTerrainPicker.js +26 -0
- package/dist/cesium/Workers/transcodeKTX2.js +56 -0
- package/dist/cesium/Workers/transferTypedArrayTest.js +26 -0
- package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
- package/dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +26 -0
- package/dist/index.html +13 -10
- package/index.html +1 -0
- package/package.json +18 -15
- package/src/App.tsx +7 -9
- package/src/components/viewer/BCFPanel.tsx +46 -4
- package/src/components/viewer/CesiumOverlay.tsx +715 -0
- package/src/components/viewer/CesiumSettingsDialog.tsx +100 -0
- package/src/components/viewer/ChatPanel.tsx +232 -90
- package/src/components/viewer/CommandPalette.tsx +6 -1
- package/src/components/viewer/DesktopEntitlementBanner.tsx +74 -0
- package/src/components/viewer/ExportChangesButton.tsx +6 -1
- package/src/components/viewer/ExportDialog.tsx +22 -6
- package/src/components/viewer/HierarchyPanel.tsx +196 -0
- package/src/components/viewer/IDSPanel.tsx +52 -3
- package/src/components/viewer/KeyboardShortcutsDialog.tsx +1 -1
- package/src/components/viewer/MainToolbar.tsx +355 -28
- package/src/components/viewer/PropertiesPanel.tsx +234 -81
- package/src/components/viewer/ScriptPanel.tsx +34 -8
- package/src/components/viewer/SettingsPage.tsx +581 -0
- package/src/components/viewer/StatusBar.tsx +17 -1
- package/src/components/viewer/ThemeSwitch.tsx +63 -7
- package/src/components/viewer/ViewerLayout.tsx +48 -6
- package/src/components/viewer/Viewport.tsx +61 -8
- package/src/components/viewer/ViewportContainer.tsx +265 -28
- package/src/components/viewer/ViewportOverlays.tsx +132 -27
- package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
- package/src/components/viewer/chat/ModelSelector.tsx +90 -54
- package/src/components/viewer/properties/GeoreferencingPanel.tsx +229 -55
- package/src/components/viewer/properties/LocationMap.tsx +462 -19
- package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
- package/src/components/viewer/selectionHandlers.ts +4 -3
- package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
- package/src/components/viewer/tools/SectionPanel.tsx +39 -18
- package/src/components/viewer/useAnimationLoop.ts +13 -1
- package/src/components/viewer/useGeometryStreaming.ts +127 -40
- package/src/components/viewer/useMouseControls.ts +4 -1
- package/src/components/viewer/useRenderUpdates.ts +1 -1
- package/src/hooks/ids/idsDataAccessor.ts +60 -24
- package/src/hooks/ingest/viewerModelIngest.ts +280 -0
- package/src/hooks/useIDS.ts +1 -1
- package/src/hooks/useIfc.ts +7 -1
- package/src/hooks/useIfcCache.ts +28 -15
- package/src/hooks/useIfcFederation.ts +378 -291
- package/src/hooks/useIfcLoader.ts +1657 -130
- package/src/hooks/useIfcServer.ts +0 -69
- package/src/hooks/useViewControls.ts +13 -5
- package/src/index.css +484 -10
- package/src/lib/desktop/desktopEntitlementEvents.ts +39 -0
- package/src/lib/desktop-entitlement.ts +43 -0
- package/src/lib/desktop-product.ts +124 -0
- package/src/lib/geo/cesium-bridge.ts +318 -0
- package/src/lib/geo/effective-georef.test.ts +73 -0
- package/src/lib/geo/effective-georef.ts +111 -0
- package/src/lib/geo/reproject.ts +249 -37
- package/src/lib/llm/byok-guard.test.ts +77 -0
- package/src/lib/llm/byok-guard.ts +39 -0
- package/src/lib/llm/free-models.test.ts +0 -6
- package/src/lib/llm/models.ts +104 -42
- package/src/lib/llm/stream-client.ts +74 -110
- package/src/lib/llm/stream-direct.test.ts +130 -0
- package/src/lib/llm/stream-direct.ts +316 -0
- package/src/lib/llm/types.ts +14 -2
- package/src/lib/recent-files.ts +2 -1
- package/src/main.tsx +1 -10
- package/src/services/analysis-extensions.ts +125 -0
- package/src/services/api-keys.ts +73 -0
- package/src/services/app-navigation.ts +13 -0
- package/src/services/bsdd.ts +53 -4
- package/src/services/cacheService.ts +1 -1
- package/src/services/desktop-cache.ts +43 -0
- package/src/services/desktop-export.ts +77 -0
- package/src/services/desktop-harness.ts +196 -0
- package/src/services/desktop-logger.ts +20 -0
- package/src/services/desktop-native-metadata.ts +207 -0
- package/src/services/desktop-panel-actions.ts +43 -0
- package/src/services/desktop-preferences.ts +44 -0
- package/src/services/file-dialog.ts +147 -0
- package/src/services/tauri-core-stub.ts +7 -0
- package/src/services/tauri-dialog-stub.ts +7 -0
- package/src/services/tauri-fs-stub.ts +7 -0
- package/src/store/constants.ts +20 -2
- package/src/store/index.ts +52 -7
- package/src/store/slices/cesiumSlice.ts +127 -0
- package/src/store/slices/chatSlice.test.ts +6 -76
- package/src/store/slices/chatSlice.ts +21 -58
- package/src/store/slices/dataSlice.ts +139 -28
- package/src/store/slices/desktopEntitlementSlice.ts +86 -0
- package/src/store/slices/loadingSlice.ts +14 -2
- package/src/store/slices/modelSlice.ts +58 -3
- package/src/store/slices/sectionSlice.test.ts +87 -7
- package/src/store/slices/sectionSlice.ts +151 -5
- package/src/store/slices/uiSlice.ts +28 -5
- package/src/store/types.ts +122 -2
- package/src/store.ts +1 -1
- package/src/utils/desktopModelSnapshot.ts +358 -0
- package/src/utils/ifcConfig.ts +6 -1
- package/src/utils/nativeSpatialDataStore.ts +253 -0
- package/src/utils/serverDataModel.ts +4 -0
- package/src/utils/spatialHierarchy.ts +10 -11
- package/src/utils/viewportUtils.ts +7 -2
- package/src/vite-env.d.ts +0 -4
- package/vite.config.ts +24 -0
- package/dist/assets/arrow-DJf2ErbF.js +0 -20
- package/dist/assets/basketViewActivator-aojwdomq.js +0 -1
- package/dist/assets/desktop-cache-oPzaWXYE.js +0 -1
- package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
- package/dist/assets/geometry.worker-Nz9_YIqh.js +0 -1
- package/dist/assets/ids-B4jTqB1O.js +0 -1
- package/dist/assets/ifc-lite_bg-eSkBTizQ.wasm +0 -0
- package/dist/assets/index-pbE7itQS.css +0 -1
- package/dist/assets/native-bridge-DSIyEYXG.js +0 -113
- package/dist/assets/wasm-bridge-B0J07fZZ.js +0 -1
- package/src/components/viewer/UpgradePage.tsx +0 -69
- package/src/lib/llm/ClerkChatSync.tsx +0 -74
- package/src/lib/llm/clerk-auth.ts +0 -62
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Settings dialog for configuring Cesium 3D overlay options:
|
|
7
|
+
* - Data source selection (OSM Buildings, Bing Aerial, Google Photorealistic)
|
|
8
|
+
* - Terrain toggle
|
|
9
|
+
* - Advanced: custom Cesium ion token override (optional — default is bundled)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { useState } from 'react';
|
|
13
|
+
import {
|
|
14
|
+
Dialog,
|
|
15
|
+
DialogContent,
|
|
16
|
+
DialogHeader,
|
|
17
|
+
DialogTitle,
|
|
18
|
+
DialogTrigger,
|
|
19
|
+
} from '@/components/ui/dialog';
|
|
20
|
+
import { Button } from '@/components/ui/button';
|
|
21
|
+
import { Label } from '@/components/ui/label';
|
|
22
|
+
import { useViewerStore } from '@/store';
|
|
23
|
+
import type { CesiumDataSource } from '@/store/slices/cesiumSlice';
|
|
24
|
+
import { Settings2 } from 'lucide-react';
|
|
25
|
+
|
|
26
|
+
const DATA_SOURCE_OPTIONS: { value: CesiumDataSource; label: string; description: string }[] = [
|
|
27
|
+
{ value: 'osm-buildings', label: 'OSM Buildings', description: 'OpenStreetMap 3D buildings worldwide' },
|
|
28
|
+
{ value: 'bing-aerial', label: 'Bing Aerial', description: 'Satellite imagery draped on terrain' },
|
|
29
|
+
{ value: 'google-photorealistic', label: 'Google Photorealistic', description: 'High-fidelity 3D photogrammetry (where available)' },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export function CesiumSettingsDialog() {
|
|
33
|
+
const dataSource = useViewerStore((s) => s.cesiumDataSource);
|
|
34
|
+
const setCesiumDataSource = useViewerStore((s) => s.setCesiumDataSource);
|
|
35
|
+
const terrainEnabled = useViewerStore((s) => s.cesiumTerrainEnabled);
|
|
36
|
+
const setCesiumTerrainEnabled = useViewerStore((s) => s.setCesiumTerrainEnabled);
|
|
37
|
+
const [open, setOpen] = useState(false);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
41
|
+
<DialogTrigger asChild>
|
|
42
|
+
<Button variant="ghost" size="icon-sm" className="h-6 w-6" aria-label="Cesium settings">
|
|
43
|
+
<Settings2 className="h-3 w-3" />
|
|
44
|
+
</Button>
|
|
45
|
+
</DialogTrigger>
|
|
46
|
+
<DialogContent className="sm:max-w-md">
|
|
47
|
+
<DialogHeader>
|
|
48
|
+
<DialogTitle className="text-sm font-bold">3D World Context</DialogTitle>
|
|
49
|
+
</DialogHeader>
|
|
50
|
+
|
|
51
|
+
<div className="space-y-4 mt-2">
|
|
52
|
+
{/* Data Source */}
|
|
53
|
+
<div className="space-y-1.5">
|
|
54
|
+
<Label className="text-xs font-medium">3D Data Source</Label>
|
|
55
|
+
<div className="space-y-1">
|
|
56
|
+
{DATA_SOURCE_OPTIONS.map((opt) => (
|
|
57
|
+
<label
|
|
58
|
+
key={opt.value}
|
|
59
|
+
className={`flex items-start gap-2 p-2 rounded border cursor-pointer transition-colors ${
|
|
60
|
+
dataSource === opt.value
|
|
61
|
+
? 'border-teal-500 bg-teal-50 dark:bg-teal-950/30'
|
|
62
|
+
: 'border-zinc-200 dark:border-zinc-700 hover:border-zinc-300 dark:hover:border-zinc-600'
|
|
63
|
+
}`}
|
|
64
|
+
>
|
|
65
|
+
<input
|
|
66
|
+
type="radio"
|
|
67
|
+
name="cesium-data-source"
|
|
68
|
+
checked={dataSource === opt.value}
|
|
69
|
+
onChange={() => setCesiumDataSource(opt.value)}
|
|
70
|
+
className="mt-0.5 accent-teal-500"
|
|
71
|
+
/>
|
|
72
|
+
<div>
|
|
73
|
+
<div className="text-xs font-medium">{opt.label}</div>
|
|
74
|
+
<div className="text-[10px] text-zinc-400">{opt.description}</div>
|
|
75
|
+
</div>
|
|
76
|
+
</label>
|
|
77
|
+
))}
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{/* Terrain Toggle */}
|
|
82
|
+
<label className="flex items-center gap-2 cursor-pointer">
|
|
83
|
+
<input
|
|
84
|
+
type="checkbox"
|
|
85
|
+
checked={terrainEnabled}
|
|
86
|
+
onChange={(e) => setCesiumTerrainEnabled(e.target.checked)}
|
|
87
|
+
className="accent-teal-500"
|
|
88
|
+
/>
|
|
89
|
+
<span className="text-xs">Enable 3D terrain (Cesium World Terrain)</span>
|
|
90
|
+
</label>
|
|
91
|
+
|
|
92
|
+
<p className="text-[10px] text-zinc-400 border-t border-zinc-100 dark:border-zinc-800 pt-3">
|
|
93
|
+
Powered by Cesium ion. Real-world 3D tiles are overlaid on your georeferenced
|
|
94
|
+
IFC model. Only available when the model contains IfcMapConversion data.
|
|
95
|
+
</p>
|
|
96
|
+
</div>
|
|
97
|
+
</DialogContent>
|
|
98
|
+
</Dialog>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -29,14 +29,15 @@ import {
|
|
|
29
29
|
ArrowDown,
|
|
30
30
|
Zap,
|
|
31
31
|
} from 'lucide-react';
|
|
32
|
-
import { SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/clerk-react';
|
|
33
32
|
import { Button } from '@/components/ui/button';
|
|
33
|
+
import { toast } from '@/components/ui/toast';
|
|
34
34
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
|
35
35
|
import { useViewerStore } from '@/store';
|
|
36
36
|
import { buildErrorFeedbackContent } from '@/store/slices/chatSlice';
|
|
37
37
|
import { ChatMessageComponent } from './chat/ChatMessage';
|
|
38
38
|
import { ModelSelector } from './chat/ModelSelector';
|
|
39
39
|
import { fetchUsageSnapshot, streamChat, type StreamMessage, type TextContentPart, type ImageContentPart, type UsageInfo } from '@/lib/llm/stream-client';
|
|
40
|
+
import { streamAnthropicChat, streamOpenAiChat } from '@/lib/llm/stream-direct';
|
|
40
41
|
import { buildStreamMessagesForModel, filterAttachmentsForModel } from '@/lib/llm/message-capabilities';
|
|
41
42
|
import { buildSystemPrompt } from '@/lib/llm/system-prompt';
|
|
42
43
|
import { getModelContext, parseCSV } from '@/lib/llm/context-builder';
|
|
@@ -48,9 +49,11 @@ import type { ScriptDiagnostic } from '@/lib/llm/script-diagnostics';
|
|
|
48
49
|
import { buildRepairSessionKey, getEscalatedRepairScope, pruneMessagesForRepair } from '@/lib/llm/repair-loop';
|
|
49
50
|
import type { ChatMessage, ChatRepairRequest, FileAttachment } from '@/lib/llm/types';
|
|
50
51
|
import { canUsePlainCodeBlockFallback, type ScriptMutationIntent } from '@/lib/llm/script-preservation';
|
|
51
|
-
import { Image as ImageIcon } from 'lucide-react';
|
|
52
|
-
import {
|
|
52
|
+
import { Check, Image as ImageIcon, Key, Eye, EyeOff, ExternalLink } from 'lucide-react';
|
|
53
|
+
import { hasDesktopFeatureAccess } from '@/lib/desktop-product';
|
|
53
54
|
import { getModelById } from '@/lib/llm/models';
|
|
55
|
+
import { resolveStreamRoute } from '@/lib/llm/byok-guard';
|
|
56
|
+
import { getApiKeys, updateApiKeys, hasAnthropicKey, hasOpenaiKey, subscribeApiKeys } from '@/services/api-keys';
|
|
54
57
|
import { useSandbox } from '@/hooks/useSandbox';
|
|
55
58
|
|
|
56
59
|
// Environment variable for the proxy URL
|
|
@@ -64,7 +67,6 @@ const EXAMPLE_PROMPTS = [
|
|
|
64
67
|
];
|
|
65
68
|
|
|
66
69
|
const CONTINUE_PROMPT = 'Continue from exactly where your last response stopped. Do not repeat previously generated text.';
|
|
67
|
-
const DEFAULT_PRO_MONTHLY_CREDIT_LIMIT = 1000;
|
|
68
70
|
const USAGE_REFRESH_INTERVAL_MS = 15_000;
|
|
69
71
|
const EST_CHARS_PER_TOKEN = 4;
|
|
70
72
|
const IMAGE_TOKEN_COST_EST = 850;
|
|
@@ -208,21 +210,30 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
208
210
|
const consumePendingPrompt = useViewerStore((s) => s.consumeChatPendingPrompt);
|
|
209
211
|
const pendingRepairRequest = useViewerStore((s) => s.chatPendingRepairRequest);
|
|
210
212
|
const consumePendingRepairRequest = useViewerStore((s) => s.consumeChatPendingRepairRequest);
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
+
const hasByokKey = useViewerStore((s) => s.chatHasByokKey);
|
|
214
|
+
const setChatHasByokKey = useViewerStore((s) => s.setChatHasByokKey);
|
|
213
215
|
const usage = useViewerStore((s) => s.chatUsage);
|
|
214
216
|
const setChatUsage = useViewerStore((s) => s.setChatUsage);
|
|
217
|
+
const desktopEntitlement = useViewerStore((s) => s.desktopEntitlement);
|
|
215
218
|
const { execute } = useSandbox();
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
219
|
+
const canUseAiAssistant = hasDesktopFeatureAccess(desktopEntitlement, 'ai_assistant');
|
|
220
|
+
|
|
221
|
+
// Sync BYOK key availability into the store and track per-provider state
|
|
222
|
+
const [keyStateAnthropic, setKeyStateAnthropic] = useState(hasAnthropicKey);
|
|
223
|
+
const [keyStateOpenai, setKeyStateOpenai] = useState(hasOpenaiKey);
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
const refresh = () => {
|
|
226
|
+
const a = hasAnthropicKey();
|
|
227
|
+
const o = hasOpenaiKey();
|
|
228
|
+
setKeyStateAnthropic(a);
|
|
229
|
+
setKeyStateOpenai(o);
|
|
230
|
+
setChatHasByokKey(a || o);
|
|
231
|
+
};
|
|
232
|
+
refresh();
|
|
233
|
+
return subscribeApiKeys(refresh);
|
|
234
|
+
}, [setChatHasByokKey]);
|
|
235
|
+
|
|
236
|
+
const displayUsage: UsageInfo | null = usage;
|
|
226
237
|
const usageResetLabel = displayUsage?.resetAt && displayUsage.resetAt > 0
|
|
227
238
|
? new Date(displayUsage.resetAt * 1000).toLocaleDateString()
|
|
228
239
|
: '—';
|
|
@@ -233,6 +244,10 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
233
244
|
const [showScrollBtn, setShowScrollBtn] = useState(false);
|
|
234
245
|
const [userScrolledUp, setUserScrolledUp] = useState(false);
|
|
235
246
|
const [lastFinishReason, setLastFinishReason] = useState<string | null>(null);
|
|
247
|
+
const promptAiUpgrade = useCallback(() => {
|
|
248
|
+
setChatError('AI assistant is available with Desktop Pro.');
|
|
249
|
+
toast.info('AI assistant is available with Desktop Pro');
|
|
250
|
+
}, [setChatError]);
|
|
236
251
|
|
|
237
252
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
238
253
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
@@ -294,7 +309,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
294
309
|
useEffect(() => {
|
|
295
310
|
let cancelled = false;
|
|
296
311
|
const refreshUsage = async () => {
|
|
297
|
-
const snapshot = await fetchUsageSnapshot(PROXY_URL
|
|
312
|
+
const snapshot = await fetchUsageSnapshot(PROXY_URL);
|
|
298
313
|
if (!cancelled && snapshot) {
|
|
299
314
|
setChatUsage(snapshot);
|
|
300
315
|
}
|
|
@@ -309,7 +324,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
309
324
|
cancelled = true;
|
|
310
325
|
window.clearInterval(timer);
|
|
311
326
|
};
|
|
312
|
-
}, [
|
|
327
|
+
}, [setChatUsage]);
|
|
313
328
|
|
|
314
329
|
// ── Keyboard shortcuts ──
|
|
315
330
|
useEffect(() => {
|
|
@@ -385,6 +400,24 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
385
400
|
// ── Core send logic ──
|
|
386
401
|
const doSend = useCallback(async (text: string, options?: ChatSendOptions) => {
|
|
387
402
|
if (!text.trim() || status === 'streaming' || status === 'sending') return;
|
|
403
|
+
if (!canUseAiAssistant) {
|
|
404
|
+
setChatError('AI assistant is available with Desktop Pro.');
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Resolve the stream route BEFORE any user-visible side effects (adding
|
|
409
|
+
// the user message, clearing attachments, setting sending state). If the
|
|
410
|
+
// selected BYOK model has no key, bail out now so the chat transcript
|
|
411
|
+
// doesn't stack orphaned user messages on repeated sends.
|
|
412
|
+
const route = resolveStreamRoute(activeModel, getApiKeys());
|
|
413
|
+
if (route.kind === 'missing-key') {
|
|
414
|
+
setChatError(
|
|
415
|
+
route.provider === 'anthropic'
|
|
416
|
+
? 'Enter your Anthropic API key above to use this model.'
|
|
417
|
+
: 'Enter your OpenAI API key above to use this model.',
|
|
418
|
+
);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
388
421
|
|
|
389
422
|
const continuationBase = options?.continuationBase;
|
|
390
423
|
const responseIntent = options?.intent ?? 'create';
|
|
@@ -571,14 +604,8 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
571
604
|
}
|
|
572
605
|
};
|
|
573
606
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
model: activeModel,
|
|
577
|
-
messages: streamMessages,
|
|
578
|
-
system: systemPrompt,
|
|
579
|
-
authToken,
|
|
580
|
-
signal: abortController.signal,
|
|
581
|
-
onChunk: (chunk) => {
|
|
607
|
+
// ── Shared stream callbacks ──
|
|
608
|
+
const handleChunk = (chunk: string) => {
|
|
582
609
|
clearPendingAttachmentsOnce();
|
|
583
610
|
accumulated += chunk;
|
|
584
611
|
if (!responseEditState.applyFailed && responseEditState.intent !== 'repair') {
|
|
@@ -612,8 +639,8 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
612
639
|
}
|
|
613
640
|
setChatStatus('streaming');
|
|
614
641
|
updateStreaming(accumulated);
|
|
615
|
-
|
|
616
|
-
|
|
642
|
+
};
|
|
643
|
+
const handleComplete = (fullText: string) => {
|
|
617
644
|
clearPendingAttachmentsOnce();
|
|
618
645
|
const normalizedText = continuationBase
|
|
619
646
|
? stripContinuationOverlap(continuationBase, fullText)
|
|
@@ -755,22 +782,62 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
755
782
|
}
|
|
756
783
|
|
|
757
784
|
commitAssistantTurn();
|
|
758
|
-
|
|
759
|
-
|
|
785
|
+
};
|
|
786
|
+
const handleUsageInfo = (info: UsageInfo) => {
|
|
760
787
|
setChatUsage(info);
|
|
761
|
-
|
|
762
|
-
|
|
788
|
+
};
|
|
789
|
+
const handleFinishReason = (reason: string | null) => {
|
|
763
790
|
setLastFinishReason(reason);
|
|
764
791
|
if (reason === 'length') {
|
|
765
792
|
setChatError('Response reached output limit. Click Continue to resume.');
|
|
766
793
|
}
|
|
767
|
-
|
|
768
|
-
|
|
794
|
+
};
|
|
795
|
+
const handleError = (err: Error) => {
|
|
769
796
|
setChatError(err.message);
|
|
770
797
|
setChatAbortController(null);
|
|
771
798
|
commitAssistantTurn();
|
|
772
|
-
|
|
773
|
-
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
// Route to direct provider streaming for BYOK models, or through the proxy
|
|
802
|
+
// for free models. The route was already resolved (and the missing-key
|
|
803
|
+
// case handled) at the top of doSend, so this dispatch is total.
|
|
804
|
+
if (route.kind === 'anthropic') {
|
|
805
|
+
await streamAnthropicChat(route.apiKey, {
|
|
806
|
+
model: activeModel,
|
|
807
|
+
messages: streamMessages,
|
|
808
|
+
system: systemPrompt,
|
|
809
|
+
signal: abortController.signal,
|
|
810
|
+
onChunk: handleChunk,
|
|
811
|
+
onComplete: handleComplete,
|
|
812
|
+
onFinishReason: handleFinishReason,
|
|
813
|
+
onError: handleError,
|
|
814
|
+
});
|
|
815
|
+
} else if (route.kind === 'openai') {
|
|
816
|
+
await streamOpenAiChat(route.apiKey, {
|
|
817
|
+
model: activeModel,
|
|
818
|
+
messages: streamMessages,
|
|
819
|
+
system: systemPrompt,
|
|
820
|
+
signal: abortController.signal,
|
|
821
|
+
onChunk: handleChunk,
|
|
822
|
+
onComplete: handleComplete,
|
|
823
|
+
onFinishReason: handleFinishReason,
|
|
824
|
+
onError: handleError,
|
|
825
|
+
});
|
|
826
|
+
} else {
|
|
827
|
+
await streamChat({
|
|
828
|
+
proxyUrl: PROXY_URL,
|
|
829
|
+
model: activeModel,
|
|
830
|
+
messages: streamMessages,
|
|
831
|
+
system: systemPrompt,
|
|
832
|
+
signal: abortController.signal,
|
|
833
|
+
onChunk: handleChunk,
|
|
834
|
+
onComplete: handleComplete,
|
|
835
|
+
onFinishReason: handleFinishReason,
|
|
836
|
+
onError: handleError,
|
|
837
|
+
onUsageInfo: handleUsageInfo,
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
|
|
774
841
|
if (abortController.signal.aborted) {
|
|
775
842
|
commitAssistantTurn();
|
|
776
843
|
const currentState = useViewerStore.getState();
|
|
@@ -780,15 +847,19 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
780
847
|
}
|
|
781
848
|
}
|
|
782
849
|
}, [
|
|
783
|
-
status, activeModel, attachments,
|
|
850
|
+
canUseAiAssistant, status, activeModel, attachments,
|
|
784
851
|
addMessage, setChatStatus, updateStreaming, finalizeAssistant,
|
|
785
852
|
setChatError, setChatAbortController, clearAttachments, setChatUsage, resizeInput,
|
|
786
853
|
buildRepairPromptFromLiveState, triggerAutoRepair, execute,
|
|
787
854
|
]);
|
|
788
855
|
|
|
789
856
|
const handleSend = useCallback(() => {
|
|
857
|
+
if (!canUseAiAssistant) {
|
|
858
|
+
promptAiUpgrade();
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
790
861
|
doSend(inputText);
|
|
791
|
-
}, [inputText,
|
|
862
|
+
}, [canUseAiAssistant, doSend, inputText, promptAiUpgrade]);
|
|
792
863
|
|
|
793
864
|
// Allow other panels (e.g. ScriptPanel errors) to trigger a chat repair turn.
|
|
794
865
|
useEffect(() => {
|
|
@@ -817,6 +888,10 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
817
888
|
}, [pendingRepairRequest, status, consumePendingRepairRequest, buildRepairPromptFromLiveState, doSend]);
|
|
818
889
|
|
|
819
890
|
const handleContinue = useCallback(() => {
|
|
891
|
+
if (!canUseAiAssistant) {
|
|
892
|
+
promptAiUpgrade();
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
820
895
|
const state = useViewerStore.getState();
|
|
821
896
|
const partial = state.chatStreamingContent.trim();
|
|
822
897
|
const lastAssistant = [...state.chatMessages].reverse().find((m) => m.role === 'assistant');
|
|
@@ -829,7 +904,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
829
904
|
}
|
|
830
905
|
setChatError(null);
|
|
831
906
|
doSend(CONTINUE_PROMPT, { continuationBase });
|
|
832
|
-
}, [doSend, finalizeAssistant, setChatError]);
|
|
907
|
+
}, [canUseAiAssistant, doSend, finalizeAssistant, promptAiUpgrade, setChatError]);
|
|
833
908
|
|
|
834
909
|
const handleStop = useCallback(() => {
|
|
835
910
|
const controller = useViewerStore.getState().chatAbortController;
|
|
@@ -854,6 +929,10 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
854
929
|
|
|
855
930
|
// ── Error feedback (Fix this) ──
|
|
856
931
|
const handleFixError = useCallback((code: string, errorMsg: string) => {
|
|
932
|
+
if (!canUseAiAssistant) {
|
|
933
|
+
promptAiUpgrade();
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
857
936
|
const diagnostics = useViewerStore.getState().scriptLastDiagnostics;
|
|
858
937
|
const liveCode = useViewerStore.getState().scriptEditorContent;
|
|
859
938
|
const staleCode = code.trim() !== liveCode.trim() ? code : undefined;
|
|
@@ -868,7 +947,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
868
947
|
requestedRepairScope: getPrimaryRootCause(diagnostics)?.repairScope,
|
|
869
948
|
rootCauseKey: getPrimaryRootCause(diagnostics)?.rootCauseKey,
|
|
870
949
|
});
|
|
871
|
-
}, [buildRepairPromptFromLiveState, doSend]);
|
|
950
|
+
}, [buildRepairPromptFromLiveState, canUseAiAssistant, doSend, promptAiUpgrade]);
|
|
872
951
|
|
|
873
952
|
// ── Clickable example prompts ──
|
|
874
953
|
const handleExampleClick = useCallback((prompt: string) => {
|
|
@@ -898,6 +977,10 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
898
977
|
|
|
899
978
|
// ── File upload (button + drag-drop + paste) ──
|
|
900
979
|
const processFiles = useCallback(async (files: FileList | File[]) => {
|
|
980
|
+
if (!canUseAiAssistant) {
|
|
981
|
+
promptAiUpgrade();
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
901
984
|
const model = getModelById(activeModel);
|
|
902
985
|
const supportsImages = model?.supportsImages ?? false;
|
|
903
986
|
const supportsFileAttachments = model?.supportsFileAttachments ?? true;
|
|
@@ -965,7 +1048,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
965
1048
|
setChatError(`Could not read ${file.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
966
1049
|
}
|
|
967
1050
|
}
|
|
968
|
-
}, [activeModel, addAttachment, attachments.length, setChatError]);
|
|
1051
|
+
}, [activeModel, addAttachment, attachments.length, canUseAiAssistant, promptAiUpgrade, setChatError]);
|
|
969
1052
|
|
|
970
1053
|
const handleFileUpload = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
971
1054
|
const files = e.target.files;
|
|
@@ -1038,19 +1121,15 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1038
1121
|
modelSupportsImages ? 'image/*' : '',
|
|
1039
1122
|
].filter(Boolean).join(',');
|
|
1040
1123
|
const canAttachInput = modelSupportsFiles || modelSupportsImages;
|
|
1041
|
-
|
|
1042
|
-
const
|
|
1124
|
+
// Detect when selected model needs a missing BYOK key (reactive state, not raw reads)
|
|
1125
|
+
const modelSource = modelForUi?.source ?? 'proxy';
|
|
1126
|
+
const needsAnthropicKey = modelSource === 'anthropic' && !keyStateAnthropic;
|
|
1127
|
+
const needsOpenaiKey = modelSource === 'openai' && !keyStateOpenai;
|
|
1128
|
+
const needsByokKey = needsAnthropicKey || needsOpenaiKey;
|
|
1043
1129
|
const showSupportEmail = Boolean(error && error.includes('louis@ltplus.com'));
|
|
1044
1130
|
const canContinue = Boolean(
|
|
1045
1131
|
!isActive && (streamingContent.trim().length > 0 || lastFinishReason === 'length'),
|
|
1046
1132
|
);
|
|
1047
|
-
const openUpgradePage = useCallback(() => {
|
|
1048
|
-
const currentPath = `${window.location.pathname}${window.location.search}`;
|
|
1049
|
-
const target = `/upgrade?returnTo=${encodeURIComponent(currentPath)}`;
|
|
1050
|
-
window.history.pushState({}, '', target);
|
|
1051
|
-
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
1052
|
-
}, []);
|
|
1053
|
-
|
|
1054
1133
|
return (
|
|
1055
1134
|
<div
|
|
1056
1135
|
className="h-full flex flex-col bg-background relative"
|
|
@@ -1085,7 +1164,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1085
1164
|
<TooltipContent>Clear</TooltipContent>
|
|
1086
1165
|
</Tooltip>
|
|
1087
1166
|
|
|
1088
|
-
<ModelSelector
|
|
1167
|
+
<ModelSelector />
|
|
1089
1168
|
<div className="flex-1" />
|
|
1090
1169
|
|
|
1091
1170
|
<Tooltip>
|
|
@@ -1102,31 +1181,6 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1102
1181
|
<TooltipContent>Auto-run: {autoExecute ? 'ON' : 'OFF'}</TooltipContent>
|
|
1103
1182
|
</Tooltip>
|
|
1104
1183
|
|
|
1105
|
-
{clerkEnabled && (
|
|
1106
|
-
<>
|
|
1107
|
-
<SignedOut>
|
|
1108
|
-
<SignInButton mode="modal">
|
|
1109
|
-
<Button variant="ghost" size="sm" className="h-6 px-2 text-xs text-muted-foreground">
|
|
1110
|
-
Sign in
|
|
1111
|
-
</Button>
|
|
1112
|
-
</SignInButton>
|
|
1113
|
-
</SignedOut>
|
|
1114
|
-
{!hasPro && (
|
|
1115
|
-
<Button
|
|
1116
|
-
variant="ghost"
|
|
1117
|
-
size="sm"
|
|
1118
|
-
className="h-6 px-2 text-xs text-muted-foreground"
|
|
1119
|
-
onClick={openUpgradePage}
|
|
1120
|
-
>
|
|
1121
|
-
Pro
|
|
1122
|
-
</Button>
|
|
1123
|
-
)}
|
|
1124
|
-
<SignedIn>
|
|
1125
|
-
<UserButton afterSignOutUrl="/" />
|
|
1126
|
-
</SignedIn>
|
|
1127
|
-
</>
|
|
1128
|
-
)}
|
|
1129
|
-
|
|
1130
1184
|
{onClose && (
|
|
1131
1185
|
<Button variant="ghost" size="icon-xs" onClick={onClose}>
|
|
1132
1186
|
<X className="h-3.5 w-3.5" />
|
|
@@ -1134,6 +1188,17 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1134
1188
|
)}
|
|
1135
1189
|
</div>
|
|
1136
1190
|
|
|
1191
|
+
{!canUseAiAssistant && (
|
|
1192
|
+
<div className="border-b bg-muted/40 px-3 py-2 text-xs text-muted-foreground">
|
|
1193
|
+
AI assistant requires Desktop Pro. Core viewing and scripting stay available without it.
|
|
1194
|
+
</div>
|
|
1195
|
+
)}
|
|
1196
|
+
|
|
1197
|
+
{/* Inline BYOK key prompt — shown when user picks a model without the matching key */}
|
|
1198
|
+
{needsByokKey && canUseAiAssistant && (
|
|
1199
|
+
<InlineKeyPrompt provider={needsAnthropicKey ? 'anthropic' : 'openai'} />
|
|
1200
|
+
)}
|
|
1201
|
+
|
|
1137
1202
|
{/* Clear confirmation */}
|
|
1138
1203
|
{showClearConfirm && (
|
|
1139
1204
|
<div className="px-3 py-2 bg-destructive/5 border-b flex items-center gap-2 text-xs">
|
|
@@ -1238,16 +1303,6 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1238
1303
|
Continue
|
|
1239
1304
|
</Button>
|
|
1240
1305
|
)}
|
|
1241
|
-
{showUpgradeNudge && clerkEnabled && (
|
|
1242
|
-
<Button
|
|
1243
|
-
variant="outline"
|
|
1244
|
-
size="sm"
|
|
1245
|
-
className="h-5 px-2 text-[10px]"
|
|
1246
|
-
onClick={openUpgradePage}
|
|
1247
|
-
>
|
|
1248
|
-
Upgrade
|
|
1249
|
-
</Button>
|
|
1250
|
-
)}
|
|
1251
1306
|
{showSupportEmail && (
|
|
1252
1307
|
<a className="underline text-[10px]" href="mailto:louis@ltplus.com">
|
|
1253
1308
|
Contact support
|
|
@@ -1308,14 +1363,16 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1308
1363
|
variant="ghost"
|
|
1309
1364
|
size="icon-xs"
|
|
1310
1365
|
onClick={() => fileInputRef.current?.click()}
|
|
1311
|
-
disabled={!canAttachInput}
|
|
1366
|
+
disabled={!canAttachInput || !canUseAiAssistant}
|
|
1312
1367
|
className="shrink-0 mb-0.5"
|
|
1313
1368
|
>
|
|
1314
1369
|
<Paperclip className="h-3.5 w-3.5" />
|
|
1315
1370
|
</Button>
|
|
1316
1371
|
</TooltipTrigger>
|
|
1317
1372
|
<TooltipContent>
|
|
1318
|
-
{
|
|
1373
|
+
{!canUseAiAssistant
|
|
1374
|
+
? 'AI assistant not available'
|
|
1375
|
+
: canAttachInput
|
|
1319
1376
|
? 'Attach file or image (paste, drag & drop)'
|
|
1320
1377
|
: 'Selected model does not support attachments'}
|
|
1321
1378
|
</TooltipContent>
|
|
@@ -1330,10 +1387,11 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1330
1387
|
}}
|
|
1331
1388
|
onKeyDown={handleKeyDown}
|
|
1332
1389
|
onPaste={handlePaste}
|
|
1333
|
-
placeholder=
|
|
1390
|
+
placeholder={!canUseAiAssistant ? 'AI assistant not available' : needsByokKey ? `Enter your ${needsAnthropicKey ? 'Anthropic' : 'OpenAI'} API key above` : 'Ask anything...'}
|
|
1334
1391
|
rows={1}
|
|
1335
1392
|
className="flex-1 resize-none rounded-md border border-input bg-background text-foreground placeholder:text-muted-foreground px-3 py-1.5 text-sm min-h-[32px] max-h-[120px] focus:outline-none focus:ring-1 focus:ring-ring"
|
|
1336
1393
|
style={{ height: 'auto', overflow: 'hidden' }}
|
|
1394
|
+
disabled={!canUseAiAssistant || needsByokKey}
|
|
1337
1395
|
/>
|
|
1338
1396
|
|
|
1339
1397
|
{isActive ? (
|
|
@@ -1357,7 +1415,7 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1357
1415
|
variant="default"
|
|
1358
1416
|
size="icon-xs"
|
|
1359
1417
|
onClick={handleSend}
|
|
1360
|
-
disabled={!inputText.trim()}
|
|
1418
|
+
disabled={!inputText.trim() || !canUseAiAssistant || needsByokKey}
|
|
1361
1419
|
className="shrink-0 mb-0.5"
|
|
1362
1420
|
>
|
|
1363
1421
|
<Send className="h-3.5 w-3.5" />
|
|
@@ -1400,3 +1458,87 @@ export function ChatPanel({ onClose }: ChatPanelProps) {
|
|
|
1400
1458
|
</div>
|
|
1401
1459
|
);
|
|
1402
1460
|
}
|
|
1461
|
+
|
|
1462
|
+
// ── Inline BYOK key prompt (shown inside chat panel when key is missing) ──
|
|
1463
|
+
|
|
1464
|
+
const PROVIDER_INFO = {
|
|
1465
|
+
anthropic: {
|
|
1466
|
+
label: 'Anthropic',
|
|
1467
|
+
placeholder: 'sk-ant-api03-...',
|
|
1468
|
+
url: 'https://console.anthropic.com/settings/keys',
|
|
1469
|
+
urlLabel: 'console.anthropic.com',
|
|
1470
|
+
},
|
|
1471
|
+
openai: {
|
|
1472
|
+
label: 'OpenAI',
|
|
1473
|
+
placeholder: 'sk-...',
|
|
1474
|
+
url: 'https://platform.openai.com/api-keys',
|
|
1475
|
+
urlLabel: 'platform.openai.com',
|
|
1476
|
+
},
|
|
1477
|
+
} as const;
|
|
1478
|
+
|
|
1479
|
+
function InlineKeyPrompt({ provider }: { provider: 'anthropic' | 'openai' }) {
|
|
1480
|
+
const [value, setValue] = useState('');
|
|
1481
|
+
const [show, setShow] = useState(false);
|
|
1482
|
+
const [saved, setSaved] = useState(false);
|
|
1483
|
+
const info = PROVIDER_INFO[provider];
|
|
1484
|
+
|
|
1485
|
+
const handleSave = useCallback(() => {
|
|
1486
|
+
const trimmed = value.trim();
|
|
1487
|
+
if (!trimmed) return;
|
|
1488
|
+
if (provider === 'anthropic') {
|
|
1489
|
+
updateApiKeys({ anthropicKey: trimmed });
|
|
1490
|
+
} else {
|
|
1491
|
+
updateApiKeys({ openaiKey: trimmed });
|
|
1492
|
+
}
|
|
1493
|
+
setSaved(true);
|
|
1494
|
+
}, [value, provider]);
|
|
1495
|
+
|
|
1496
|
+
// Brief success state before the parent unmounts this component
|
|
1497
|
+
if (saved) {
|
|
1498
|
+
return (
|
|
1499
|
+
<div className="border-b bg-emerald-500/10 px-3 py-2 flex items-center gap-2 text-xs text-emerald-700 dark:text-emerald-400">
|
|
1500
|
+
<Check className="h-3.5 w-3.5" />
|
|
1501
|
+
<span>{info.label} key saved — ready to chat</span>
|
|
1502
|
+
</div>
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
return (
|
|
1507
|
+
<div className="border-b bg-muted/30 px-3 py-2.5 space-y-1.5">
|
|
1508
|
+
<div className="flex items-center gap-1.5 text-xs font-medium">
|
|
1509
|
+
<Key className="h-3.5 w-3.5" />
|
|
1510
|
+
{info.label} API key required
|
|
1511
|
+
</div>
|
|
1512
|
+
<p className="text-[11px] text-muted-foreground">
|
|
1513
|
+
Paste your key below — stored in your browser only, sent directly to {info.label}.{' '}
|
|
1514
|
+
<a href={info.url} target="_blank" rel="noopener noreferrer" className="underline inline-flex items-center gap-0.5">
|
|
1515
|
+
Get a key <ExternalLink className="h-2.5 w-2.5" />
|
|
1516
|
+
</a>
|
|
1517
|
+
</p>
|
|
1518
|
+
<div className="flex gap-1.5">
|
|
1519
|
+
<div className="relative flex-1">
|
|
1520
|
+
<input
|
|
1521
|
+
type={show ? 'text' : 'password'}
|
|
1522
|
+
value={value}
|
|
1523
|
+
onChange={(e) => setValue(e.target.value)}
|
|
1524
|
+
onKeyDown={(e) => { if (e.key === 'Enter') handleSave(); }}
|
|
1525
|
+
placeholder={info.placeholder}
|
|
1526
|
+
autoComplete="off"
|
|
1527
|
+
spellCheck={false}
|
|
1528
|
+
className="w-full rounded border border-input bg-background px-2 py-1 text-xs font-mono focus:outline-none focus:ring-1 focus:ring-ring pr-7"
|
|
1529
|
+
/>
|
|
1530
|
+
<button
|
|
1531
|
+
type="button"
|
|
1532
|
+
onClick={() => setShow(!show)}
|
|
1533
|
+
className="absolute right-1.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
|
1534
|
+
>
|
|
1535
|
+
{show ? <EyeOff className="h-3 w-3" /> : <Eye className="h-3 w-3" />}
|
|
1536
|
+
</button>
|
|
1537
|
+
</div>
|
|
1538
|
+
<Button size="sm" className="h-7 px-3 text-xs" onClick={handleSave} disabled={!value.trim()}>
|
|
1539
|
+
Save
|
|
1540
|
+
</Button>
|
|
1541
|
+
</div>
|
|
1542
|
+
</div>
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
@@ -70,6 +70,7 @@ import { SCRIPT_TEMPLATES } from '@/lib/scripts/templates';
|
|
|
70
70
|
import { GLTFExporter, CSVExporter } from '@ifc-lite/export';
|
|
71
71
|
import { getRecentFiles, formatFileSize, getCachedFile } from '@/lib/recent-files';
|
|
72
72
|
import type { RecentFileEntry } from '@/lib/recent-files';
|
|
73
|
+
import { closeActiveAnalysisExtension } from '@/services/analysis-extensions';
|
|
73
74
|
|
|
74
75
|
// ── Types ──────────────────────────────────────────────────────────────
|
|
75
76
|
|
|
@@ -189,6 +190,8 @@ function activateRightPanel(panel: 'bcf' | 'ids' | 'lens') {
|
|
|
189
190
|
panel === 'ids' ? s.idsPanelVisible :
|
|
190
191
|
s.lensPanelVisible;
|
|
191
192
|
|
|
193
|
+
closeActiveAnalysisExtension();
|
|
194
|
+
|
|
192
195
|
// Close all content panels
|
|
193
196
|
s.setBcfPanelVisible(false);
|
|
194
197
|
s.setIdsPanelVisible(false);
|
|
@@ -211,6 +214,8 @@ function activateBottomPanel(panel: 'script' | 'list') {
|
|
|
211
214
|
const s = useViewerStore.getState();
|
|
212
215
|
const isActive = panel === 'script' ? s.scriptPanelVisible : s.listPanelVisible;
|
|
213
216
|
|
|
217
|
+
closeActiveAnalysisExtension();
|
|
218
|
+
|
|
214
219
|
// Close all bottom panels
|
|
215
220
|
s.setScriptPanelVisible(false);
|
|
216
221
|
s.setListPanelVisible(false);
|
|
@@ -270,7 +275,7 @@ export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
|
|
|
270
275
|
detail: formatFileSize(rf.size),
|
|
271
276
|
action: () => {
|
|
272
277
|
// Try loading from IndexedDB blob cache → dispatches to MainToolbar's loadFile
|
|
273
|
-
getCachedFile(
|
|
278
|
+
getCachedFile(rf).then(file => {
|
|
274
279
|
if (file) {
|
|
275
280
|
window.dispatchEvent(new CustomEvent('ifc-lite:load-file', { detail: file }));
|
|
276
281
|
} else {
|