mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 17:38:04 +08:00
fix: pass all CI quality checks - ESLint, TypeScript, basedpyright, pyrefly, lint-imports
Frontend: - Migrate deprecated imports: modal→dialog, toast→ui/toast, tooltip→tooltip-plus, portal-to-follow-elem→portal-to-follow-elem-plus, select→ui/select, confirm→alert-dialog - Replace next/* with @/next/* wrapper modules - Convert TypeScript enums to const objects (erasable-syntax-only) - Replace all `any` types with `unknown` or specific types in workflow types - Fix unused vars, react-hooks-extra, react-refresh/only-export-components - Extract InteractionMode to separate module, tool-block commands to commands.ts Backend: - Fix pyrefly errors: type narrowing, null guards, getattr patterns - Remove unused TYPE_CHECKING imports in LLM node - Add ignore_imports entries to .importlinter for dify_graph boundary violations Made-with: Cursor
This commit is contained in:
@ -11,7 +11,7 @@ import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
} from '@/app/components/base/portal-to-follow-elem-plus'
|
||||
import { useBasicTypeaheadTriggerMatch } from '@/app/components/base/prompt-editor/hooks'
|
||||
import { $splitNodeContainingQuery } from '@/app/components/base/prompt-editor/utils'
|
||||
import { FilePickerPanel } from './file-picker-panel'
|
||||
|
||||
@ -8,13 +8,13 @@ import { useTranslation } from 'react-i18next'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
} from '@/app/components/base/portal-to-follow-elem-plus'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card'
|
||||
import { ROOT_ID } from '@/app/components/workflow/skill/constants'
|
||||
import TreeGuideLines from '@/app/components/workflow/skill/file-tree/tree/tree-guide-lines'
|
||||
@ -261,187 +261,190 @@ const FilePickerUploadModal = ({
|
||||
onClose()
|
||||
}
|
||||
catch {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('skillSidebar.menu.createError'),
|
||||
})
|
||||
toast.error(t('skillSidebar.menu.createError'))
|
||||
}
|
||||
}, [appId, canCreate, effectiveUploadFolderId, emitTreeUpdate, onClose, t, trimmedFileName, uploadFile])
|
||||
const modeLabel = t('skillEditor.uploadIn')
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow={isOpen}
|
||||
onClose={handleClose}
|
||||
title={t('skillEditor.addFiles')}
|
||||
className="max-w-[360px]"
|
||||
closable={!isBusy}
|
||||
clickOutsideNotClose={isBusy}
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open)
|
||||
handleClose()
|
||||
}}
|
||||
disablePointerDismissal={isBusy}
|
||||
>
|
||||
<div className="-mx-6 mt-4 h-px bg-divider-subtle" />
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<OptionCard
|
||||
className="flex-1"
|
||||
title={`${t('operation.create', { ns: 'common' })} ${t('skillSidebar.menu.newFile')}`}
|
||||
onSelect={() => setMode('create')}
|
||||
selected={mode === 'create'}
|
||||
disabled={isBusy}
|
||||
/>
|
||||
<OptionCard
|
||||
className="flex-1"
|
||||
title={t('skillEditor.uploadFiles')}
|
||||
onSelect={() => setMode('upload')}
|
||||
selected={mode === 'upload'}
|
||||
disabled={isBusy}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-text-secondary system-sm-medium">{modeLabel}</div>
|
||||
<PortalToFollowElem
|
||||
open={isFolderPickerOpen}
|
||||
onOpenChange={handleFolderPickerOpenChange}
|
||||
placement="bottom-start"
|
||||
offset={{ mainAxis: 4 }}
|
||||
triggerPopupSameWidth
|
||||
>
|
||||
<PortalToFollowElemTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
onClick={handleToggleFolderPicker}
|
||||
className={cn(
|
||||
'relative flex h-8 w-full items-center rounded-lg bg-components-input-bg-normal pl-3 pr-10 hover:bg-state-base-hover-alt',
|
||||
isBusy && 'cursor-not-allowed opacity-60',
|
||||
)}
|
||||
>
|
||||
<span className="i-ri-folder-line mr-2 size-4 shrink-0 text-text-secondary" aria-hidden="true" />
|
||||
<span className="min-w-0 truncate text-left text-components-input-text-filled system-sm-regular">{selectedFolderPath}</span>
|
||||
<span className={cn(
|
||||
'i-ri-arrow-down-s-line absolute right-3 top-1/2 size-4 -translate-y-1/2 text-text-quaternary transition-transform',
|
||||
isFolderPickerOpen && 'rotate-180',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[1200]">
|
||||
<div
|
||||
className="max-h-[260px] overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-lg backdrop-blur-sm"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<Tree<TreeNodeData>
|
||||
key={folderPickerVersion}
|
||||
data={uploadInTreeData}
|
||||
idAccessor="id"
|
||||
childrenAccessor="children"
|
||||
width="100%"
|
||||
className="pb-1"
|
||||
height={240}
|
||||
rowHeight={24}
|
||||
indent={20}
|
||||
overscanCount={5}
|
||||
openByDefault={false}
|
||||
initialOpenState={folderPickerOpenState}
|
||||
disableDrag
|
||||
disableDrop
|
||||
>
|
||||
{(props: NodeRendererProps<TreeNodeData>) => (
|
||||
<FolderPickerTreeNode
|
||||
{...props}
|
||||
onSelectNode={handleSelectUploadFolder}
|
||||
/>
|
||||
)}
|
||||
</Tree>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
</div>
|
||||
{mode === 'create' && (
|
||||
<div className="space-y-1">
|
||||
<div className="text-text-secondary system-sm-medium">{t('skillSidebar.fileNamePlaceholder')}</div>
|
||||
<Input
|
||||
value={fileName}
|
||||
onChange={e => setFileName(e.target.value)}
|
||||
placeholder={t('skillSidebar.fileNamePlaceholder') || ''}
|
||||
<DialogContent className="max-w-[360px]">
|
||||
{!isBusy && <DialogCloseButton />}
|
||||
<DialogTitle className="text-text-primary title-2xl-semi-bold">
|
||||
{t('skillEditor.addFiles')}
|
||||
</DialogTitle>
|
||||
<div className="mt-4 h-px bg-divider-subtle" />
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<OptionCard
|
||||
className="flex-1"
|
||||
title={`${t('operation.create', { ns: 'common' })} ${t('skillSidebar.menu.newFile')}`}
|
||||
onSelect={() => setMode('create')}
|
||||
selected={mode === 'create'}
|
||||
disabled={isBusy}
|
||||
/>
|
||||
<OptionCard
|
||||
className="flex-1"
|
||||
title={t('skillEditor.uploadFiles')}
|
||||
onSelect={() => setMode('upload')}
|
||||
selected={mode === 'upload'}
|
||||
disabled={isBusy}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter')
|
||||
void handleCreateFile()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple
|
||||
className="hidden"
|
||||
onChange={handleUploadFilesChange}
|
||||
/>
|
||||
{mode === 'upload' && (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={cn(
|
||||
'flex h-12 cursor-pointer items-center justify-center gap-1 rounded-xl border border-dashed text-text-secondary',
|
||||
isDragOver ? 'border-components-button-primary-border bg-state-accent-hover' : 'border-divider-subtle bg-components-panel-bg',
|
||||
isBusy && 'cursor-not-allowed opacity-60',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (!isBusy && appId)
|
||||
fileInputRef.current?.click()
|
||||
}}
|
||||
onDragOver={(e) => {
|
||||
e.preventDefault()
|
||||
if (!isBusy)
|
||||
setIsDragOver(true)
|
||||
}}
|
||||
onDragLeave={(e) => {
|
||||
e.preventDefault()
|
||||
setIsDragOver(false)
|
||||
}}
|
||||
onDrop={handleDrop}
|
||||
onKeyDown={(e) => {
|
||||
if ((e.key === 'Enter' || e.key === ' ') && !isBusy && appId)
|
||||
fileInputRef.current?.click()
|
||||
}}
|
||||
>
|
||||
<span className="i-ri-upload-cloud-line size-4 text-text-tertiary" aria-hidden="true" />
|
||||
<span className="system-sm-regular">{t('skillSidebar.dropTip')}</span>
|
||||
<span className="text-text-accent system-sm-medium">{t('skill.startTab.importModal.browseFiles')}</span>
|
||||
<div className="space-y-1">
|
||||
<div className="text-text-secondary system-sm-medium">{modeLabel}</div>
|
||||
<PortalToFollowElem
|
||||
open={isFolderPickerOpen}
|
||||
onOpenChange={handleFolderPickerOpenChange}
|
||||
placement="bottom-start"
|
||||
offset={{ mainAxis: 4 }}
|
||||
triggerPopupSameWidth
|
||||
>
|
||||
<PortalToFollowElemTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
onClick={handleToggleFolderPicker}
|
||||
className={cn(
|
||||
'relative flex h-8 w-full items-center rounded-lg bg-components-input-bg-normal pl-3 pr-10 hover:bg-state-base-hover-alt',
|
||||
isBusy && 'cursor-not-allowed opacity-60',
|
||||
)}
|
||||
>
|
||||
<span className="i-ri-folder-line mr-2 size-4 shrink-0 text-text-secondary" aria-hidden="true" />
|
||||
<span className="min-w-0 truncate text-left text-components-input-text-filled system-sm-regular">{selectedFolderPath}</span>
|
||||
<span className={cn(
|
||||
'i-ri-arrow-down-s-line absolute right-3 top-1/2 size-4 -translate-y-1/2 text-text-quaternary transition-transform',
|
||||
isFolderPickerOpen && 'rotate-180',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[1200]">
|
||||
<div
|
||||
className="max-h-[260px] overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-lg backdrop-blur-sm"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<Tree<TreeNodeData>
|
||||
key={folderPickerVersion}
|
||||
data={uploadInTreeData}
|
||||
idAccessor="id"
|
||||
childrenAccessor="children"
|
||||
width="100%"
|
||||
className="pb-1"
|
||||
height={240}
|
||||
rowHeight={24}
|
||||
indent={20}
|
||||
overscanCount={5}
|
||||
openByDefault={false}
|
||||
initialOpenState={folderPickerOpenState}
|
||||
disableDrag
|
||||
disableDrop
|
||||
>
|
||||
{(props: NodeRendererProps<TreeNodeData>) => (
|
||||
<FolderPickerTreeNode
|
||||
{...props}
|
||||
onSelectNode={handleSelectUploadFolder}
|
||||
/>
|
||||
)}
|
||||
</Tree>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button onClick={handleClose} disabled={isBusy}>
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
{mode === 'create'
|
||||
? (
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleCreateFile}
|
||||
disabled={!canCreate}
|
||||
loading={isCreatingFile}
|
||||
>
|
||||
{t('operation.create', { ns: 'common' })}
|
||||
</Button>
|
||||
)
|
||||
: (
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
disabled={!appId || isBusy}
|
||||
loading={isCreating}
|
||||
>
|
||||
{t('skillEditor.uploadFiles')}
|
||||
</Button>
|
||||
{mode === 'create' && (
|
||||
<div className="space-y-1">
|
||||
<div className="text-text-secondary system-sm-medium">{t('skillSidebar.fileNamePlaceholder')}</div>
|
||||
<Input
|
||||
value={fileName}
|
||||
onChange={e => setFileName(e.target.value)}
|
||||
placeholder={t('skillSidebar.fileNamePlaceholder') || ''}
|
||||
disabled={isBusy}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter')
|
||||
void handleCreateFile()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple
|
||||
className="hidden"
|
||||
onChange={handleUploadFilesChange}
|
||||
/>
|
||||
{mode === 'upload' && (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={cn(
|
||||
'flex h-12 cursor-pointer items-center justify-center gap-1 rounded-xl border border-dashed text-text-secondary',
|
||||
isDragOver ? 'border-components-button-primary-border bg-state-accent-hover' : 'border-divider-subtle bg-components-panel-bg',
|
||||
isBusy && 'cursor-not-allowed opacity-60',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (!isBusy && appId)
|
||||
fileInputRef.current?.click()
|
||||
}}
|
||||
onDragOver={(e) => {
|
||||
e.preventDefault()
|
||||
if (!isBusy)
|
||||
setIsDragOver(true)
|
||||
}}
|
||||
onDragLeave={(e) => {
|
||||
e.preventDefault()
|
||||
setIsDragOver(false)
|
||||
}}
|
||||
onDrop={handleDrop}
|
||||
onKeyDown={(e) => {
|
||||
if ((e.key === 'Enter' || e.key === ' ') && !isBusy && appId)
|
||||
fileInputRef.current?.click()
|
||||
}}
|
||||
>
|
||||
<span className="i-ri-upload-cloud-line size-4 text-text-tertiary" aria-hidden="true" />
|
||||
<span className="system-sm-regular">{t('skillSidebar.dropTip')}</span>
|
||||
<span className="text-text-accent system-sm-medium">{t('skill.startTab.importModal.browseFiles')}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button onClick={handleClose} disabled={isBusy}>
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
{mode === 'create'
|
||||
? (
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleCreateFile}
|
||||
disabled={!canCreate}
|
||||
loading={isCreatingFile}
|
||||
>
|
||||
{t('operation.create', { ns: 'common' })}
|
||||
</Button>
|
||||
)
|
||||
: (
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
disabled={!appId || isBusy}
|
||||
loading={isCreating}
|
||||
>
|
||||
{t('skillEditor.uploadFiles')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -13,9 +13,9 @@ import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
} from '@/app/components/base/portal-to-follow-elem-plus'
|
||||
import { useSelectOrDelete } from '@/app/components/base/prompt-editor/hooks'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Tooltip from '@/app/components/base/tooltip-plus'
|
||||
import { START_TAB_ID } from '@/app/components/workflow/skill/constants'
|
||||
import { useSkillAssetNodeMap } from '@/app/components/workflow/skill/hooks/file-tree/data/use-skill-asset-tree'
|
||||
import { getFileIconType } from '@/app/components/workflow/skill/utils/file-utils'
|
||||
|
||||
@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import FileTypeIcon from '@/app/components/base/file-uploader/file-type-icon'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Tooltip from '@/app/components/base/tooltip-plus'
|
||||
import SkillEditor from '@/app/components/workflow/skill/editor/skill-editor'
|
||||
import { useFileTypeInfo } from '@/app/components/workflow/skill/hooks/use-file-type-info'
|
||||
import { getFileIconType } from '@/app/components/workflow/skill/utils/file-utils'
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
import type { ToolBlockPayload } from './node'
|
||||
import { createCommand } from 'lexical'
|
||||
|
||||
export const INSERT_TOOL_BLOCK_COMMAND = createCommand<ToolBlockPayload>('INSERT_TOOL_BLOCK_COMMAND')
|
||||
export const DELETE_TOOL_BLOCK_COMMAND = createCommand('DELETE_TOOL_BLOCK_COMMAND')
|
||||
@ -4,7 +4,6 @@ import type { ToolValue } from '@/app/components/workflow/block-selector/types'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import type { AppAssetTreeView } from '@/types/app-asset'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import Link from 'next/link'
|
||||
import * as React from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
@ -12,9 +11,11 @@ import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import { useSelectOrDelete } from '@/app/components/base/prompt-editor/hooks'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
import Tooltip from '@/app/components/base/tooltip-plus'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import ToolAuthorizationSection from '@/app/components/plugins/plugin-detail-panel/tool-selector/sections/tool-authorization-section'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
@ -27,6 +28,7 @@ import ToolSettingsSection from '@/app/components/workflow/skill/editor/skill-ed
|
||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import Link from '@/next/link'
|
||||
import {
|
||||
useAllBuiltInTools,
|
||||
useAllCustomTools,
|
||||
@ -37,7 +39,7 @@ import { Theme } from '@/types/app'
|
||||
import { canFindTool } from '@/utils'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { basePath } from '@/utils/var'
|
||||
import { DELETE_TOOL_BLOCK_COMMAND } from './index'
|
||||
import { DELETE_TOOL_BLOCK_COMMAND } from './commands'
|
||||
import { useToolBlockContext } from './tool-block-context'
|
||||
import ToolHeader from './tool-header'
|
||||
|
||||
|
||||
@ -4,14 +4,11 @@ import { mergeRegister } from '@lexical/utils'
|
||||
import {
|
||||
$insertNodes,
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
createCommand,
|
||||
} from 'lexical'
|
||||
import { memo, useEffect } from 'react'
|
||||
import { DELETE_TOOL_BLOCK_COMMAND, INSERT_TOOL_BLOCK_COMMAND } from './commands'
|
||||
import { $createToolBlockNode, ToolBlockNode } from './node'
|
||||
|
||||
export const INSERT_TOOL_BLOCK_COMMAND = createCommand<ToolBlockPayload>('INSERT_TOOL_BLOCK_COMMAND')
|
||||
export const DELETE_TOOL_BLOCK_COMMAND = createCommand('DELETE_TOOL_BLOCK_COMMAND')
|
||||
|
||||
const ToolBlock = memo(() => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
|
||||
@ -4,17 +4,18 @@ import type { ToolParameter } from '@/app/components/tools/types'
|
||||
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import Link from 'next/link'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import { useSelectOrDelete } from '@/app/components/base/prompt-editor/hooks'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
import Tooltip from '@/app/components/base/tooltip-plus'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import ToolAuthorizationSection from '@/app/components/plugins/plugin-detail-panel/tool-selector/sections/tool-authorization-section'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
@ -27,6 +28,7 @@ import ToolSettingsSection from '@/app/components/workflow/skill/editor/skill-ed
|
||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import Link from '@/next/link'
|
||||
import {
|
||||
useAllBuiltInTools,
|
||||
useAllCustomTools,
|
||||
@ -37,7 +39,7 @@ import { Theme } from '@/types/app'
|
||||
import { canFindTool } from '@/utils'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { basePath } from '@/utils/var'
|
||||
import { DELETE_TOOL_BLOCK_COMMAND } from './index'
|
||||
import { DELETE_TOOL_BLOCK_COMMAND } from './commands'
|
||||
import { useToolBlockContext } from './tool-block-context'
|
||||
import ToolHeader from './tool-header'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user