"use client"; import { useCallback, useEffect, useMemo, useRef, useState, type Key } from "react"; import { useReactFlow } from "@xyflow/react"; import { Button, Drawer, Empty, Input, Modal, Popover, Spin, Tree, message } from "antd"; import type { InputRef, TreeProps } from "antd"; import { AudioOutlined, FileImageOutlined, FolderAddOutlined, FolderOpenOutlined, FolderOutlined, PictureOutlined, PlayCircleOutlined, PlusOutlined, LeftOutlined } from "@ant-design/icons"; import { useI18n } from "@/i18n"; import { useWorkflowStore } from "@/store/workflowStore"; import { authFetch } from "@/utils/authFetch"; import { createSmartMediaNode, detectSmartMediaKind } from "@/utils/smartMediaNode"; import { ASSET_LIBRARY_ITEM_DRAG_MIME, ASSET_LIBRARY_ITEM_KIND_DRAG_MIME_PREFIX, getUserFileFolderKey, getUserFileItemKey, getUserFileList, ROOT_PARENT_ID, USER_FILE_PAGE_SIZE, type UserFileItem, type UserFileListResponse, type UserFileMutationResponse, } from "@/utils/userFileLibrary"; import { AssetLibraryFolderPickerModal } from "./AssetLibraryFolderPickerModal"; import { AssetLibraryItemActionsPopover } from "./AssetLibraryItemActionsPopover"; import { AssetLibraryManagerModal } from "./AssetLibraryManagerModal"; type AssetLibraryFileKind = "image" | "video" | "audio" | "other"; type AssetTreeNode = { key: string; title: string; item?: UserFileItem; isLeaf: boolean; depth: number; isCreateInput?: boolean; isEmpty?: boolean; createParentId?: number; children?: AssetTreeNode[]; }; interface AssetLibraryDrawerProps { open: boolean; onClose: () => void; } interface AssetLibraryPanelProps { active?: boolean; className?: string; } const treeClassName = [ "!bg-transparent !text-[var(--text-secondary)]", "[&_.ant-tree-list-holder-inner]:gap-y-0.5", "[&_.ant-tree-treenode]:!w-full [&_.ant-tree-treenode]:!items-center [&_.ant-tree-treenode]:!p-0", "[&_.ant-tree-indent-unit]:!w-5", "[&_.ant-tree-switcher]:!hidden", "[&_.ant-tree-node-content-wrapper]:!m-0 [&_.ant-tree-node-content-wrapper]:!min-w-0 [&_.ant-tree-node-content-wrapper]:!flex-1 [&_.ant-tree-node-content-wrapper]:!bg-transparent [&_.ant-tree-node-content-wrapper]:!p-0 [&_.ant-tree-node-content-wrapper]:!text-inherit", "[&_.ant-tree-node-content-wrapper:hover]:!bg-transparent [&_.ant-tree-node-content-wrapper.ant-tree-node-selected]:!bg-transparent", "[&_.ant-tree-title]:!block [&_.ant-tree-title]:!w-full", ].join(" "); function getPaneCenter() { const pane = document.querySelector(".react-flow"); if (pane) { const rect = pane.getBoundingClientRect(); return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2, }; } return { x: window.innerWidth / 2, y: window.innerHeight / 2 }; } function getFileKind(item: UserFileItem): AssetLibraryFileKind { if (item.fileCategory === "image") return "image"; if (item.fileCategory === "video") return "video"; if (item.fileCategory === "audio") return "audio"; return detectSmartMediaKind({ mimeType: item.mimeType, fileExt: item.fileExt, url: item.url, }) ?? "other"; } function getTreeThumbUrl(item: UserFileItem): string | null { const kind = getFileKind(item); if (kind === "image") return item.url || null; if (kind === "video") return item.coverUrl || null; return null; } function getHoverMediaUrl(item: UserFileItem): string | null { const kind = getFileKind(item); if (kind === "image" || kind === "video" || kind === "audio") return item.url || null; return null; } function getVideoPosterUrl(item: UserFileItem): string | null { return item.coverUrl || null; } function formatCreateTime(value?: string) { if (!value) return ""; const date = new Date(value); if (Number.isNaN(date.getTime())) return value; const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); const hours = String(date.getHours()).padStart(2, "0"); const minutes = String(date.getMinutes()).padStart(2, "0"); const seconds = String(date.getSeconds()).padStart(2, "0"); return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; } function MediaThumb({ item }: { item: UserFileItem }) { const kind = getFileKind(item); const thumbUrl = getTreeThumbUrl(item); if (kind === "image" && thumbUrl) { return ; } if (kind === "video") { return (
{thumbUrl ? ( ) : ( )}
); } if (kind === "audio") { return ; } return ; } function PreviewMedia({ item }: { item: UserFileItem }) { const kind = getFileKind(item); const mediaUrl = getHoverMediaUrl(item); if (kind === "image" && mediaUrl) { return {item.name}; } if (kind === "video" && mediaUrl) { return (