Compare commits

...

10 Commits

Author SHA1 Message Date
Joel
580201ed2c merge main 2025-08-28 14:57:30 +08:00
Joel
1b9c817dba feat: add process data truncate 2025-08-25 11:26:57 +08:00
Joel
0ca7c29c47 feat: preiew show the large data 2025-08-22 11:35:54 +08:00
Joel
68ba41e57e chore: fix trunate change proplem 2025-08-22 11:08:54 +08:00
Joel
d4370a8ca5 chore: alert ui 2025-08-19 15:07:53 +08:00
Joel
64897bc6fe chore: hide mock data 2025-08-19 14:21:53 +08:00
Joel
559d014b29 chore: use api return truncate 2025-08-19 14:18:41 +08:00
Joel
3c4b374038 feat: run result data too long export 2025-08-19 14:04:00 +08:00
Joel
b4e76af4a7 feat: string type too long hide 2025-08-18 18:15:10 +08:00
Joel
2391e582f2 feat: debug show big data 2025-08-18 16:57:41 +08:00
16 changed files with 152 additions and 9 deletions

View File

@@ -39,6 +39,7 @@ type Props = {
tip?: React.JSX.Element tip?: React.JSX.Element
nodesOutputVars?: NodeOutPutVar[] nodesOutputVars?: NodeOutPutVar[]
availableNodes?: Node[] availableNodes?: Node[]
footer?: React.ReactNode
} }
const Base: FC<Props> = ({ const Base: FC<Props> = ({
@@ -57,6 +58,7 @@ const Base: FC<Props> = ({
showFileList, showFileList,
showCodeGenerator = false, showCodeGenerator = false,
tip, tip,
footer,
}) => { }) => {
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
const { const {
@@ -128,6 +130,7 @@ const Base: FC<Props> = ({
{showFileList && fileList.length > 0 && ( {showFileList && fileList.length > 0 && (
<FileListInLog fileList={fileList} /> <FileListInLog fileList={fileList} />
)} )}
{footer}
</div> </div>
</Wrap> </Wrap>
) )

View File

@@ -39,6 +39,7 @@ export type Props = {
showCodeGenerator?: boolean showCodeGenerator?: boolean
className?: string className?: string
tip?: React.JSX.Element tip?: React.JSX.Element
footer?: React.ReactNode
} }
export const languageMap = { export const languageMap = {
@@ -67,6 +68,7 @@ const CodeEditor: FC<Props> = ({
showCodeGenerator = false, showCodeGenerator = false,
className, className,
tip, tip,
footer,
}) => { }) => {
const [isFocus, setIsFocus] = React.useState(false) const [isFocus, setIsFocus] = React.useState(false)
const [isMounted, setIsMounted] = React.useState(false) const [isMounted, setIsMounted] = React.useState(false)
@@ -191,6 +193,7 @@ const CodeEditor: FC<Props> = ({
showFileList={showFileList} showFileList={showFileList}
showCodeGenerator={showCodeGenerator} showCodeGenerator={showCodeGenerator}
tip={tip} tip={tip}
footer={footer}
> >
{main} {main}
</Base> </Base>

View File

@@ -15,6 +15,7 @@ type CodeEditorProps = {
editorWrapperClassName?: string editorWrapperClassName?: string
readOnly?: boolean readOnly?: boolean
hideTopMenu?: boolean hideTopMenu?: boolean
topContent?: React.ReactNode
} & React.HTMLAttributes<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
const CodeEditor: FC<CodeEditorProps> = ({ const CodeEditor: FC<CodeEditorProps> = ({
@@ -24,6 +25,7 @@ const CodeEditor: FC<CodeEditorProps> = ({
editorWrapperClassName, editorWrapperClassName,
readOnly = false, readOnly = false,
hideTopMenu = false, hideTopMenu = false,
topContent,
className, className,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -127,6 +129,7 @@ const CodeEditor: FC<CodeEditorProps> = ({
</div> </div>
</div> </div>
)} )}
{topContent}
<div className={classNames('relative overflow-hidden', editorWrapperClassName)}> <div className={classNames('relative overflow-hidden', editorWrapperClassName)}>
<Editor <Editor
defaultLanguage='json' defaultLanguage='json'

View File

@@ -1,6 +1,7 @@
import React, { type FC } from 'react' import React, { type FC } from 'react'
import CodeEditor from './code-editor' import CodeEditor from './code-editor'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import LargeDataAlert from '@/app/components/workflow/variable-inspect/large-data-alert'
type SchemaEditorProps = { type SchemaEditorProps = {
schema: string schema: string
@@ -8,6 +9,7 @@ type SchemaEditorProps = {
hideTopMenu?: boolean hideTopMenu?: boolean
className?: string className?: string
readonly?: boolean readonly?: boolean
isTruncated?: boolean
} }
const SchemaEditor: FC<SchemaEditorProps> = ({ const SchemaEditor: FC<SchemaEditorProps> = ({
@@ -16,6 +18,7 @@ const SchemaEditor: FC<SchemaEditorProps> = ({
hideTopMenu, hideTopMenu,
className, className,
readonly = false, readonly = false,
isTruncated,
}) => { }) => {
return ( return (
<CodeEditor <CodeEditor
@@ -25,6 +28,7 @@ const SchemaEditor: FC<SchemaEditorProps> = ({
value={schema} value={schema}
onUpdate={onUpdate} onUpdate={onUpdate}
hideTopMenu={hideTopMenu} hideTopMenu={hideTopMenu}
topContent={isTruncated && <LargeDataAlert className='mx-1 mb-3 mt-[-4px]' />}
/> />
) )
} }

View File

@@ -184,7 +184,12 @@ const WorkflowPreview = () => {
{currentTab === 'DETAIL' && ( {currentTab === 'DETAIL' && (
<ResultPanel <ResultPanel
inputs={workflowRunningData?.result?.inputs} inputs={workflowRunningData?.result?.inputs}
inputs_truncated={workflowRunningData?.result?.inputs_truncated}
process_data={workflowRunningData?.result?.process_data}
process_data_truncated={workflowRunningData?.result?.process_data_truncated}
outputs={workflowRunningData?.result?.outputs} outputs={workflowRunningData?.result?.outputs}
outputs_truncated={workflowRunningData?.result?.outputs_truncated}
outputs_full_content={workflowRunningData?.result?.outputs_full_content}
status={workflowRunningData?.result?.status || ''} status={workflowRunningData?.result?.status || ''}
error={workflowRunningData?.result?.error} error={workflowRunningData?.result?.error}
elapsed_time={workflowRunningData?.result?.elapsed_time} elapsed_time={workflowRunningData?.result?.elapsed_time}

View File

@@ -147,7 +147,10 @@ const RunPanel: FC<RunProps> = ({ hideResult, activeTab = 'RESULT', runID, getRe
{!loading && currentTab === 'DETAIL' && runDetail && ( {!loading && currentTab === 'DETAIL' && runDetail && (
<ResultPanel <ResultPanel
inputs={runDetail.inputs} inputs={runDetail.inputs}
inputs_truncated={runDetail.inputs_truncated}
outputs={runDetail.outputs} outputs={runDetail.outputs}
outputs_truncated={runDetail.outputs_truncated}
outputs_full_content={runDetail.outputs_full_content}
status={runDetail.status} status={runDetail.status}
error={runDetail.error} error={runDetail.error}
elapsed_time={runDetail.elapsed_time} elapsed_time={runDetail.elapsed_time}

View File

@@ -30,6 +30,7 @@ import ErrorHandleTip from '@/app/components/workflow/nodes/_base/components/err
import { hasRetryNode } from '@/app/components/workflow/utils' import { hasRetryNode } from '@/app/components/workflow/utils'
import { useDocLink } from '@/context/i18n' import { useDocLink } from '@/context/i18n'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import LargeDataAlert from '../variable-inspect/large-data-alert'
type Props = { type Props = {
className?: string className?: string
@@ -231,6 +232,7 @@ const NodePanel: FC<Props> = ({
language={CodeLanguage.json} language={CodeLanguage.json}
value={nodeInfo.inputs} value={nodeInfo.inputs}
isJSONStringifyBeauty isJSONStringifyBeauty
footer={nodeInfo.inputs_truncated && <LargeDataAlert textHasNoExport className='mx-1 mb-1 mt-2 h-7' />}
/> />
</div> </div>
)} )}
@@ -254,6 +256,7 @@ const NodePanel: FC<Props> = ({
value={nodeInfo.outputs} value={nodeInfo.outputs}
isJSONStringifyBeauty isJSONStringifyBeauty
tip={<ErrorHandleTip type={nodeInfo.execution_metadata?.error_strategy} />} tip={<ErrorHandleTip type={nodeInfo.execution_metadata?.error_strategy} />}
footer={nodeInfo.outputs_truncated && <LargeDataAlert textHasNoExport downloadUrl={nodeInfo.outputs_full_content?.download_url} className='mx-1 mb-1 mt-2 h-7' />}
/> />
</div> </div>
)} )}

View File

@@ -16,12 +16,19 @@ import { IterationLogTrigger } from '@/app/components/workflow/run/iteration-log
import { LoopLogTrigger } from '@/app/components/workflow/run/loop-log' import { LoopLogTrigger } from '@/app/components/workflow/run/loop-log'
import { RetryLogTrigger } from '@/app/components/workflow/run/retry-log' import { RetryLogTrigger } from '@/app/components/workflow/run/retry-log'
import { AgentLogTrigger } from '@/app/components/workflow/run/agent-log' import { AgentLogTrigger } from '@/app/components/workflow/run/agent-log'
import LargeDataAlert from '../variable-inspect/large-data-alert'
export type ResultPanelProps = { export type ResultPanelProps = {
nodeInfo?: NodeTracing nodeInfo?: NodeTracing
inputs?: string inputs?: string
inputs_truncated?: boolean
process_data?: string process_data?: string
process_data_truncated?: boolean
outputs?: string | Record<string, any> outputs?: string | Record<string, any>
outputs_truncated?: boolean
outputs_full_content?: {
download_url: string
}
status: string status: string
error?: string error?: string
elapsed_time?: number elapsed_time?: number
@@ -42,8 +49,12 @@ export type ResultPanelProps = {
const ResultPanel: FC<ResultPanelProps> = ({ const ResultPanel: FC<ResultPanelProps> = ({
nodeInfo, nodeInfo,
inputs, inputs,
inputs_truncated,
process_data, process_data,
process_data_truncated,
outputs, outputs,
outputs_truncated,
outputs_full_content,
status, status,
error, error,
elapsed_time, elapsed_time,
@@ -118,6 +129,7 @@ const ResultPanel: FC<ResultPanelProps> = ({
language={CodeLanguage.json} language={CodeLanguage.json}
value={inputs} value={inputs}
isJSONStringifyBeauty isJSONStringifyBeauty
footer={inputs_truncated && <LargeDataAlert textHasNoExport className='mx-1 mb-1 mt-2 h-7' />}
/> />
{process_data && ( {process_data && (
<CodeEditor <CodeEditor
@@ -126,6 +138,7 @@ const ResultPanel: FC<ResultPanelProps> = ({
language={CodeLanguage.json} language={CodeLanguage.json}
value={process_data} value={process_data}
isJSONStringifyBeauty isJSONStringifyBeauty
footer={process_data_truncated && <LargeDataAlert textHasNoExport className='mx-1 mb-1 mt-2 h-7' />}
/> />
)} )}
{(outputs || status === 'running') && ( {(outputs || status === 'running') && (
@@ -136,6 +149,7 @@ const ResultPanel: FC<ResultPanelProps> = ({
value={outputs} value={outputs}
isJSONStringifyBeauty isJSONStringifyBeauty
tip={<ErrorHandleTip type={execution_metadata?.error_strategy} />} tip={<ErrorHandleTip type={execution_metadata?.error_strategy} />}
footer={outputs_truncated && <LargeDataAlert textHasNoExport downloadUrl={outputs_full_content?.download_url} className='mx-1 mb-1 mt-2 h-7' />}
/> />
)} )}
</div> </div>

View File

@@ -379,8 +379,14 @@ export type WorkflowRunningData = {
result: { result: {
workflow_id?: string workflow_id?: string
inputs?: string inputs?: string
inputs_truncated: boolean
process_data?: string process_data?: string
process_data_truncated: boolean
outputs?: string outputs?: string
outputs_truncated: boolean
outputs_full_content?: {
download_url: string
}
status: string status: string
error?: string error?: string
elapsed_time?: number elapsed_time?: number

View File

@@ -0,0 +1,33 @@
'use client'
import { RiInformation2Fill } from '@remixicon/react'
import type { FC } from 'react'
import React from 'react'
import cn from '@/utils/classnames'
import { useTranslation } from 'react-i18next'
type Props = {
textHasNoExport?: boolean
downloadUrl?: string
className?: string
}
const LargeDataAlert: FC<Props> = ({
textHasNoExport,
downloadUrl,
className,
}) => {
const { t } = useTranslation()
const text = textHasNoExport ? t('workflow.debug.variableInspect.largeDataNoExport') : t('workflow.debug.variableInspect.largeData')
return (
<div className={cn('flex h-8 items-center justify-between rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur px-2 shadow-xs', className)}>
<div className='flex h-full w-0 grow items-center space-x-1'>
<RiInformation2Fill className='size-4 shrink-0 text-text-accent' />
<div className='system-xs-regular w-0 grow truncate text-text-primary'>{text}</div>
</div>
{downloadUrl && (
<div className='system-xs-medium-uppercase ml-1 shrink-0 cursor-pointer text-text-accent'>{t('workflow.debug.variableInspect.export')}</div>
)}
</div>
)
}
export default React.memo(LargeDataAlert)

View File

@@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next'
import { import {
RiArrowGoBackLine, RiArrowGoBackLine,
RiCloseLine, RiCloseLine,
RiFileDownloadFill,
RiMenuLine, RiMenuLine,
RiSparklingFill, RiSparklingFill,
} from '@remixicon/react' } from '@remixicon/react'
@@ -52,6 +53,13 @@ const Right = ({
const bottomPanelWidth = useStore(s => s.bottomPanelWidth) const bottomPanelWidth = useStore(s => s.bottomPanelWidth)
const setShowVariableInspectPanel = useStore(s => s.setShowVariableInspectPanel) const setShowVariableInspectPanel = useStore(s => s.setShowVariableInspectPanel)
const setCurrentFocusNodeId = useStore(s => s.setCurrentFocusNodeId) const setCurrentFocusNodeId = useStore(s => s.setCurrentFocusNodeId)
const isTruncated = currentNodeVar?.var.is_truncated
const fullContent = currentNodeVar?.var.full_content
// const isTruncated = true
// const fullContent = {
// size_bytes: 11289600,
// download_url: 'https://upload.dify.ai/files/222bc6e7-40bd-4433-9ba8-4b9ecda88b14/file-preview?timestamp=1754976824&nonce=d970eb39b119f76ec94a9b026f2825b3&sign=ltJO4vS0jrwxuBl4GU74E1Sg_Tia2Y4g2LoBoPh3970=&as_attachment=true',
// }
const { const {
resetConversationVar, resetConversationVar,
@@ -183,7 +191,16 @@ const Right = ({
</> </>
)} )}
<div title={currentNodeVar.var.name} className='system-sm-semibold truncate text-text-secondary'>{currentNodeVar.var.name}</div> <div title={currentNodeVar.var.name} className='system-sm-semibold truncate text-text-secondary'>{currentNodeVar.var.name}</div>
<div className='system-xs-medium ml-1 shrink-0 text-text-tertiary'>{currentNodeVar.var.value_type}</div> <div className='system-xs-medium ml-1 shrink-0 space-x-2 text-text-tertiary'>
<span>{currentNodeVar.var.value_type}</span>
{isTruncated && (
<>
<span>·</span>
<span>{((fullContent?.size_bytes || 0) / 1024 / 1024).toFixed(1)}MB</span>
</>
)}
</div>
</> </>
)} )}
</div> </div>
@@ -200,20 +217,32 @@ const Right = ({
</div> </div>
</Tooltip> </Tooltip>
)} )}
{currentNodeVar.var.edited && ( {isTruncated && (
<Tooltip popupContent={t('workflow.debug.variableInspect.exportToolTip')}>
<ActionButton>
<a
href={fullContent?.download_url}
target='_blank'
>
<RiFileDownloadFill className='size-4' />
</a>
</ActionButton>
</Tooltip>
)}
{!isTruncated && currentNodeVar.var.edited && (
<Badge> <Badge>
<span className='ml-[2.5px] mr-[4.5px] h-[3px] w-[3px] rounded bg-text-accent-secondary'></span> <span className='ml-[2.5px] mr-[4.5px] h-[3px] w-[3px] rounded bg-text-accent-secondary'></span>
<span className='system-2xs-semibold-uupercase'>{t('workflow.debug.variableInspect.edited')}</span> <span className='system-2xs-semibold-uupercase'>{t('workflow.debug.variableInspect.edited')}</span>
</Badge> </Badge>
)} )}
{currentNodeVar.var.edited && currentNodeVar.var.type !== VarInInspectType.conversation && ( {!isTruncated && currentNodeVar.var.edited && currentNodeVar.var.type !== VarInInspectType.conversation && (
<Tooltip popupContent={t('workflow.debug.variableInspect.reset')}> <Tooltip popupContent={t('workflow.debug.variableInspect.reset')}>
<ActionButton onClick={resetValue}> <ActionButton onClick={resetValue}>
<RiArrowGoBackLine className='h-4 w-4' /> <RiArrowGoBackLine className='h-4 w-4' />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
)} )}
{currentNodeVar.var.edited && currentNodeVar.var.type === VarInInspectType.conversation && ( {!isTruncated && currentNodeVar.var.edited && currentNodeVar.var.type === VarInInspectType.conversation && (
<Tooltip popupContent={t('workflow.debug.variableInspect.resetConversationVar')}> <Tooltip popupContent={t('workflow.debug.variableInspect.resetConversationVar')}>
<ActionButton onClick={handleClear}> <ActionButton onClick={handleClear}>
<RiArrowGoBackLine className='h-4 w-4' /> <RiArrowGoBackLine className='h-4 w-4' />
@@ -238,7 +267,7 @@ const Right = ({
<Loading /> <Loading />
</div> </div>
)} )}
{currentNodeVar && !isValueFetching && <ValueContent currentVar={currentNodeVar.var} handleValueChange={handleValueChange} />} {currentNodeVar && !isValueFetching && <ValueContent currentVar={currentNodeVar.var} handleValueChange={handleValueChange} isTruncated={!!isTruncated} />}
</div> </div>
{isShowPromptGenerator && ( {isShowPromptGenerator && (
isCodeBlock isCodeBlock

View File

@@ -21,16 +21,19 @@ import { SupportUploadFileTypes } from '@/app/components/workflow/types'
import type { VarInInspect } from '@/types/workflow' import type { VarInInspect } from '@/types/workflow'
import { VarInInspectType } from '@/types/workflow' import { VarInInspectType } from '@/types/workflow'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import LargeDataAlert from './large-data-alert'
import BoolValue from '../panel/chat-variable-panel/components/bool-value' import BoolValue from '../panel/chat-variable-panel/components/bool-value'
type Props = { type Props = {
currentVar: VarInInspect currentVar: VarInInspect
handleValueChange: (varId: string, value: any) => void handleValueChange: (varId: string, value: any) => void
isTruncated: boolean
} }
const ValueContent = ({ const ValueContent = ({
currentVar, currentVar,
handleValueChange, handleValueChange,
isTruncated,
}: Props) => { }: Props) => {
const contentContainerRef = useRef<HTMLDivElement>(null) const contentContainerRef = useRef<HTMLDivElement>(null)
const errorMessageRef = useRef<HTMLDivElement>(null) const errorMessageRef = useRef<HTMLDivElement>(null)
@@ -78,6 +81,8 @@ const ValueContent = ({
}, [currentVar.id, currentVar.value]) }, [currentVar.id, currentVar.value])
const handleTextChange = (value: string) => { const handleTextChange = (value: string) => {
if(isTruncated)
return
if (currentVar.value_type === 'string') if (currentVar.value_type === 'string')
setValue(value) setValue(value)
@@ -127,6 +132,8 @@ const ValueContent = ({
} }
const handleEditorChange = (value: string) => { const handleEditorChange = (value: string) => {
if(isTruncated)
return
setJson(value) setJson(value)
if (jsonValueValidate(value, currentVar.value_type)) { if (jsonValueValidate(value, currentVar.value_type)) {
const parsed = JSON.parse(value) const parsed = JSON.parse(value)
@@ -170,15 +177,18 @@ const ValueContent = ({
ref={contentContainerRef} ref={contentContainerRef}
className='flex h-full flex-col' className='flex h-full flex-col'
> >
<div className={cn('grow')} style={{ height: `${editorHeight}px` }}> <div className={cn('relative grow')} style={{ height: `${editorHeight}px` }}>
{showTextEditor && ( {showTextEditor && (
<>
{isTruncated && <LargeDataAlert className='absolute left-3 right-3 top-1' />}
<Textarea <Textarea
readOnly={textEditorDisabled} readOnly={textEditorDisabled}
disabled={textEditorDisabled} disabled={textEditorDisabled || isTruncated}
className='h-full' className={cn('h-full', isTruncated && 'pt-[48px]')}
value={value as any} value={value as any}
onChange={e => handleTextChange(e.target.value)} onChange={e => handleTextChange(e.target.value)}
/> />
</>
)} )}
{showBoolEditor && ( {showBoolEditor && (
<div className='w-[295px]'> <div className='w-[295px]'>
@@ -211,11 +221,12 @@ const ValueContent = ({
} }
{showJSONEditor && ( {showJSONEditor && (
<SchemaEditor <SchemaEditor
readonly={JSONEditorDisabled} readonly={JSONEditorDisabled || isTruncated}
className='overflow-y-auto' className='overflow-y-auto'
hideTopMenu hideTopMenu
schema={json} schema={json}
onUpdate={handleEditorChange} onUpdate={handleEditorChange}
isTruncated={isTruncated}
/> />
)} )}
{showFileEditor && ( {showFileEditor && (

View File

@@ -988,6 +988,10 @@ const translation = {
envNode: 'Environment', envNode: 'Environment',
chatNode: 'Conversation', chatNode: 'Conversation',
systemNode: 'System', systemNode: 'System',
exportToolTip: 'Export Variable as File',
largeData: 'Large data, read-only preview. Export to view all.',
largeDataNoExport: 'Large data - partial preview only',
export: 'export',
}, },
lastOutput: 'Last Output', lastOutput: 'Last Output',
relations: { relations: {

View File

@@ -988,6 +988,10 @@ const translation = {
envNode: '环境变量', envNode: '环境变量',
chatNode: '会话变量', chatNode: '会话变量',
systemNode: '系统变量', systemNode: '系统变量',
exportToolTip: '导出变量为文件',
largeData: '大数据 - 仅部分只读预览。请导出查看完整数据。',
largeDataNoExport: '大数据 - 仅部分预览',
export: '导出',
}, },
lastOutput: '上次输出', lastOutput: '上次输出',
relations: { relations: {

View File

@@ -285,8 +285,13 @@ export type WorkflowRunDetailResponse = {
viewport?: Viewport viewport?: Viewport
} }
inputs: string inputs: string
inputs_truncated: boolean
status: 'running' | 'succeeded' | 'failed' | 'stopped' status: 'running' | 'succeeded' | 'failed' | 'stopped'
outputs?: string outputs?: string
outputs_truncated: boolean
outputs_full_content?: {
download_url: string
}
error?: string error?: string
elapsed_time?: number elapsed_time?: number
total_tokens?: number total_tokens?: number

View File

@@ -37,8 +37,14 @@ export type NodeTracing = {
node_type: BlockEnum node_type: BlockEnum
title: string title: string
inputs: any inputs: any
inputs_truncated: boolean
process_data: any process_data: any
process_data_truncated: boolean
outputs?: Record<string, any> outputs?: Record<string, any>
outputs_truncated: boolean
outputs_full_content?: {
download_url: string
}
status: string status: string
parallel_run_id?: string parallel_run_id?: string
error?: string error?: string
@@ -378,6 +384,11 @@ export enum VarInInspectType {
system = 'sys', system = 'sys',
} }
export type FullContent = {
size_bytes: number
download_url: string
}
export type VarInInspect = { export type VarInInspect = {
id: string id: string
type: VarInInspectType type: VarInInspectType
@@ -388,6 +399,8 @@ export type VarInInspect = {
value: any value: any
edited: boolean edited: boolean
visible: boolean visible: boolean
is_truncated: boolean
full_content: FullContent
} }
export type NodeWithVar = { export type NodeWithVar = {