fix(frontend): add warning when integer number if too big for frontend (#5340)
This commit is contained in:
@@ -76,6 +76,7 @@
|
||||
| 'pdf'
|
||||
| undefined
|
||||
|
||||
let hasBigInt = false
|
||||
$: resultKind = inferResultKind(result)
|
||||
|
||||
export let forceJson = false
|
||||
@@ -168,6 +169,13 @@
|
||||
largeObject = size > DISPLAY_MAX_SIZE
|
||||
}
|
||||
|
||||
if (!largeObject) {
|
||||
hasBigInt = checkIfHasBigInt(result)
|
||||
if (hasBigInt) {
|
||||
return 'json'
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
if (result.length === 0) {
|
||||
return 'json'
|
||||
@@ -263,6 +271,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfHasBigInt(result: any) {
|
||||
if (typeof result === 'number' && Number.isInteger(result) && !Number.isSafeInteger(result)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
return result.some(checkIfHasBigInt)
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object') {
|
||||
return Object.values(result).some(checkIfHasBigInt)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function contentOrRootString(obj: string | { filename: string; content: string } | undefined) {
|
||||
if (obj == undefined || obj == null) {
|
||||
return ''
|
||||
@@ -401,14 +424,17 @@
|
||||
/>
|
||||
{/each}</div
|
||||
>
|
||||
{:else if resultKind === 'nondisplayable'}<div class="text-red-400">Non displayable object</div
|
||||
>{:else}<div
|
||||
{:else if resultKind === 'nondisplayable'}
|
||||
<div class="text-red-400">Non displayable object</div>
|
||||
{:else}
|
||||
<div
|
||||
class="inline-highlight relative grow {['plain', 'markdown'].includes(resultKind ?? '')
|
||||
? ''
|
||||
: 'min-h-[160px]'}"
|
||||
>{#if result != undefined && length != undefined && largeObject != undefined}<div
|
||||
class="flex justify-between items-center w-full"
|
||||
><div class="text-tertiary text-sm">
|
||||
>
|
||||
{#if result != undefined && length != undefined && largeObject != undefined}
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<div class="text-tertiary text-sm flex flex-row gap-2 items-center">
|
||||
{#if !hideAsJson && !['json', 's3object'].includes(resultKind ?? '') && typeof result === 'object'}<ToggleButtonGroup
|
||||
class="h-6"
|
||||
selected={forceJson ? 'json' : resultKind?.startsWith('table-') ? 'table' : 'pretty'}
|
||||
@@ -458,8 +484,9 @@
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div><div class="grow"
|
||||
>{#if !forceJson && resultKind === 'table-col'}
|
||||
</div>
|
||||
<div class="grow">
|
||||
{#if !forceJson && resultKind === 'table-col'}
|
||||
{@const data = 'table-col' in result ? result['table-col'] : result}
|
||||
<AutoDataTable objects={objectOfArraysToObjects(data)} />
|
||||
{:else if !forceJson && resultKind === 'table-row'}
|
||||
@@ -779,7 +806,7 @@
|
||||
<div class="prose-xs dark:prose-invert !list-disc !list-outside">
|
||||
<Markdown md={result?.md ?? result?.markdown} />
|
||||
</div>
|
||||
{:else if largeObject}
|
||||
{:else if largeObject || hasBigInt}
|
||||
{#if result && typeof result === 'object' && 'file' in result}
|
||||
<div
|
||||
><a
|
||||
@@ -789,34 +816,36 @@
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-sm text-tertiary"
|
||||
><a
|
||||
download="{filename ?? 'result'}.json"
|
||||
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 {filename ? '' : 'as JSON'}
|
||||
</a>
|
||||
{#if download_as_csv}
|
||||
<DownloadCsv
|
||||
getContent={() => convertJsonToCsv(result)}
|
||||
customText="Download as CSV"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if largeObject}
|
||||
<div class="text-sm text-tertiary"
|
||||
><a
|
||||
download="{filename ?? 'result'}.json"
|
||||
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 {filename ? '' : 'as JSON'}
|
||||
</a>
|
||||
{#if download_as_csv}
|
||||
<DownloadCsv
|
||||
getContent={() => convertJsonToCsv(result)}
|
||||
customText="Download as CSV"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="mt-1 mb-2">
|
||||
<Alert
|
||||
size="xs"
|
||||
title="Large result detected"
|
||||
type="warning"
|
||||
tooltip="We recommend using persistent object storage for large result. See docs for setting up an object storage service integration using s3 or any other s3 compatible services."
|
||||
documentationLink="https://www.windmill.dev/docs/core_concepts/persistent_storage#object-storage-for-large-data-s3-r2-minio-azure-blob"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-1 mb-2">
|
||||
<Alert
|
||||
size="xs"
|
||||
title="Large result detected"
|
||||
type="warning"
|
||||
tooltip="We recommend using persistent object storage for large result. See docs for setting up an object storage service integration using s3 or any other s3 compatible services."
|
||||
documentationLink="https://www.windmill.dev/docs/core_concepts/persistent_storage#object-storage-for-large-data-s3-r2-minio-azure-blob"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if result && result != 'WINDMILL_TOO_BIG'}
|
||||
<ObjectViewer json={result} />
|
||||
{/if}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
import { NEVER_TESTED_THIS_FAR } from '../flows/models'
|
||||
import Portal from '$lib/components/Portal.svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { Download, PanelRightOpen } from 'lucide-svelte'
|
||||
import { Download, PanelRightOpen, TriangleAlertIcon } from 'lucide-svelte'
|
||||
import S3FilePicker from '../S3FilePicker.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import AnimatedButton from '$lib/components/common/button/AnimatedButton.svelte'
|
||||
import Popover from '../Popover.svelte'
|
||||
|
||||
export let json: any
|
||||
export let level = 0
|
||||
@@ -166,6 +167,17 @@
|
||||
<span class="text-2xs">null</span>
|
||||
{:else if typeof json[key] == 'string'}
|
||||
<span class="text-2xs">"{truncate(json[key], 200)}"</span>
|
||||
{:else if typeof json[key] == 'number' && Number.isInteger(json[key]) && !Number.isSafeInteger(json[key])}
|
||||
<span class="inline-flex flex-row gap-1 items-center text-2xs">
|
||||
{truncate(JSON.stringify(json[key]), 200)}
|
||||
<Popover>
|
||||
<TriangleAlertIcon size={14} class="text-yellow-500 mb-0.5" />
|
||||
<svelte:fragment slot="text">
|
||||
This number is too large for the frontend to handle correctly and may be
|
||||
rounded.
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</span>
|
||||
{:else}
|
||||
<span class="text-2xs">
|
||||
{truncate(JSON.stringify(json[key]), 200)}
|
||||
|
||||
Reference in New Issue
Block a user