diff --git a/web/src/lib/locales/en.ts b/web/src/lib/locales/en.ts
index f33b394f..3630d350 100644
--- a/web/src/lib/locales/en.ts
+++ b/web/src/lib/locales/en.ts
@@ -310,6 +310,7 @@ export default {
'file.page.unknownPath': 'Unknown path',
'file.page.copyPath': 'Copy path',
'file.page.copyContent': 'Copy file content',
+ 'file.page.download': 'Download file',
'file.page.tab.diff': 'Diff',
'file.page.tab.file': 'File',
'file.page.missingPath': 'No file path provided.',
diff --git a/web/src/lib/locales/zh-CN.ts b/web/src/lib/locales/zh-CN.ts
index b5e6c07b..ef48bc81 100644
--- a/web/src/lib/locales/zh-CN.ts
+++ b/web/src/lib/locales/zh-CN.ts
@@ -314,6 +314,7 @@ export default {
'file.page.unknownPath': '未知路径',
'file.page.copyPath': '复制路径',
'file.page.copyContent': '复制文件内容',
+ 'file.page.download': '下载文件',
'file.page.tab.diff': 'Diff',
'file.page.tab.file': '文件',
'file.page.missingPath': '未提供文件路径。',
diff --git a/web/src/routes/sessions/file.tsx b/web/src/routes/sessions/file.tsx
index a2327404..ab2b89d9 100644
--- a/web/src/routes/sessions/file.tsx
+++ b/web/src/routes/sessions/file.tsx
@@ -36,6 +36,44 @@ function decodePath(value: string): string {
return decoded.ok ? decoded.text : value
}
+function DownloadIcon(props: { className?: string }) {
+ return (
+
+ )
+}
+
+function triggerDownload(fileName: string, base64Content: string, mimeType: string | null) {
+ const byteChars = atob(base64Content)
+ const byteArray = new Uint8Array(byteChars.length)
+ for (let i = 0; i < byteChars.length; i++) {
+ byteArray[i] = byteChars.charCodeAt(i)
+ }
+ const blob = new Blob([byteArray], { type: mimeType ?? 'application/octet-stream' })
+ const url = URL.createObjectURL(blob)
+ const a = document.createElement('a')
+ a.href = url
+ a.download = fileName
+ document.body.appendChild(a)
+ a.click()
+ document.body.removeChild(a)
+ URL.revokeObjectURL(url)
+}
+
function BackIcon(props: { className?: string }) {
return (