From 02a77747229021b0ab6650412719c0fe0d0494c1 Mon Sep 17 00:00:00 2001
From: Mr_chank
Date: Sat, 16 May 2026 00:58:26 +1000
Subject: [PATCH] fix: add download attribute to fix JAR files saving as ZIP in
Chromium (#6065)
* fix: add download attribute to fix JAR files saving as ZIP in Chromium
- JAR files were downloading with a `.zip` extension in Chromium-based browsers (Chrome, Edge, Arc, Brave, Opera, Vivaldi)
- Root cause: JAR files are ZIP archives internally, so Chromium sniffs the `Content-Type` as `application/zip` and overrides the filename extension when no `download` attribute is present
- Fix: add `download=""` to all file download `` tags so the browser uses the original filename from the API
* fix: add download attribute to remaining download links
Missed in initial pass: changelog page button, versions overflow
menu, settings/versions overflow menu. Also adds `download` prop
to Button and OverflowMenu to support dropdown link items.
Adds missing `getPrimaryFile` definition in changelog.vue.
---------
Co-authored-by: Mr_chank <180248271+chank-op@users.noreply.github.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
---
.../frontend/src/pages/[type]/[id]/changelog.vue | 1 +
.../src/pages/[type]/[id]/settings/versions.vue | 1 +
.../src/pages/[type]/[id]/version/[version].vue | 2 ++
apps/frontend/src/pages/[type]/[id]/versions.vue | 2 ++
packages/ui/src/components/base/Button.vue | 5 +++++
packages/ui/src/components/base/OverflowMenu.vue | 2 ++
.../ui/src/components/version/VersionSummary.vue | 16 +++++++++++++---
7 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/apps/frontend/src/pages/[type]/[id]/changelog.vue b/apps/frontend/src/pages/[type]/[id]/changelog.vue
index e6974b6d1..cd85b5cac 100644
--- a/apps/frontend/src/pages/[type]/[id]/changelog.vue
+++ b/apps/frontend/src/pages/[type]/[id]/changelog.vue
@@ -57,6 +57,7 @@
diff --git a/apps/frontend/src/pages/[type]/[id]/settings/versions.vue b/apps/frontend/src/pages/[type]/[id]/settings/versions.vue
index 7176020d3..4d1e11ebc 100644
--- a/apps/frontend/src/pages/[type]/[id]/settings/versions.vue
+++ b/apps/frontend/src/pages/[type]/[id]/settings/versions.vue
@@ -111,6 +111,7 @@
color: 'primary',
hoverFilled: true,
link: createDownloadUrl(version),
+ download: getPrimaryFile(version).filename,
action: () => {
emit('onDownload')
},
diff --git a/apps/frontend/src/pages/[type]/[id]/version/[version].vue b/apps/frontend/src/pages/[type]/[id]/version/[version].vue
index 52fdc553a..68a10f682 100644
--- a/apps/frontend/src/pages/[type]/[id]/version/[version].vue
+++ b/apps/frontend/src/pages/[type]/[id]/version/[version].vue
@@ -140,6 +140,7 @@
@@ -307,6 +308,7 @@
:href="decorateDownloadUrl(file.url)"
class="raised-button"
:title="`Download ${file.filename}`"
+ :download="file.filename"
tabindex="0"
>
diff --git a/apps/frontend/src/pages/[type]/[id]/versions.vue b/apps/frontend/src/pages/[type]/[id]/versions.vue
index 169494773..75996265a 100644
--- a/apps/frontend/src/pages/[type]/[id]/versions.vue
+++ b/apps/frontend/src/pages/[type]/[id]/versions.vue
@@ -47,6 +47,7 @@
{
emit('onDownload')
},
diff --git a/packages/ui/src/components/base/Button.vue b/packages/ui/src/components/base/Button.vue
index 22f8b4cf5..48416b4f5 100644
--- a/packages/ui/src/components/base/Button.vue
+++ b/packages/ui/src/components/base/Button.vue
@@ -11,6 +11,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
+ download: {
+ type: String,
+ default: null,
+ },
action: {
type: Function,
default: null,
@@ -106,6 +110,7 @@ const classes = computed(() => {
class="btn"
:class="classes"
:href="disabled ? undefined : link"
+ :download="download || undefined"
:target="external ? '_blank' : '_self'"
@click="
(event) => {
diff --git a/packages/ui/src/components/base/OverflowMenu.vue b/packages/ui/src/components/base/OverflowMenu.vue
index f0949a3a9..92db08c3c 100644
--- a/packages/ui/src/components/base/OverflowMenu.vue
+++ b/packages/ui/src/components/base/OverflowMenu.vue
@@ -36,6 +36,7 @@
: undefined
"
:link="option.link ? option.link : undefined"
+ :download="option.download ? option.download : undefined"
:external="option.external ? option.external : false"
:disabled="option.disabled"
@click="
@@ -76,6 +77,7 @@ interface Item extends BaseOption {
icon?: Component
action?: (event?: MouseEvent) => void
link?: string
+ download?: string
external?: boolean
color?:
| 'primary'
diff --git a/packages/ui/src/components/version/VersionSummary.vue b/packages/ui/src/components/version/VersionSummary.vue
index a14e0ac02..8e26a8ea1 100644
--- a/packages/ui/src/components/version/VersionSummary.vue
+++ b/packages/ui/src/components/version/VersionSummary.vue
@@ -12,7 +12,12 @@
-
+
Download
@@ -42,12 +47,17 @@ const props = defineProps<{
decorateDownloadUrl?: (url: string) => string
}>()
+const primaryFile = computed(
+ () => props.version.files.find((x) => x.primary) || props.version.files[0],
+)
+
const downloadUrl = computed(() => {
- const primary: VersionFile = props.version.files.find((x) => x.primary) || props.version.files[0]
- const raw = primary.url
+ const raw = primaryFile.value.url
return props.decorateDownloadUrl ? props.decorateDownloadUrl(raw) : raw
})
+const primaryFilename = computed(() => primaryFile.value.filename)
+
const emit = defineEmits<{
onDownload: []
onNavigate: [url: string]