route result and args downloads through downloadViaClient (#9122)

* fix(frontend): route result and args downloads through downloadViaClient

* refactor(frontend): reuse argsApiPath in WINDMILL_TOO_BIG branch
This commit is contained in:
Ruben Fiszel
2026-05-12 11:48:42 +00:00
committed by GitHub
parent 07a4cb6872
commit 0bb77a9bd6
2 changed files with 73 additions and 35 deletions
@@ -3,6 +3,7 @@
import { Download, InfoIcon, ClipboardCopy, Expand } from 'lucide-svelte'
import Popover from './Popover.svelte'
import { copyToClipboard } from '$lib/utils'
import { downloadViaClient, shouldDownloadViaClient } from '$lib/utils/downloadFile'
import type { DisplayResultUi } from './custom_ui'
import { createEventDispatcher } from 'svelte'
@@ -37,21 +38,38 @@
return 'error stringifying object: ' + e.toString()
}
}
let resultApiPath = $derived(
workspaceId && jobId
? nodeId
? `/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}`
: `/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
: undefined
)
let downloadName = $derived(`${filename ?? 'result'}.json`)
</script>
<div class={twMerge('flex flex-row gap-2.5 z-10 text-primary -mt-1 items-center')}>
{#if customUi?.disableDownload !== true}
<a
download="{filename ?? 'result'}.json"
class="text-current"
href={workspaceId && jobId
? nodeId
? `${base}/api/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}`
: `${base}/api/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
: `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
>
<Download size={14} />
</a>
{#if resultApiPath && shouldDownloadViaClient()}
<button
class="text-current"
onclick={() => downloadViaClient(resultApiPath!, downloadName)}
aria-label="Download result"
>
<Download size={14} />
</button>
{:else}
<a
download={downloadName}
class="text-current"
href={resultApiPath
? `${base}/api${resultApiPath}`
: `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
>
<Download size={14} />
</a>
{/if}
{/if}
{#if disableTooltips !== true}
<Popover documentationLink="https://www.windmill.dev/docs/core_concepts/rich_display_rendering">
+44 -24
View File
@@ -13,6 +13,7 @@
import HighlightTheme from './HighlightTheme.svelte'
import { deepEqual } from 'fast-equals'
import { isWindmillTooBigObject } from './job_args'
import { downloadViaClient, shouldDownloadViaClient } from '$lib/utils/downloadFile'
interface Props {
id?: string | undefined
@@ -27,6 +28,10 @@
let runLocally: Drawer | undefined = $state()
let jsonStr = $state('')
const argsDownloadName = 'windmill-args.json'
let argsApiPath = $derived(id && workspace ? `/w/${workspace}/jobs_u/get_args/${id}` : undefined)
let argsDataHref = $derived(`data:text/json;charset=utf-8,${encodeURIComponent(jsonStr)}`)
function pythonCode() {
return `
if __name__ == "__main__":
@@ -60,10 +65,12 @@ ${Object.entries(args)
{#if args && typeof args === 'object' && deepEqual( Object.keys(args ?? {}), ['reason'] ) && args['reason'] == 'PREPROCESSOR_ARGS_ARE_DISCARDED'}
Preprocessor args are discarded
{:else if id && workspace && args && typeof args === 'object' && deepEqual( Object.keys(args ?? {}), ['reason'] ) && args['reason'] == 'WINDMILL_TOO_BIG'}
The args are too big in size to be able to fetch alongside job. Please <a
href="/api/w/{workspace}/jobs_u/get_args/{id}"
target="_blank">download the JSON file to view them</a
>.
The args are too big in size to be able to fetch alongside job. Please {#if shouldDownloadViaClient()}<button
class="text-blue-500 hover:underline"
onclick={() => downloadViaClient(argsApiPath!, argsDownloadName)}
>download the JSON file to view them</button
>{:else}<a href="/api{argsApiPath}" target="_blank">download the JSON file to view them</a
>{/if}.
{:else}
<div class="relative">
<DataTable size="sm" containerClass="bg-surface-tertiary">
@@ -120,17 +127,26 @@ ${Object.entries(args)
<Drawer bind:this={jsonViewer} size="900px">
<DrawerContent title="Expanded Args" on:close={jsonViewer.closeDrawer}>
{#snippet actions()}
<Button
download="windmill-args.json"
href={id && workspace
? `/api/w/${workspace}/jobs_u/get_args/${id}`
: `data:text/json;charset=utf-8,${encodeURIComponent(jsonStr)}`}
startIcon={{ icon: Download }}
size="xs"
color="light"
>
Download
</Button>
{#if argsApiPath && shouldDownloadViaClient()}
<Button
on:click={() => downloadViaClient(argsApiPath!, argsDownloadName)}
startIcon={{ icon: Download }}
size="xs"
color="light"
>
Download
</Button>
{:else}
<Button
download={argsDownloadName}
href={argsApiPath ? `/api${argsApiPath}` : argsDataHref}
startIcon={{ icon: Download }}
size="xs"
color="light"
>
Download
</Button>
{/if}
<Button
on:click={() => runLocally?.openDrawer()}
color="light"
@@ -150,15 +166,19 @@ ${Object.entries(args)
{/snippet}
{#if jsonStr.length > 100000 || (id && workspace && args && isWindmillTooBigObject(args))}
<div class="text-sm mb-2 text-primary">
<a
download="windmill-args.json"
href={id && workspace
? `/api/w/${workspace}/jobs_u/get_args/${id}`
: `data:text/json;charset=utf-8,${encodeURIComponent(jsonStr)}`}
>
JSON is too large to be displayed in full.
</a></div
>
{#if argsApiPath && shouldDownloadViaClient()}
<button
class="underline"
onclick={() => downloadViaClient(argsApiPath!, argsDownloadName)}
>
JSON is too large to be displayed in full.
</button>
{:else}
<a download={argsDownloadName} href={argsApiPath ? `/api${argsApiPath}` : argsDataHref}>
JSON is too large to be displayed in full.
</a>
{/if}
</div>
{:else}
<Highlight language={json} code={jsonStr.replace(/\\n/g, '\n')} />
{/if}