diff --git a/assets/licenses.txt b/assets/licenses.txt index 405643e..1ee7f72 100644 --- a/assets/licenses.txt +++ b/assets/licenses.txt @@ -211,12 +211,11 @@ Apache License ----------- -The following npm packages may be included in this product: +The following npm package may be included in this product: - - source-map-js@1.2.0 - source-map-js@1.2.1 -These packages each contain the following license: +This package contains the following license: Copyright (c) 2009-2011, Mozilla Foundation and contributors All rights reserved. @@ -778,11 +777,13 @@ The above copyright notice and this permission notice shall be included in all c ----------- -The following npm package may be included in this product: +The following npm packages may be included in this product: - - sharp@0.33.4 + - @img/sharp-linux-x64@0.33.5 + - @img/sharp-linuxmusl-x64@0.33.5 + - sharp@0.33.5 -This package contains the following license: +These packages each contain the following license: Apache License Version 2.0, January 2004 @@ -980,7 +981,7 @@ third-party archives. The following npm package may be included in this product: - - typescript@5.6.3 + - typescript@5.7.2 This package contains the following license: @@ -1120,7 +1121,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The following npm package may be included in this product: - - @lit-labs/ssr-dom-shim@1.2.0 + - @lit-labs/ssr-dom-shim@1.2.1 This package contains the following license: @@ -1246,7 +1247,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following npm package may be included in this product: - - @babel/parser@7.25.3 + - @babel/parser@7.26.3 This package contains the following license: @@ -1366,7 +1367,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The following npm package may be included in this product: - - magic-string@0.30.11 + - magic-string@0.30.17 This package contains the following license: @@ -1404,30 +1405,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ----------- -The following npm package may be included in this product: +The following npm packages may be included in this product: - - to-fast-properties@2.0.0 + - @img/sharp-libvips-linux-x64@1.0.4 + - @img/sharp-libvips-linuxmusl-x64@1.0.4 -This package contains the following license: +These packages each contain the following license: -MIT License - -Copyright (c) 2014 Petka Antonov - 2015 Sindre Sorhus - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +LGPL-3.0-or-later ----------- The following npm packages may be included in this product: - - @babel/helper-string-parser@7.24.8 - - @babel/helper-validator-identifier@7.24.7 - - @babel/types@7.25.2 + - @babel/helper-string-parser@7.25.9 + - @babel/helper-validator-identifier@7.25.9 + - @babel/types@7.26.3 These packages each contain the following license: @@ -1518,7 +1511,7 @@ SOFTWARE. The following npm package may be included in this product: - - @monogrid/gainmap-js@3.0.3 + - @monogrid/gainmap-js@3.1.0 This package contains the following license: @@ -1608,7 +1601,7 @@ The MIT license applies to all non-font and non-icon files. The following npm package may be included in this product: - - semver@7.6.2 + - semver@7.6.3 This package contains the following license: @@ -1692,7 +1685,7 @@ THE SOFTWARE. The following npm package may be included in this product: - - three@0.169.0 + - three@0.171.0 This package contains the following license: @@ -1782,7 +1775,7 @@ THE SOFTWARE. The following npm package may be included in this product: - - vuetify@3.7.4 + - vuetify@3.7.6 This package contains the following license: @@ -1913,9 +1906,9 @@ SOFTWARE. The following npm packages may be included in this product: - - @gltf-transform/core@4.1.0 - - @gltf-transform/extensions@4.1.0 - - @gltf-transform/functions@4.1.0 + - @gltf-transform/core@4.1.1 + - @gltf-transform/extensions@4.1.1 + - @gltf-transform/functions@4.1.1 These packages each contain the following license: @@ -2004,7 +1997,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following npm package may be included in this product: - - nanoid@3.3.7 + - nanoid@3.3.8 This package contains the following license: diff --git a/frontend/App.vue b/frontend/App.vue index 73589b4..d757e7a 100644 --- a/frontend/App.vue +++ b/frontend/App.vue @@ -52,10 +52,11 @@ async function onModelUpdateRequest(event: NetworkUpdateEvent) { let model = event.models[modelIndex]; tools.value?.removeObjectSelections(model.name); try { + let loadHelpers = (await settings()).loadHelpers; if (!model.isRemove) { - doc = await SceneMgr.loadModel(sceneUrl, doc, model.name, model.url, isLast && settings.loadHelpers, isLast); + doc = await SceneMgr.loadModel(sceneUrl, doc, model.name, model.url, isLast && loadHelpers, isLast); } else { - doc = await SceneMgr.removeModel(sceneUrl, doc, model.name, isLast && settings.loadHelpers, isLast); + doc = await SceneMgr.removeModel(sceneUrl, doc, model.name, isLast && loadHelpers, isLast); } } catch (e) { console.error("Error loading model", model, e); @@ -79,16 +80,18 @@ let networkMgr = new NetworkManager(); networkMgr.addEventListener('update-early', (e) => viewer.value?.onProgress((e as CustomEvent>).detail.length * 0.01)); networkMgr.addEventListener('update', (e) => onModelUpdateRequest(e as NetworkUpdateEvent)); -// Start loading all configured models ASAP -for (let model of settings.preload) { - networkMgr.load(model); -} -watch(viewer, (newViewer) => { - if (newViewer) { - newViewer.setPosterText('Trying to load' + - ' models from:' + settings.preload.map((url) => '- ' + url + '').join("")); +(async () => { // Start loading all configured models ASAP + let sett = await settings(); + watch(viewer, (newViewer) => { + if (newViewer) { + newViewer.setPosterText('Trying to load' + + ' models from:' + sett.preload.map((url: string) => '- ' + url + '').join("")); + } + }); + for (let model of sett.preload) { + await networkMgr.load(model); } -}); +})(); async function loadModelManual() { const modelUrl = prompt("For an improved experience in viewing CAD/GLTF models with automatic updates, it's recommended to use the official yacv_server Python package. This ensures seamless serving of models and automatic updates.\n\nOtherwise, enter the URL of the model to load:"); diff --git a/frontend/misc/network.ts b/frontend/misc/network.ts index c4bcbcb..b31fa84 100644 --- a/frontend/misc/network.ts +++ b/frontend/misc/network.ts @@ -61,6 +61,7 @@ export class NetworkManager extends EventTarget { private async monitorDevServer(url: URL, stop: () => boolean = () => false) { while (!stop()) { + let monitorEveryMs = (await settings()).monitorEveryMs; try { // WARNING: This will spam the console logs with failed requests when the server is down const controller = new AbortController(); @@ -82,12 +83,12 @@ export class NetworkManager extends EventTarget { } } else { // Server is down, wait a little longer before retrying - await new Promise(resolve => setTimeout(resolve, 10 * settings.monitorEveryMs)); + await new Promise(resolve => setTimeout(resolve, 10 * monitorEveryMs)); } controller.abort(); } catch (e) { // Ignore errors (retry very soon) } - await new Promise(resolve => setTimeout(resolve, settings.monitorEveryMs)); + await new Promise(resolve => setTimeout(resolve, monitorEveryMs)); } } diff --git a/frontend/misc/settings.ts b/frontend/misc/settings.ts index 98e0500..0a37825 100644 --- a/frontend/misc/settings.ts +++ b/frontend/misc/settings.ts @@ -1,35 +1,66 @@ // These are the default values for the settings, which are overridden below -export const settings = { - preload: [ - // @ts-ignore - // new URL('../../assets/fox.glb', import.meta.url).href, - // @ts-ignore - // new URL('../../assets/logo_build/base.glb', import.meta.url).href, - // @ts-ignore - // new URL('../../assets/logo_build/location.glb', import.meta.url).href, - // @ts-ignore - // new URL('../../assets/logo_build/img.jpg.glb', import.meta.url).href, - // Websocket URLs automatically listen for new models from the python backend - '', // Get the default preload URL if not overridden - ], - loadHelpers: true, - edgeWidth: 0, /* The default line size for edges, set to 0 to use basic gl.LINEs */ - displayLoadingEveryMs: 1000, /* How often to display partially loaded models */ - monitorEveryMs: 100, - monitorOpenTimeoutMs: 1000, - // ModelViewer settings - autoplay: true, // Global animation toggle - arModes: 'webxr scene-viewer quick-look', - zoomSensitivity: 0.25, - orbitSensitivity: 1, - panSensitivity: 1, - exposure: 1, - shadowIntensity: 0, - background: '', +let settingsCache: any = null; + +export async function settings() { + if (settingsCache !== null) return settingsCache; + let settings = { + preload: [ + // @ts-ignore + // new URL('../../assets/fox.glb', import.meta.url).href, + // @ts-ignore + // new URL('../../assets/logo_build/base.glb', import.meta.url).href, + // @ts-ignore + // new URL('../../assets/logo_build/location.glb', import.meta.url).href, + // @ts-ignore + // new URL('../../assets/logo_build/img.jpg.glb', import.meta.url).href, + // Websocket URLs automatically listen for new models from the python backend + '', // Get the default preload URL if not overridden + ], + loadHelpers: true, + edgeWidth: 0, /* The default line size for edges, set to 0 to use basic gl.LINEs */ + displayLoadingEveryMs: 1000, /* How often to display partially loaded models */ + monitorEveryMs: 100, + monitorOpenTimeoutMs: 1000, + // ModelViewer settings + autoplay: true, // Global animation toggle + arModes: 'webxr scene-viewer quick-look', + zoomSensitivity: 0.25, + orbitSensitivity: 1, + panSensitivity: 1, + exposure: 1, + shadowIntensity: 0, + background: '', + }; + + // Auto-override any settings from the URL + const url = new URL(window.location.href); + url.searchParams.forEach((value, key) => { + if (key in settings) (settings as any)[key] = parseSetting(key, value, settings); + }) + + // Get the default preload URL if not overridden (requires a fetch that is avoided if possible) + for (let i = 0; i < settings.preload.length; i++) { + let url = settings.preload[i]; + if (url === '') { + const possibleBackend = new URL("./?api_updates=true", window.location.href) + await fetch(possibleBackend, {method: "HEAD"}).then((response) => { + if (response.ok && response.headers.get("Content-Type") === "text/event-stream") { + // Frontend served by the backend: default to this URL for updates + url = "dev+" + possibleBackend.href; + } + }).catch((error) => console.error("Failed to check for backend:", error)); + if (url === '') { // Fallback to the default preload URL of localhost + url = "dev+http://localhost:32323"; + } + } + settings.preload[i] = url; + } + settingsCache = settings; + return settings; } const firstTimeNames: Array = []; // Needed for array values, which clear the array when overridden -function parseSetting(name: string, value: string): any { +function parseSetting(name: string, value: string, settings: any): any { let arrayElem = name.endsWith(".0") if (arrayElem) name = name.slice(0, -2); let prevValue = (settings as any)[name]; @@ -42,7 +73,7 @@ function parseSetting(name: string, value: string): any { } else { toExtend = prevValue; } - toExtend.push(parseSetting(name + ".0", value)); + toExtend.push(parseSetting(name + ".0", value, settings)); return toExtend; } else { prevValue = prevValue[0]; @@ -59,27 +90,3 @@ function parseSetting(name: string, value: string): any { throw new Error(`Unknown setting type: ${typeof prevValue} -- ${prevValue}`); } } - -// Auto-override any settings from the URL -const url = new URL(window.location.href); -url.searchParams.forEach((value, key) => { - if (key in settings) (settings as any)[key] = parseSetting(key, value); -}) - -// Get the default preload URL if not overridden (requires a fetch that is avoided if possible) -for (let i = 0; i < settings.preload.length; i++) { - let url = settings.preload[i]; - if (url === '') { - const possibleBackend = new URL("./?api_updates=true", window.location.href) - await fetch(possibleBackend, {method: "HEAD"}).then((response) => { - if (response.ok && response.headers.get("Content-Type") === "text/event-stream") { - // Frontend served by the backend: default to this URL for updates - url = "dev+" + possibleBackend.href; - } - }).catch((error) => console.error("Failed to check for backend:", error)); - if (url === '') { // Fallback to the default preload URL of localhost - url = "dev+http://localhost:32323"; - } - } - settings.preload[i] = url; -} diff --git a/frontend/models/Model.vue b/frontend/models/Model.vue index db143c1..f9daa6c 100644 --- a/frontend/models/Model.vue +++ b/frontend/models/Model.vue @@ -55,7 +55,11 @@ const clipPlaneY = ref(1); const clipPlaneSwappedY = ref(false); const clipPlaneZ = ref(1); const clipPlaneSwappedZ = ref(false); -const edgeWidth = ref(settings.edgeWidth); +const edgeWidth = ref(0); +(async () => { + let s = await settings(); + edgeWidth.value = s.edgeWidth; +})(); // Misc properties const enabledFeatures = defineModel>("enabledFeatures", {default: [0, 1, 2]}); diff --git a/frontend/tools/Selection.vue b/frontend/tools/Selection.vue index cf90f56..73f6386 100644 --- a/frontend/tools/Selection.vue +++ b/frontend/tools/Selection.vue @@ -1,5 +1,5 @@