mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
refactor(skill): rename components for semantic clarity
Rename components and reorganize directory structure: - skill-doc-editor.tsx → file-content-panel.tsx (handles edit/preview/download) - editor-area.tsx → content-area.tsx - editor-body.tsx → content-body.tsx - editor-tabs.tsx → file-tabs.tsx - editor-tab-item.tsx → file-tab-item.tsx Create viewer/ directory for non-editor components: - Move media-file-preview.tsx from editor/ to viewer/ - Move unsupported-file-download.tsx from editor/ to viewer/ This clarifies the distinction between: - editor/: actual file editors (code, markdown) - viewer/: preview and download components (media, unsupported files)
This commit is contained in:
103
web/app/components/workflow/skill/file-tabs.tsx
Normal file
103
web/app/components/workflow/skill/file-tabs.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import FileTabItem from './file-tab-item'
|
||||
import { useSkillAssetNodeMap } from './hooks/use-skill-asset-tree'
|
||||
|
||||
const FileTabs: FC = () => {
|
||||
const { t } = useTranslation('workflow')
|
||||
const openTabIds = useStore(s => s.openTabIds)
|
||||
const activeTabId = useStore(s => s.activeTabId)
|
||||
const previewTabId = useStore(s => s.previewTabId)
|
||||
const dirtyContents = useStore(s => s.dirtyContents)
|
||||
const dirtyMetadataIds = useStore(s => s.dirtyMetadataIds)
|
||||
const storeApi = useWorkflowStore()
|
||||
const { data: nodeMap } = useSkillAssetNodeMap()
|
||||
|
||||
const [pendingCloseId, setPendingCloseId] = useState<string | null>(null)
|
||||
|
||||
const handleTabClick = useCallback((fileId: string) => {
|
||||
storeApi.getState().activateTab(fileId)
|
||||
}, [storeApi])
|
||||
|
||||
const handleTabDoubleClick = useCallback((fileId: string) => {
|
||||
storeApi.getState().pinTab(fileId)
|
||||
}, [storeApi])
|
||||
|
||||
const closeTab = useCallback((fileId: string) => {
|
||||
storeApi.getState().closeTab(fileId)
|
||||
storeApi.getState().clearDraftContent(fileId)
|
||||
storeApi.getState().clearFileMetadata(fileId)
|
||||
}, [storeApi])
|
||||
|
||||
const handleTabClose = useCallback((fileId: string) => {
|
||||
if (dirtyContents.has(fileId) || dirtyMetadataIds.has(fileId)) {
|
||||
setPendingCloseId(fileId)
|
||||
return
|
||||
}
|
||||
closeTab(fileId)
|
||||
}, [dirtyContents, dirtyMetadataIds, closeTab])
|
||||
|
||||
const handleConfirmClose = useCallback(() => {
|
||||
if (pendingCloseId) {
|
||||
closeTab(pendingCloseId)
|
||||
setPendingCloseId(null)
|
||||
}
|
||||
}, [pendingCloseId, closeTab])
|
||||
|
||||
const handleCancelClose = useCallback(() => {
|
||||
setPendingCloseId(null)
|
||||
}, [])
|
||||
|
||||
if (openTabIds.length === 0)
|
||||
return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center overflow-hidden rounded-t-lg border-b border-components-panel-border-subtle bg-components-panel-bg-alt',
|
||||
)}
|
||||
>
|
||||
{openTabIds.map((fileId) => {
|
||||
const node = nodeMap?.get(fileId)
|
||||
const name = node?.name ?? fileId
|
||||
const isActive = activeTabId === fileId
|
||||
const isDirty = dirtyContents.has(fileId) || dirtyMetadataIds.has(fileId)
|
||||
const isPreview = previewTabId === fileId
|
||||
|
||||
return (
|
||||
<FileTabItem
|
||||
key={fileId}
|
||||
fileId={fileId}
|
||||
name={name}
|
||||
isActive={isActive}
|
||||
isDirty={isDirty}
|
||||
isPreview={isPreview}
|
||||
onClick={handleTabClick}
|
||||
onClose={handleTabClose}
|
||||
onDoubleClick={handleTabDoubleClick}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<Confirm
|
||||
isShow={pendingCloseId !== null}
|
||||
type="warning"
|
||||
title={t('skillSidebar.unsavedChanges.title')}
|
||||
content={t('skillSidebar.unsavedChanges.content')}
|
||||
confirmText={t('skillSidebar.unsavedChanges.confirmClose')}
|
||||
onConfirm={handleConfirmClose}
|
||||
onCancel={handleCancelClose}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(FileTabs)
|
||||
Reference in New Issue
Block a user