applications: fix relative installer/link hrefs + serve /installers via IIS
Some checks failed
CI / backend (push) Failing after 1m53s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 8s
CI / migrations-mysql (push) Failing after 9s

Two problems with application download/launch/doc links:

1. Stored paths like 'installers/Foo.exe' are relative, so an <a href> on
   /shopdb/applications/6 resolved to /shopdb/applications/installers/Foo.exe.
   New basePath.fileHref() mounts a relative path under the app base
   (-> /shopdb/installers/Foo.exe) while leaving full URLs and UNC/file paths
   untouched. Applied to installpath, applicationlink, and documentationpath in
   the list and detail views.

2. Even the correct /shopdb/installers/Foo.exe 404s: httpPlatformHandler is
   path="*", so IIS forwards it to Flask, which has no such route. Add a
   web.config <location path="installers"> that clears the handler and serves
   that subpath as IIS static (with .exe/.msi MIME), from a physical
   APP_ROOT\installers folder.
This commit is contained in:
cproudlock
2026-07-29 10:25:46 -04:00
parent 071d40488b
commit 1ee9328bf9
4 changed files with 61 additions and 6 deletions

View File

@@ -12,6 +12,24 @@ export function withBase(path) {
return BASE_URL + String(path).replace(/^\//, '')
}
// Resolve a stored file/link path for use in an <a href>. 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