import type { FC } from 'react' import type { SandboxFileTreeNode } from '@/types/sandbox-file' import { RiDownloadLine, RiMenuLine, } from '@remixicon/react' import { memo, useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' import CopyFeedback from '@/app/components/base/copy-feedback' import Loading from '@/app/components/base/loading' import ArtifactsTree from '@/app/components/workflow/skill/file-tree/artifacts-tree' import { useAppContext } from '@/context/app-context' import { useDownloadSandboxFile, useSandboxFilesTree } from '@/service/use-sandbox-file' import { cn } from '@/utils/classnames' import { useStore } from '../store' const formatFileSize = (bytes: number | null): string => { if (bytes === null || bytes === 0) return '0 B' const units = ['B', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(1024)) return `${(bytes / 1024 ** i).toFixed(i === 0 ? 0 : 1)} ${units[i]}` } type ArtifactsPreviewPaneProps = { file: SandboxFileTreeNode | null onDownload: (node: SandboxFileTreeNode) => void isDownloading: boolean onOpenMenu: () => void } const ArtifactsPreviewPane = memo(({ file, onDownload, isDownloading, onOpenMenu, }) => { const { t } = useTranslation('workflow') const bottomPanelWidth = useStore(s => s.bottomPanelWidth) if (!file) { return (

{t('debug.variableInspect.tabArtifacts.selectFile')}

) } const pathParts = file.path.split('/') return (
{bottomPanelWidth < 488 && ( )}
{pathParts.map((part, i) => ( {i > 0 && /} {part} ))}
{formatFileSize(file.size)}
onDownload(file)} disabled={isDownloading} aria-label={`Download ${file.name}`} >

{t('debug.variableInspect.tabArtifacts.previewNotAvailable')}

) }) const ArtifactsTab: FC = () => { const { t } = useTranslation() const { userProfile } = useAppContext() const sandboxId = userProfile?.id const bottomPanelWidth = useStore(s => s.bottomPanelWidth) const { data: treeData, hasFiles, isLoading } = useSandboxFilesTree(sandboxId, { enabled: !!sandboxId, }) const downloadMutation = useDownloadSandboxFile(sandboxId) const [selectedFile, setSelectedFile] = useState(null) const [showLeftPanel, setShowLeftPanel] = useState(true) const handleFileSelect = useCallback((node: SandboxFileTreeNode) => { if (node.node_type === 'file') setSelectedFile(node) }, []) const { mutateAsync: downloadFile } = downloadMutation const handleDownload = useCallback(async (node: SandboxFileTreeNode) => { try { const ticket = await downloadFile(node.path) window.open(ticket.download_url, '_blank') } catch (error) { console.error('Download failed:', error) } }, [downloadFile]) if (isLoading) { return (
) } if (!hasFiles) { return (

{t('skillSidebar.artifacts.emptyState', { ns: 'workflow' })}

) } return (
{bottomPanelWidth < 488 && showLeftPanel && (
setShowLeftPanel(false)} /> )}
setShowLeftPanel(true)} />
) } export default ArtifactsTab