From b6df7b3afe3a7ec485f131b007f71de0fe1b05f2 Mon Sep 17 00:00:00 2001 From: yyh Date: Mon, 19 Jan 2026 23:15:00 +0800 Subject: [PATCH] fix(skill): use presigned URL for image/video preview in skill editor Previously, media files were fetched via getFileContent API which decodes binary data as UTF-8, resulting in corrupted strings that cannot be used as img/video src. Now media files use getFileDownloadUrl API to get a presigned URL, enabling proper preview of images and videos of any size. --- .../workflow/skill/skill-doc-editor.tsx | 30 ++++++++++++++----- web/service/use-app-asset.ts | 4 +-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/web/app/components/workflow/skill/skill-doc-editor.tsx b/web/app/components/workflow/skill/skill-doc-editor.tsx index eff3f78820..5b19b5895a 100644 --- a/web/app/components/workflow/skill/skill-doc-editor.tsx +++ b/web/app/components/workflow/skill/skill-doc-editor.tsx @@ -11,7 +11,7 @@ import Loading from '@/app/components/base/loading' import Toast from '@/app/components/base/toast' import { useStore, useWorkflowStore } from '@/app/components/workflow/store' import useTheme from '@/hooks/use-theme' -import { useGetAppAssetFileContent, useUpdateAppAssetFileContent } from '@/service/use-app-asset' +import { useGetAppAssetFileContent, useGetAppAssetFileDownloadUrl, useUpdateAppAssetFileContent } from '@/service/use-app-asset' import { Theme } from '@/types/app' import { basePath } from '@/utils/var' import CodeFileEditor from './editor/code-file-editor' @@ -57,11 +57,26 @@ const SkillDocEditor: FC = () => { } }, [currentFileNode?.name, currentFileNode?.extension]) + const isMediaFile = isImage || isVideo + const { data: fileContent, - isLoading, - error, - } = useGetAppAssetFileContent(appId, activeTabId || '') + isLoading: isContentLoading, + error: contentError, + } = useGetAppAssetFileContent(appId, activeTabId || '', { + enabled: !isMediaFile, + }) + + const { + data: downloadUrlData, + isLoading: isDownloadUrlLoading, + error: downloadUrlError, + } = useGetAppAssetFileDownloadUrl(appId, activeTabId || '', { + enabled: isMediaFile && !!activeTabId, + }) + + const isLoading = isMediaFile ? isDownloadUrlLoading : isContentLoading + const error = isMediaFile ? downloadUrlError : contentError const updateContent = useUpdateAppAssetFileContent() @@ -200,7 +215,8 @@ const SkillDocEditor: FC = () => { ) } - const previewUrl = fileContent?.content || '' + const mediaPreviewUrl = downloadUrlData?.download_url || '' + const textPreviewUrl = fileContent?.content || '' const fileName = currentFileNode?.name || '' const fileSize = currentFileNode?.size @@ -226,7 +242,7 @@ const SkillDocEditor: FC = () => { {(isImage || isVideo) && ( )} {isOffice && ( @@ -236,7 +252,7 @@ const SkillDocEditor: FC = () => { )} diff --git a/web/service/use-app-asset.ts b/web/service/use-app-asset.ts index c21aa1e817..1de386e790 100644 --- a/web/service/use-app-asset.ts +++ b/web/service/use-app-asset.ts @@ -96,7 +96,7 @@ export const useCreateAppAssetFile = () => { }) } -export const useGetAppAssetFileContent = (appId: string, nodeId: string) => { +export const useGetAppAssetFileContent = (appId: string, nodeId: string, options?: { enabled?: boolean }) => { return useQuery({ queryKey: consoleQuery.appAsset.getFileContent.queryKey({ input: { params: { appId, nodeId } } }), queryFn: () => consoleClient.appAsset.getFileContent({ params: { appId, nodeId } }), @@ -109,7 +109,7 @@ export const useGetAppAssetFileContent = (appId: string, nodeId: string) => { return { content: data.content } } }, - enabled: !!appId && !!nodeId, + enabled: (options?.enabled ?? true) && !!appId && !!nodeId, }) }