From e0b3dbcff3380274f572841e4766c97d249cc5c1 Mon Sep 17 00:00:00 2001 From: Cam Proudlock Date: Wed, 29 Jul 2026 10:25:56 -0400 Subject: [PATCH] app installer hrefs + IIS /installers static --- deploy/windows/web.config | 35 +++++++++++++++++++ frontend/src/utils/basePath.js | 18 ++++++++++ .../frontend/views/ApplicationDetail.vue | 7 ++-- .../frontend/views/ApplicationsList.vue | 7 ++-- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/deploy/windows/web.config b/deploy/windows/web.config index 4821797c..b5b0704f 100644 --- a/deploy/windows/web.config +++ b/deploy/windows/web.config @@ -76,4 +76,39 @@ --> + + + + + + + + + + + + + + + + diff --git a/frontend/src/utils/basePath.js b/frontend/src/utils/basePath.js index b77cbbbb..a9db043d 100644 --- a/frontend/src/utils/basePath.js +++ b/frontend/src/utils/basePath.js @@ -12,6 +12,24 @@ export function withBase(path) { return BASE_URL + String(path).replace(/^\//, '') } +// Resolve a stored file/link path for use in an . Full URLs (http, +// https, file:, mailto:, ...) and UNC / protocol-relative paths (\\server, +// //host) open as-is. A path relative to the app (e.g. 'installers/x.exe' or +// './installers/x.exe') is mounted under the base so it does NOT resolve +// against the current route - '/shopdb/applications/6' + 'installers/x.exe' +// wrongly became '/shopdb/applications/installers/x.exe'. +export function fileHref(path) { + if (!path) return null + const trimmed = String(path).trim() + if (!trimmed) return null + if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) + || trimmed.startsWith('\\\\') + || trimmed.startsWith('//')) { + return trimmed + } + return withBase('/' + trimmed.replace(/^(\.?\/)+/, '')) +} + // Inverse of withBase: turn a browser pathname (which includes the mount // base, e.g. '/ops/computers') into a router path ('/computers'). Router // navigation already applies the base; feeding it an un-stripped pathname diff --git a/plugins/applications/frontend/views/ApplicationDetail.vue b/plugins/applications/frontend/views/ApplicationDetail.vue index aa5da354..833df5c0 100644 --- a/plugins/applications/frontend/views/ApplicationDetail.vue +++ b/plugins/applications/frontend/views/ApplicationDetail.vue @@ -31,13 +31,13 @@ Hidden @@ -167,6 +167,7 @@ import { useRoute } from 'vue-router' import { applicationsApi } from '@/api' import { getContactEmailDomain } from '@/utils/siteSettings' import { sanitizeNotesHtml } from '@/utils/sanitizeHtml' +import { fileHref } from '@/utils/basePath' const route = useRoute() diff --git a/plugins/applications/frontend/views/ApplicationsList.vue b/plugins/applications/frontend/views/ApplicationsList.vue index 3a7c6ec5..5116c127 100644 --- a/plugins/applications/frontend/views/ApplicationsList.vue +++ b/plugins/applications/frontend/views/ApplicationsList.vue @@ -41,15 +41,15 @@ - + ⬇ - + 🔗 - + 📄 @@ -102,6 +102,7 @@ import { ref, onMounted } from 'vue' import { applicationsApi } from '@/api' import PaginationBar from '@/components/PaginationBar.vue' import { useListQuery } from '@/composables/listQuery' +import { fileHref } from '@/utils/basePath' const applications = ref([]) const loading = ref(true)