diff --git a/frontend/src/lib/components/apps/components/display/AppDownload.svelte b/frontend/src/lib/components/apps/components/display/AppDownload.svelte index ef2822f32f..9af424ebed 100644 --- a/frontend/src/lib/components/apps/components/display/AppDownload.svelte +++ b/frontend/src/lib/components/apps/components/display/AppDownload.svelte @@ -109,7 +109,8 @@ color={resolvedConfig.color} download={resolvedConfig.filename} href={transformBareBase64IfNecessary(resolvedConfig.source)} - target="_self" + target="_blank" + ref="external" nonCaptureEvent > diff --git a/frontend/src/lib/components/apps/components/helpers/eval.ts b/frontend/src/lib/components/apps/components/helpers/eval.ts index 5ef7e6b0bb..ede329350b 100644 --- a/frontend/src/lib/components/apps/components/helpers/eval.ts +++ b/frontend/src/lib/components/apps/components/helpers/eval.ts @@ -243,7 +243,10 @@ export async function eval_like( (input, filename) => { const handleError = (error) => { console.error('Error downloading file:', error) - sendUserToast(`Error downloading file: ${error.message}. Ensure it is a valid URL, a base64 encoded data URL (data:...), or a valid S3 object.`, true) + sendUserToast( + `Error downloading file: ${error.message}. Ensure it is a valid URL, a base64 encoded data URL (data:...), or a valid S3 object.`, + true + ) } const isBase64 = (str) => { @@ -255,9 +258,12 @@ export async function eval_like( } const downloadFile = (url, downloadFilename) => { + console.log(url, downloadFilename) const link = document.createElement('a') link.href = url - link.download = downloadFilename || 'download' + link.download = downloadFilename || true + link.target = '_blank' + link.rel = 'external' document.body.appendChild(link) link.click() document.body.removeChild(link) @@ -265,10 +271,10 @@ export async function eval_like( if (typeof input === 'object' && input.s3) { const workspaceId = computeGlobalContext(worldStore).ctx.workspace - const s3href = `${base}/api/w/${workspaceId}/job_helpers/download_s3_file?file_key=${input?.s3}${ - input?.storage ? `&storage=${input.storage}` : '' - }` - downloadFile(s3href, filename || input.s3); + const s3href = `${base}/api/w/${workspaceId}/job_helpers/download_s3_file?file_key=${ + input?.s3 + }${input?.storage ? `&storage=${input.storage}` : ''}` + downloadFile(s3href, filename || input.s3) } else if (typeof input === 'string') { if (input.startsWith('data:')) { downloadFile(input, filename) @@ -277,26 +283,19 @@ export async function eval_like( downloadFile(base64Url, filename) } else if (/^(http|https):\/\//.test(input) || input.startsWith('/')) { const url = input.startsWith('/') ? `${window.location.origin}${input}` : input - fetch(url) - .then(response => { - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - return response.blob() - }) - .then(blob => { - const objectUrl = URL.createObjectURL(blob) - const urlParts = input.split('/') - const inferredFilename = urlParts[urlParts.length - 1] - downloadFile(objectUrl, filename || inferredFilename) - URL.revokeObjectURL(objectUrl) - }) - .catch(handleError) + console.log('Downloading file from:', url) + downloadFile(url, filename ?? url.split('/').pop()?.split('?')[0]) } else { - handleError(new Error('The input must be a valid URL, a base64 encoded string, or a valid S3 object.')) + handleError( + new Error( + 'The input must be a valid URL, a base64 encoded string, or a valid S3 object.' + ) + ) } } else { - handleError(new Error('The input must be a string or an object with a getAuthenticatedUrl method.')) + handleError( + new Error('The input must be a string or an object with a getAuthenticatedUrl method.') + ) } } ) diff --git a/frontend/src/lib/components/apps/utils.ts b/frontend/src/lib/components/apps/utils.ts index 34310efab9..cb30aac94f 100644 --- a/frontend/src/lib/components/apps/utils.ts +++ b/frontend/src/lib/components/apps/utils.ts @@ -458,6 +458,9 @@ export function transformBareBase64IfNecessary(source: string | undefined) { if (!source) { return source } + if (/^(http|https):\/\//.test(source) || source.startsWith('/')) { + return source + } if (source.startsWith('data:') || source.includes(',')) { return source } else {