diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt
index 8b1e52cef6..4c2e4d7211 100644
--- a/backend/ee-repo-ref.txt
+++ b/backend/ee-repo-ref.txt
@@ -1 +1 @@
-36158ddebc1b77f47380d6bba59d70bc6d18b653
\ No newline at end of file
+d3e20c73b06a7c6820868769a49b5fa621591653
\ No newline at end of file
diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs
index d5ac116531..0a8878fad6 100644
--- a/backend/windmill-api/src/apps.rs
+++ b/backend/windmill-api/src/apps.rs
@@ -1858,7 +1858,8 @@ async fn delete_s3_file_from_app(
let s3_client = build_object_store_client(&s3_resource).await?;
- let path = object_store::path::Path::from(file_key.as_str());
+ let path = object_store::path::Path::parse(file_key.as_str())
+ .map_err(|e| Error::internal_err(format!("Error parsing file key: {}", e)))?;
s3_client.delete(&path).await.map_err(|err| {
tracing::error!("Error deleting file: {:?}", err);
diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte
index 999c57bb26..5eac69b8be 100644
--- a/frontend/src/lib/components/DisplayResult.svelte
+++ b/frontend/src/lib/components/DisplayResult.svelte
@@ -729,7 +729,8 @@
appPath
? 'apps_u/load_image_preview/' + appPath
: 'job_helpers/load_image_preview'
- }?file_key=${result.s3}` + (result.storage ? `&storage=${result.storage}` : '')}
+ }?file_key=${encodeURIComponent(result.s3)}` +
+ (result.storage ? `&storage=${result.storage}` : '')}
/>
{:else if result?.s3?.endsWith('.pdf')}
@@ -740,7 +741,8 @@
appPath
? 'apps_u/load_image_preview/' + appPath
: 'job_helpers/load_image_preview'
- }?file_key=${result.s3}` + (result.storage ? `&storage=${result.storage}` : '')}
+ }?file_key=${encodeURIComponent(result.s3)}` +
+ (result.storage ? `&storage=${result.storage}` : '')}
/>
{/if}
@@ -798,8 +800,9 @@
{:else}
@@ -815,8 +818,9 @@
- {#if fileMetadata?.fileKey.endsWith('.png') || fileMetadata?.fileKey.endsWith('.jpg') || fileMetadata?.fileKey.endsWith('.jpeg') || fileMetadata?.fileKey.endsWith('.webp')}
-
-
-
- {:else if fileMetadata?.fileKey.endsWith('.pdf')}
-
- {:else if filePreviewLoading}
-
- File preview loading
-
- {:else if fileMetadata !== undefined && filePreview !== undefined}
-
- {#if filePreview.contentType === 'Unknown'}
- Type of file not supported for preview.
- {:else if filePreview.contentType === 'Csv'}
- Previewing a {filePreview.contentType?.toLowerCase()} file. Separator character:
-
-
- loadFilePreview(
- fileMetadata?.fileKey ?? '',
- fileMetadata?.size,
- fileMetadata?.mimeType
- )}
- >
- ,
- ;
- \t
- |
-
-
- Header row:
-
-
- loadFilePreview(
- fileMetadata?.fileKey ?? '',
- fileMetadata?.size,
- fileMetadata?.mimeType
- )}
- />
-
- {:else}
- Previewing a {filePreview.contentType?.toLowerCase()} file.
- {/if}
-
-
{#if !emptyString(filePreview.contentPreview)}{filePreview.contentPreview}{:else if filePreview.contentType !== undefined}Preview impossible.{/if}
+ {#if filePreviewLoading || fileMetadata}
+ {#if fileMetadata?.fileKey.endsWith('.png') || fileMetadata?.fileKey.endsWith('.jpg') || fileMetadata?.fileKey.endsWith('.jpeg') || fileMetadata?.fileKey.endsWith('.webp')}
+
+
+
+ {:else if fileMetadata?.fileKey.endsWith('.pdf')}
+
+ {:else if filePreviewLoading}
+
+ File preview loading
+
+ {:else if fileMetadata !== undefined && filePreview !== undefined}
+
+ {#if filePreview.contentType === 'Unknown'}
+ Type of file not supported for preview.
+ {:else if filePreview.contentType === 'Csv'}
+ Previewing a {filePreview.contentType?.toLowerCase()} file. Separator character:
+
+
+ loadFilePreview(
+ fileMetadata?.fileKey ?? '',
+ fileMetadata?.size,
+ fileMetadata?.mimeType
+ )}
+ >
+ ,
+ ;
+ \t
+ |
+
+
+ Header row:
+
+
+ loadFilePreview(
+ fileMetadata?.fileKey ?? '',
+ fileMetadata?.size,
+ fileMetadata?.mimeType
+ )}
+ />
+
+ {:else}
+ Previewing a {filePreview.contentType?.toLowerCase()} file.
+ {/if}
+
+ {#if !emptyString(filePreview.contentPreview)}{filePreview.contentPreview}{:else if filePreview.contentType !== undefined}Preview impossible.{/if}
+ {/if}
{/if}
@@ -812,7 +832,7 @@
uploadModalOpen = false
if (evt.detail !== undefined && evt.detail !== null) {
selectedFileKey = { s3: evt.detail }
- loadFiles()
+ await clearAndLoadFiles()
loadFileMetadataPlusPreviewAsync(evt.detail)
}
}}
diff --git a/frontend/src/lib/components/apps/components/helpers/eval.ts b/frontend/src/lib/components/apps/components/helpers/eval.ts
index 3e6b5cc522..bb737040bd 100644
--- a/frontend/src/lib/components/apps/components/helpers/eval.ts
+++ b/frontend/src/lib/components/apps/components/helpers/eval.ts
@@ -3,7 +3,11 @@ import { sendUserToast } from '$lib/toast'
import { waitJob } from '$lib/components/waitJob'
import { base } from '$lib/base'
-export function computeGlobalContext(world: World | undefined, id: string | undefined, extraContext: any = {}) {
+export function computeGlobalContext(
+ world: World | undefined,
+ id: string | undefined,
+ extraContext: any = {}
+) {
return {
...Object.fromEntries(
Object.entries(world?.outputsById ?? {})
@@ -29,15 +33,17 @@ function create_context_function_template(
return `
return async function (context, state, createProxy, goto, setTab, recompute, globalRecompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, showToast, waitJob, askNewResource, downloadFile) {
"use strict";
-${contextKeys && contextKeys.length > 0
- ? `let ${contextKeys.map((key) => ` ${key} = createProxy('${key}', context['${key}'])`)};`
- : ``
- }
-${hasReturnAsLastLine
- ? eval_string
- : `
+${
+ contextKeys && contextKeys.length > 0
+ ? `let ${contextKeys.map((key) => ` ${key} = createProxy('${key}', context['${key}'])`)};`
+ : ``
+}
+${
+ hasReturnAsLastLine
+ ? eval_string
+ : `
return ${eval_string.startsWith('return ') ? eval_string.substring(7) : eval_string}`
- }
+}
}
`
@@ -278,9 +284,9 @@ export async function eval_like(
if (typeof input === 'object' && input.s3) {
const workspaceId = ((context ?? {}) as any).ctx?.workspace
- const s3href = `${base}/api/w/${workspaceId}/job_helpers/download_s3_file?file_key=${
- input?.s3
- }${input?.storage ? `&storage=${input.storage}` : ''}`
+ const s3href = `${base}/api/w/${workspaceId}/job_helpers/download_s3_file?file_key=${encodeURIComponent(
+ input?.s3 ?? ''
+ )}${input?.storage ? `&storage=${input.storage}` : ''}`
downloadFile(s3href, filename || input.s3)
} else if (typeof input === 'string') {
if (input.startsWith('data:')) {
diff --git a/frontend/src/lib/components/common/fileDownload/FileDownload.svelte b/frontend/src/lib/components/common/fileDownload/FileDownload.svelte
index 2c80eea7ef..519acbb1d9 100644
--- a/frontend/src/lib/components/common/fileDownload/FileDownload.svelte
+++ b/frontend/src/lib/components/common/fileDownload/FileDownload.svelte
@@ -15,7 +15,9 @@ focus-within:border-blue-500 hover:bg-blue-50 dark:hover:bg-frost-900 focus-with
duration-200 rounded-lg p-1 gap-2"
href={`${base}/api/w/${workspaceId ?? $workspaceStore}${
appPath ? `/apps_u/download_s3_file/${appPath}` : '/job_helpers/download_s3_file'
- }?file_key=${s3object?.s3}${s3object?.storage ? `&storage=${s3object.storage}` : ''}`}
+ }?file_key=${encodeURIComponent(s3object?.s3 ?? '')}${
+ s3object?.storage ? `&storage=${s3object.storage}` : ''
+ }`}
download={s3object?.s3.split('/').pop() ?? 'unnamed_download.file'}
>