refactor(skill): unify root/blank constants and eliminate magic strings

- Add constants.ts with ROOT_ID, CONTEXT_MENU_TYPE, NODE_MENU_TYPE
- Add root utilities to tree-utils.ts (isRootId, toApiParentId, etc.)
- Replace '__root__' with ROOT_ID for consistent root identifier
- Replace inline 'blank'/'root' strings with constants
- Use NodeMenuType for type-safe menu type props
- Remove duplicate ContextMenuType from types.ts, use from constants.ts
This commit is contained in:
yyh
2026-01-19 23:04:18 +08:00
parent 9080607028
commit 31a7db2657
9 changed files with 78 additions and 22 deletions

View File

@ -13,6 +13,7 @@ import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
import { cn } from '@/utils/classnames'
import { CONTEXT_MENU_TYPE, ROOT_ID } from '../constants'
import { useInlineCreateNode } from '../hooks/use-inline-create-node'
import { useRootFileDrop } from '../hooks/use-root-file-drop'
import { useSkillAssetTreeData } from '../hooks/use-skill-asset-tree'
@ -63,7 +64,7 @@ const FileTree: React.FC<FileTreeProps> = ({ className, searchTerm = '' }) => {
const storeApi = useWorkflowStore()
// Root dropzone highlight (when dragging to root, not to a specific folder)
const isRootDropzone = dragOverFolderId === '__root__'
const isRootDropzone = dragOverFolderId === ROOT_ID
useEffect(() => {
if (!dragOverFolderId)
@ -114,7 +115,7 @@ const FileTree: React.FC<FileTreeProps> = ({ className, searchTerm = '' }) => {
storeApi.getState().setContextMenu({
top: e.clientY,
left: e.clientX,
type: 'blank',
type: CONTEXT_MENU_TYPE.BLANK,
})
}, [storeApi])

View File

@ -2,6 +2,7 @@
import type { FC } from 'react'
import type { NodeApi, TreeApi } from 'react-arborist'
import type { NodeMenuType } from '../constants'
import type { TreeNodeData } from '../type'
import {
RiDeleteBinLine,
@ -15,6 +16,7 @@ import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Confirm from '@/app/components/base/confirm'
import { cn } from '@/utils/classnames'
import { NODE_MENU_TYPE } from '../constants'
import { useFileOperations } from '../hooks/use-file-operations'
import MenuItem from './menu-item'
@ -24,7 +26,7 @@ export const MENU_CONTAINER_STYLES = [
] as const
type NodeMenuProps = {
type: 'file' | 'folder' | 'root'
type: NodeMenuType
nodeId?: string
onClose: () => void
className?: string
@ -41,8 +43,8 @@ const NodeMenu: FC<NodeMenuProps> = ({
node,
}) => {
const { t } = useTranslation('workflow')
const isRoot = type === 'root'
const isFolder = type === 'folder' || isRoot
const isRoot = type === NODE_MENU_TYPE.ROOT
const isFolder = type === NODE_MENU_TYPE.FOLDER || isRoot
const {
fileInputRef,

View File

@ -7,18 +7,13 @@ import { useClickAway } from 'ahooks'
import * as React from 'react'
import { useCallback, useRef } from 'react'
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
import { getMenuNodeId, getNodeMenuType } from '../utils/tree-utils'
import NodeMenu from './node-menu'
type TreeContextMenuProps = {
treeRef: React.RefObject<TreeApi<TreeNodeData> | null>
}
function getMenuType(contextMenu: { type: string, isFolder?: boolean }): 'root' | 'folder' | 'file' {
if (contextMenu.type === 'blank')
return 'root'
return contextMenu.isFolder ? 'folder' : 'file'
}
const TreeContextMenu: FC<TreeContextMenuProps> = ({ treeRef }) => {
const ref = useRef<HTMLDivElement>(null)
const contextMenu = useStore(s => s.contextMenu)
@ -45,8 +40,8 @@ const TreeContextMenu: FC<TreeContextMenuProps> = ({ treeRef }) => {
}}
>
<NodeMenu
type={getMenuType(contextMenu)}
nodeId={contextMenu.type === 'blank' ? 'root' : contextMenu.nodeId}
type={getNodeMenuType(contextMenu.type, contextMenu.isFolder)}
nodeId={getMenuNodeId(contextMenu.type, contextMenu.nodeId)}
onClose={handleClose}
treeRef={treeRef}
/>