From 3105c53b6f2cffb84499b7c809c2d843357b8e31 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Sun, 17 Aug 2025 22:43:09 +0800 Subject: [PATCH] Add external asset transfer for editor attachments (#7687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /area ui /area editor /kind feature /milestone 2.21.x #### What this PR does / why we need it: Support transfer external assets in the editor to the attachment library. Currently, it supports individual images, videos, and audio files. image in progress: - [ ] Batch transferring of all external assets. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/2335 #### Special notes for your reviewer: #### Does this PR introduce a user-facing change? ```release-note 支持转存编辑器中的外部资源到附件库 ``` --- .../editor/composables/use-attachment.ts | 59 ++++++++++++++++ .../editor/extensions/audio/AudioView.vue | 27 +++++++- .../editor/extensions/image/ImageView.vue | 28 +++++++- .../editor/extensions/upload/index.ts | 57 +++++++++++++++- .../editor/extensions/video/VideoView.vue | 27 +++++++- ui/src/components/editor/utils/upload.ts | 67 ++++++++++++++++++- ui/src/locales/_missing_translations_es.yaml | 7 +- ui/src/locales/en.yaml | 9 +++ ui/src/locales/zh-CN.yaml | 5 ++ ui/src/locales/zh-TW.yaml | 5 ++ 10 files changed, 284 insertions(+), 7 deletions(-) diff --git a/ui/src/components/editor/composables/use-attachment.ts b/ui/src/components/editor/composables/use-attachment.ts index 29e49bb9f..91283e7b1 100644 --- a/ui/src/components/editor/composables/use-attachment.ts +++ b/ui/src/components/editor/composables/use-attachment.ts @@ -1,4 +1,10 @@ +import { useGlobalInfoStore } from "@/stores/global-info"; +import { ucApiClient } from "@halo-dev/api-client"; +import { Toast } from "@halo-dev/components"; import type { AttachmentLike } from "@halo-dev/console-shared"; +import { computed, ref, type Ref } from "vue"; +import { useI18n } from "vue-i18n"; +import type { AttachmentAttr } from "../utils/attachment"; interface useAttachmentSelectReturn { onAttachmentSelect: (attachments: AttachmentLike[]) => void; @@ -24,3 +30,56 @@ export function useAttachmentSelect(): useAttachmentSelectReturn { attachmentResult, }; } + +export function useExternalAssetsTransfer( + src: Ref, + callback: (attachment: AttachmentAttr) => void +) { + const { globalInfo } = useGlobalInfoStore(); + const { t } = useI18n(); + + const isExternalAsset = computed(() => { + if (src.value?.startsWith("/")) { + return false; + } + + if (!globalInfo?.externalUrl) { + return false; + } + + return !src.value?.startsWith(globalInfo?.externalUrl); + }); + + const transferring = ref(false); + + async function handleTransfer() { + if (!src.value) { + return; + } + + transferring.value = true; + + const { data } = + await ucApiClient.storage.attachment.externalTransferAttachment1({ + ucUploadFromUrlRequest: { + url: src.value, + }, + waitForPermalink: true, + }); + + callback({ + url: data.status?.permalink, + name: data.spec.displayName, + }); + + Toast.success(t("core.common.toast.save_success")); + + transferring.value = false; + } + + return { + isExternalAsset, + transferring, + handleTransfer, + }; +} diff --git a/ui/src/components/editor/extensions/audio/AudioView.vue b/ui/src/components/editor/extensions/audio/AudioView.vue index 39a18134c..86b321747 100644 --- a/ui/src/components/editor/extensions/audio/AudioView.vue +++ b/ui/src/components/editor/extensions/audio/AudioView.vue @@ -1,10 +1,12 @@