From ec450eb7f938272cc9efbcba89b5e1f78944362a Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Fri, 24 Apr 2026 14:36:48 +0800
Subject: [PATCH] chore(dify-ui): update tooltip and infotip migration (#35543)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
---
eslint-suppressions.json | 59 -------------
web/app/components/base/infotip/index.tsx | 2 +-
.../form-input-item.branches.spec.tsx | 6 +-
.../error-handle/error-handle-on-panel.tsx | 6 +-
.../components/form-input-type-switch.tsx | 85 ++++++++++++------
.../nodes/_base/components/help-link.tsx | 33 ++++---
.../components/__tests__/model-bar.spec.tsx | 10 +--
.../components/__tests__/tool-icon.spec.tsx | 6 +-
.../nodes/agent/components/model-bar.tsx | 88 +++++++++++--------
.../nodes/agent/components/tool-icon.tsx | 81 +++++++++--------
.../top-k-and-score-threshold.tsx | 24 +++--
.../json-schema-config-modal/code-editor.tsx | 61 ++++++++-----
.../visual-editor/edit-card/actions.tsx | 76 ++++++++++------
.../components/__tests__/copy-id.spec.tsx | 12 +--
.../nodes/tool/components/copy-id.tsx | 45 +++++-----
.../note-node/note-editor/toolbar/command.tsx | 54 ++++++------
web/docs/overlay-migration.md | 6 --
17 files changed, 345 insertions(+), 309 deletions(-)
diff --git a/eslint-suppressions.json b/eslint-suppressions.json
index 405ce77400..943d38878e 100644
--- a/eslint-suppressions.json
+++ b/eslint-suppressions.json
@@ -4270,11 +4270,6 @@
"count": 1
}
},
- "web/app/components/workflow/nodes/_base/components/error-handle/error-handle-on-panel.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/workflow/nodes/_base/components/error-handle/error-handle-type-selector.tsx": {
"no-restricted-imports": {
"count": 1
@@ -4293,16 +4288,6 @@
"count": 1
}
},
- "web/app/components/workflow/nodes/_base/components/form-input-type-switch.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
- "web/app/components/workflow/nodes/_base/components/help-link.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx": {
"no-restricted-imports": {
"count": 1
@@ -4502,22 +4487,6 @@
"count": 1
}
},
- "web/app/components/workflow/nodes/agent/components/model-bar.tsx": {
- "no-restricted-imports": {
- "count": 1
- },
- "ts/no-empty-object-type": {
- "count": 1
- }
- },
- "web/app/components/workflow/nodes/agent/components/tool-icon.tsx": {
- "no-restricted-imports": {
- "count": 1
- },
- "react/unsupported-syntax": {
- "count": 1
- }
- },
"web/app/components/workflow/nodes/agent/default.ts": {
"ts/no-explicit-any": {
"count": 3
@@ -4859,11 +4828,6 @@
"count": 1
}
},
- "web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/type.ts": {
"ts/no-explicit-any": {
"count": 2
@@ -4966,14 +4930,6 @@
"count": 1
}
},
- "web/app/components/workflow/nodes/llm/components/json-schema-config-modal/code-editor.tsx": {
- "no-restricted-imports": {
- "count": 1
- },
- "ts/no-explicit-any": {
- "count": 4
- }
- },
"web/app/components/workflow/nodes/llm/components/json-schema-config-modal/index.tsx": {
"no-restricted-imports": {
"count": 1
@@ -5009,11 +4965,6 @@
"count": 2
}
},
- "web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/actions.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/auto-width-input.tsx": {
"react/set-state-in-effect": {
"count": 1
@@ -5235,11 +5186,6 @@
"count": 5
}
},
- "web/app/components/workflow/nodes/tool/components/copy-id.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/workflow/nodes/tool/components/input-var-list.tsx": {
"ts/no-explicit-any": {
"count": 7
@@ -5405,11 +5351,6 @@
"count": 1
}
},
- "web/app/components/workflow/note-node/note-editor/toolbar/command.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/workflow/note-node/note-editor/utils.ts": {
"regexp/no-useless-quantifier": {
"count": 1
diff --git a/web/app/components/base/infotip/index.tsx b/web/app/components/base/infotip/index.tsx
index b97b499af3..ce818fe030 100644
--- a/web/app/components/base/infotip/index.tsx
+++ b/web/app/components/base/infotip/index.tsx
@@ -73,7 +73,7 @@ export function Infotip({
/>
{children}
diff --git a/web/app/components/workflow/nodes/_base/components/__tests__/form-input-item.branches.spec.tsx b/web/app/components/workflow/nodes/_base/components/__tests__/form-input-item.branches.spec.tsx
index 7786dbec17..2e95473bb2 100644
--- a/web/app/components/workflow/nodes/_base/components/__tests__/form-input-item.branches.spec.tsx
+++ b/web/app/components/workflow/nodes/_base/components/__tests__/form-input-item.branches.spec.tsx
@@ -225,7 +225,7 @@ describe('FormInputItem branches', () => {
})
expect(screen.getByText('alpha')).toBeInTheDocument()
- fireEvent.click(screen.getByRole('button'))
+ fireEvent.click(screen.getByText('alpha').closest('button') as HTMLButtonElement)
fireEvent.click(screen.getByText('beta'))
expect(onChange).toHaveBeenCalledWith({
@@ -320,9 +320,9 @@ describe('FormInputItem branches', () => {
})
await waitFor(() => {
- expect(screen.getByRole('button')).not.toBeDisabled()
+ expect(screen.getByText('Select options').closest('button')).not.toBeDisabled()
})
- fireEvent.click(screen.getByRole('button'))
+ fireEvent.click(screen.getByText('Select options').closest('button') as HTMLButtonElement)
fireEvent.click(screen.getByText('trigger-option'))
expect(onChange).toHaveBeenCalledWith({
diff --git a/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-on-panel.tsx b/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-on-panel.tsx
index 10a167c504..a00e8e1adc 100644
--- a/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-on-panel.tsx
+++ b/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-on-panel.tsx
@@ -5,7 +5,7 @@ import type {
} from '@/app/components/workflow/types'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
-import Tooltip from '@/app/components/base/tooltip'
+import { Infotip } from '@/app/components/base/infotip'
import Collapse from '../collapse'
import DefaultValue from './default-value'
import ErrorHandleTypeSelector from './error-handle-type-selector'
@@ -57,7 +57,9 @@ const ErrorHandle = ({
{t('nodes.common.errorHandle.title', { ns: 'workflow' })}
-
+
+ {t('nodes.common.errorHandle.tip', { ns: 'workflow' })}
+
{collapseIcon}
= ({
onChange,
}) => {
const { t } = useTranslation()
+ const variableLabel = t('nodes.common.typeSwitch.variable', { ns: 'workflow' })
+ const inputLabel = t('nodes.common.typeSwitch.input', { ns: 'workflow' })
+
return (
-
- onChange(VarType.variable)}
- >
-
-
-
-
- onChange(VarType.constant)}
- >
-
-
-
+ {value === VarType.variable
+ ? (
+
+ )
+ : (
+
+ onChange(VarType.variable)}
+ >
+
+
+ )}
+ />
+ {variableLabel}
+
+ )}
+ {value === VarType.constant
+ ? (
+
+ )
+ : (
+
+ onChange(VarType.constant)}
+ >
+
+
+ )}
+ />
+ {inputLabel}
+
+ )}
)
}
diff --git a/web/app/components/workflow/nodes/_base/components/help-link.tsx b/web/app/components/workflow/nodes/_base/components/help-link.tsx
index 30f95a12be..298f50738f 100644
--- a/web/app/components/workflow/nodes/_base/components/help-link.tsx
+++ b/web/app/components/workflow/nodes/_base/components/help-link.tsx
@@ -1,8 +1,7 @@
import type { BlockEnum } from '@/app/components/workflow/types'
-import { RiBookOpenLine } from '@remixicon/react'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
-import TooltipPlus from '@/app/components/base/tooltip'
import { useNodeHelpLink } from '../hooks/use-node-help-link'
type HelpLinkProps = {
@@ -17,19 +16,25 @@ const HelpLink = ({
if (!link)
return null
- return (
-
-
-
-
-
+ const label = t('userProfile.helpCenter', { ns: 'common' })
+ return (
+
+
+
+
+ )}
+ />
+ {label}
+
)
}
diff --git a/web/app/components/workflow/nodes/agent/components/__tests__/model-bar.spec.tsx b/web/app/components/workflow/nodes/agent/components/__tests__/model-bar.spec.tsx
index d85f54ed19..2127b48dca 100644
--- a/web/app/components/workflow/nodes/agent/components/__tests__/model-bar.spec.tsx
+++ b/web/app/components/workflow/nodes/agent/components/__tests__/model-bar.spec.tsx
@@ -1,5 +1,5 @@
import type { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
-import { fireEvent, render, screen } from '@testing-library/react'
+import { render, screen } from '@testing-library/react'
import { ModelBar } from '../model-bar'
type ModelProviderItem = {
@@ -52,11 +52,9 @@ describe('agent/model-bar', () => {
const emptySelector = screen.getByText((_, element) => element?.textContent === 'no-model:0')
- fireEvent.mouseEnter(emptySelector)
-
expect(emptySelector).toBeInTheDocument()
expect(screen.getByText('indicator:red')).toBeInTheDocument()
- expect(screen.getByText('workflow.nodes.agent.modelNotSelected')).toBeInTheDocument()
+ expect(screen.getByLabelText('workflow.nodes.agent.modelNotSelected')).toBeInTheDocument()
})
it('should render the selected model without warning when it is installed', () => {
@@ -69,10 +67,8 @@ describe('agent/model-bar', () => {
it('should show a warning tooltip when the selected model is not installed', () => {
render()
- fireEvent.mouseEnter(screen.getByText('openai/gpt-4.1:1'))
-
expect(screen.getByText('openai/gpt-4.1:1')).toBeInTheDocument()
expect(screen.getByText('indicator:red')).toBeInTheDocument()
- expect(screen.getByText('workflow.nodes.agent.modelNotInstallTooltip')).toBeInTheDocument()
+ expect(screen.getByLabelText('workflow.nodes.agent.modelNotInstallTooltip')).toBeInTheDocument()
})
})
diff --git a/web/app/components/workflow/nodes/agent/components/__tests__/tool-icon.spec.tsx b/web/app/components/workflow/nodes/agent/components/__tests__/tool-icon.spec.tsx
index 30a12bb528..af61b43367 100644
--- a/web/app/components/workflow/nodes/agent/components/__tests__/tool-icon.spec.tsx
+++ b/web/app/components/workflow/nodes/agent/components/__tests__/tool-icon.spec.tsx
@@ -87,19 +87,17 @@ describe('agent/tool-icon', () => {
const { rerender } = render()
- fireEvent.mouseEnter(screen.getByText('app-icon:#fff:B'))
expect(screen.getByText('indicator:yellow')).toBeInTheDocument()
- expect(screen.getByText('workflow.nodes.agent.toolNotAuthorizedTooltip:{"tool":"tool-b"}')).toBeInTheDocument()
+ expect(screen.getByLabelText('workflow.nodes.agent.toolNotAuthorizedTooltip:{"tool":"tool-b"}')).toBeInTheDocument()
mockWorkflowTools = []
mockMarketplaceIcon = 'https://example.com/market-tool.png'
rerender()
const marketplaceIcon = screen.getByRole('img', { name: 'tool icon' })
- fireEvent.mouseEnter(marketplaceIcon)
expect(marketplaceIcon).toHaveAttribute('src', 'https://example.com/market-tool.png')
expect(screen.getByText('indicator:red')).toBeInTheDocument()
- expect(screen.getByText('workflow.nodes.agent.toolNotInstallTooltip:{"tool":"tool-c"}')).toBeInTheDocument()
+ expect(screen.getByLabelText('workflow.nodes.agent.toolNotInstallTooltip:{"tool":"tool-c"}')).toBeInTheDocument()
})
it('should fall back to the group icon while tool data is still loading', () => {
diff --git a/web/app/components/workflow/nodes/agent/components/model-bar.tsx b/web/app/components/workflow/nodes/agent/components/model-bar.tsx
index 8e2f19d726..0ec0b943ef 100644
--- a/web/app/components/workflow/nodes/agent/components/model-bar.tsx
+++ b/web/app/components/workflow/nodes/agent/components/model-bar.tsx
@@ -1,7 +1,7 @@
import type { FC } from 'react'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import Tooltip from '@/app/components/base/tooltip'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
@@ -10,7 +10,10 @@ import Indicator from '@/app/components/header/indicator'
type ModelBarProps = {
provider: string
model: string
-} | {}
+} | {
+ provider?: never
+ model?: never
+}
const useAllModel = () => {
const { data: textGeneration } = useModelList(ModelTypeEnum.textGeneration)
@@ -35,23 +38,27 @@ const useAllModel = () => {
export const ModelBar: FC = (props) => {
const { t } = useTranslation()
const modelList = useAllModel()
- if (!('provider' in props)) {
+ if (props.provider === undefined) {
+ const tooltip = t('nodes.agent.modelNotSelected', { ns: 'workflow' })
+
return (
-
-
-
-
-
+
+
+
+
+
+ )}
+ />
+ {tooltip}
)
}
@@ -59,23 +66,34 @@ export const ModelBar: FC = (props) => {
provider => provider.provider === props.provider && provider.models.some(model => model.model === props.model),
)
const showWarn = modelList && !modelInstalled
- return modelList && (
-
-
-
- {showWarn && }
-
+ if (!modelList)
+ return null
+
+ const modelNotInstalledTooltip = t('nodes.agent.modelNotInstallTooltip', { ns: 'workflow' })
+ const modelSelector = (
+
+
+ {showWarn && }
+
+ )
+
+ if (modelInstalled)
+ return modelSelector
+
+ return (
+
+
+ {modelNotInstalledTooltip}
)
}
diff --git a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx
index b545c2f370..3986dcf6a4 100644
--- a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx
+++ b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx
@@ -1,9 +1,10 @@
+import type { ReactNode } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { memo, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AppIcon from '@/app/components/base/app-icon'
import { Group } from '@/app/components/base/icons/src/vender/other'
-import Tooltip from '@/app/components/base/tooltip'
import Indicator from '@/app/components/header/indicator'
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools } from '@/service/use-tools'
import { getIconFromMarketPlace } from '@/utils/get-icon'
@@ -62,44 +63,50 @@ export const ToolIcon = memo(({ providerName }: ToolIconProps) => {
throw new Error('Unknown status')
}, [name, notSuccess, status, t])
const [iconFetchError, setIconFetchError] = useState(false)
- return (
-
+
+ if (!iconFetchError && icon) {
+ if (typeof icon === 'string') {
+ iconContent = (
+
setIconFetchError(true)}
+ />
+ )
+ }
+ else if (typeof icon === 'object') {
+ iconContent = (
+
+ )
+ }
+ }
+
+ const iconNode = (
+
-
-
- {(() => {
- if (iconFetchError || !icon)
- return
- if (typeof icon === 'string') {
- return (
-

setIconFetchError(true)}
- />
- )
- }
- if (typeof icon === 'object') {
- return (
-
- )
- }
- return
- })()}
-
- {indicator &&
}
+
+ {iconContent}
+ {indicator &&
}
+
+ )
+
+ if (!notSuccess || !tooltip)
+ return iconNode
+
+ return (
+
+
+ {tooltip}
)
})
diff --git a/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx b/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx
index 814b3cea6d..b81032242f 100644
--- a/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx
+++ b/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx
@@ -9,7 +9,7 @@ import {
import { Switch } from '@langgenius/dify-ui/switch'
import { memo, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
-import Tooltip from '@/app/components/base/tooltip'
+import { Infotip } from '@/app/components/base/infotip'
import { env } from '@/env'
export type TopKAndScoreThresholdProps = {
@@ -59,10 +59,13 @@ const TopKAndScoreThreshold = ({
{t('datasetConfig.top_k', { ns: 'appDebug' })}
-
+
+ {t('datasetConfig.top_kTip', { ns: 'appDebug' })}
+
{t('datasetConfig.score_threshold', { ns: 'appDebug' })}
-
+
+ {t('datasetConfig.score_thresholdTip', { ns: 'appDebug' })}
+
+type EditorOnMount = NonNullable['onMount']>
+type MonacoEditor = Parameters[0]
+type Monaco = Parameters[1]
+
const CodeEditor: FC = ({
value,
onUpdate,
@@ -36,8 +39,8 @@ const CodeEditor: FC = ({
}) => {
const { t } = useTranslation()
const { theme } = useTheme()
- const monacoRef = useRef(null)
- const editorRef = useRef(null)
+ const monacoRef = useRef(null)
+ const editorRef = useRef(null)
const [isMounted, setIsMounted] = React.useState(false)
const containerRef = useRef(null)
@@ -50,7 +53,7 @@ const CodeEditor: FC = ({
}
}, [theme])
- const handleEditorDidMount = useCallback((editor: any, monaco: any) => {
+ const handleEditorDidMount = useCallback((editor, monaco) => {
editorRef.current = editor
monacoRef.current = monaco
@@ -83,7 +86,7 @@ const CodeEditor: FC = ({
})
monaco.editor.setTheme('light-theme')
setIsMounted(true)
- }, [])
+ }, [onBlur, onFocus])
const formatJsonContent = useCallback(() => {
if (editorRef.current)
@@ -122,24 +125,36 @@ const CodeEditor: FC = ({
{showFormatButton && (
-
-
+
+
+
+
+ )}
+ />
+ {t('operation.format', { ns: 'common' })}
)}
-
-
+
+ copy(value)}
+ >
+
+
+ )}
+ />
+ {t('operation.copy', { ns: 'common' })}
diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/actions.tsx b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/actions.tsx
index 0afedab3d2..2f3b70aefc 100644
--- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/actions.tsx
+++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/actions.tsx
@@ -1,8 +1,7 @@
import type { FC } from 'react'
-import { RiAddCircleLine, RiDeleteBinLine, RiEditLine } from '@remixicon/react'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
-import Tooltip from '@/app/components/base/tooltip'
type ActionsProps = {
disableAddBtn: boolean
@@ -18,36 +17,59 @@ const Actions: FC = ({
onDelete,
}) => {
const { t } = useTranslation()
+ const addChildFieldLabel = t('nodes.llm.jsonSchema.addChildField', { ns: 'workflow' })
+ const editLabel = t('operation.edit', { ns: 'common' })
+ const removeLabel = t('operation.remove', { ns: 'common' })
return (
-
-
+
+
+
+
+ )}
+ />
+ {addChildFieldLabel}
-
-
+
+
+
+
+ )}
+ />
+ {editLabel}
-
-
+
+
+
+
+ )}
+ />
+ {removeLabel}
)
diff --git a/web/app/components/workflow/nodes/tool/components/__tests__/copy-id.spec.tsx b/web/app/components/workflow/nodes/tool/components/__tests__/copy-id.spec.tsx
index ee6791ca03..2fb7e66e24 100644
--- a/web/app/components/workflow/nodes/tool/components/__tests__/copy-id.spec.tsx
+++ b/web/app/components/workflow/nodes/tool/components/__tests__/copy-id.spec.tsx
@@ -20,27 +20,21 @@ describe('tool/copy-id', () => {
it('should copy content and reset copied state when mouse leaves', () => {
const { container } = render()
- const trigger = screen.getByText('tool-123').parentElement as HTMLElement
+ const trigger = screen.getByRole('button', { name: 'appOverview.overview.appInfo.embedded.copy' })
const wrapper = container.querySelector('.inline-flex') as HTMLElement
- act(() => {
- fireEvent.mouseEnter(trigger)
- })
- expect(screen.getByText('appOverview.overview.appInfo.embedded.copy')).toBeInTheDocument()
-
act(() => {
fireEvent.click(trigger)
vi.advanceTimersByTime(100)
})
expect(copy).toHaveBeenCalledWith('tool-123')
- expect(screen.getByText('appOverview.overview.appInfo.embedded.copied')).toBeInTheDocument()
+ expect(trigger).toHaveAccessibleName('appOverview.overview.appInfo.embedded.copied')
act(() => {
fireEvent.mouseLeave(wrapper)
vi.advanceTimersByTime(100)
- fireEvent.mouseEnter(trigger)
})
- expect(screen.getByText('appOverview.overview.appInfo.embedded.copy')).toBeInTheDocument()
+ expect(trigger).toHaveAccessibleName('appOverview.overview.appInfo.embedded.copy')
})
it('should stop click propagation from the outer wrapper', () => {
diff --git a/web/app/components/workflow/nodes/tool/components/copy-id.tsx b/web/app/components/workflow/nodes/tool/components/copy-id.tsx
index eaf3d1bec5..18a510caaf 100644
--- a/web/app/components/workflow/nodes/tool/components/copy-id.tsx
+++ b/web/app/components/workflow/nodes/tool/components/copy-id.tsx
@@ -1,11 +1,10 @@
'use client'
-import { RiFileCopyLine } from '@remixicon/react'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import copy from 'copy-to-clipboard'
import { debounce } from 'es-toolkit/compat'
import * as React from 'react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
-import Tooltip from '@/app/components/base/tooltip'
type Props = {
content: string
@@ -25,27 +24,33 @@ const CopyFeedbackNew = ({ content }: Props) => {
const onMouseLeave = debounce(() => {
setIsCopied(false)
}, 100)
+ const tooltip = (isCopied
+ ? t(`${prefixEmbedded}.copied`, { ns: 'appOverview' })
+ : t(`${prefixEmbedded}.copy`, { ns: 'appOverview' })) || ''
return (
e.stopPropagation()} onMouseLeave={onMouseLeave}>
-
-
+
+
+
+ {content}
+
+
+
+ )}
+ />
+
+ {tooltip}
+
)
diff --git a/web/app/components/workflow/note-node/note-editor/toolbar/command.tsx b/web/app/components/workflow/note-node/note-editor/toolbar/command.tsx
index ab4bf8c7bb..9f9c02de33 100644
--- a/web/app/components/workflow/note-node/note-editor/toolbar/command.tsx
+++ b/web/app/components/workflow/note-node/note-editor/toolbar/command.tsx
@@ -1,17 +1,10 @@
import { cn } from '@langgenius/dify-ui/cn'
-import {
- RiBold,
- RiItalic,
- RiLink,
- RiListUnordered,
- RiStrikethrough,
-} from '@remixicon/react'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import {
memo,
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
-import Tooltip from '@/app/components/base/tooltip'
import { useStore } from '../store'
import { useCommand } from './hooks'
@@ -32,15 +25,15 @@ const Command = ({
const icon = useMemo(() => {
switch (type) {
case 'bold':
- return
+ return
case 'italic':
- return
+ return
case 'strikethrough':
- return
+ return
case 'link':
- return
+ return
case 'bullet':
- return
+ return
}
}, [type, selectedIsBold, selectedIsItalic, selectedIsStrikeThrough, selectedIsLink, selectedIsBullet])
@@ -60,22 +53,27 @@ const Command = ({
}, [type, t])
return (
-
-
+ handleCommand(type)}
+ >
+ {icon}
+
)}
- onClick={() => handleCommand(type)}
- >
- {icon}
-
+ />
+ {tip}
)
}
diff --git a/web/docs/overlay-migration.md b/web/docs/overlay-migration.md
index 73c0f02d9d..cb020f9ab6 100644
--- a/web/docs/overlay-migration.md
+++ b/web/docs/overlay-migration.md
@@ -44,12 +44,6 @@ This document tracks the Dify-web migration away from legacy overlay APIs.
## Allowlist maintenance
-- After each migration batch, run:
-
-```sh
-pnpm -C web lint:fix --prune-suppressions
-```
-
- If a migrated file was in the allowlist, remove it from `web/eslint.constants.mjs` in the same PR.
- Never increase allowlist scope to bypass new code.