From 3db107edc9cb755668f11f29cc22601fddf1b28f Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Mon, 27 Apr 2026 12:46:43 +0800
Subject: [PATCH 1/3] chore(ci): increase tsslint heap limit (#35591)
---
.github/workflows/style.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml
index 35b8f86cab..6b00899cf0 100644
--- a/.github/workflows/style.yml
+++ b/.github/workflows/style.yml
@@ -110,6 +110,8 @@ jobs:
- name: Web tsslint
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ./web
+ env:
+ NODE_OPTIONS: --max-old-space-size=4096
run: vp run lint:tss
- name: Web type check
From 818a71d6379efa2634d5d66960dc353098323729 Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Mon, 27 Apr 2026 13:03:38 +0800
Subject: [PATCH 2/3] refactor(web): migrate simple overlay tooltips (#35588)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
---
eslint-suppressions.json | 56 ---------
.../src/select/__tests__/index.spec.tsx | 6 +-
.../base/__tests__/header.spec.tsx | 8 --
.../data-source/base/header.tsx | 37 +++---
.../breadcrumbs/__tests__/bucket.spec.tsx | 6 +-
.../file-list/header/breadcrumbs/bucket.tsx | 32 +++--
.../common/__tests__/summary-status.spec.tsx | 3 -
.../completed/common/summary-status.tsx | 28 +++--
.../secret-key/__tests__/input-copy.spec.tsx | 6 +-
.../develop/secret-key/input-copy.tsx | 33 ++++--
.../base/__tests__/key-value-item.spec.tsx | 16 ++-
.../__tests__/icon-with-tooltip.spec.tsx | 49 ++------
.../plugins/base/badges/icon-with-tooltip.tsx | 25 ++--
.../plugins/base/key-value-item.tsx | 24 ++--
.../__tests__/plugin-source-badge.spec.tsx | 74 +++---------
.../components/plugin-source-badge.tsx | 24 ++--
.../plugin-detail-panel/endpoint-card.tsx | 39 +++++--
.../__tests__/task-status-indicator.spec.tsx | 16 +--
.../components/task-status-indicator.tsx | 109 +++++++++---------
.../mcp/detail/__tests__/content.spec.tsx | 11 +-
.../components/tools/mcp/detail/content.tsx | 67 +++++++----
21 files changed, 299 insertions(+), 370 deletions(-)
diff --git a/eslint-suppressions.json b/eslint-suppressions.json
index 1bff82ac17..b3c7a18fea 100644
--- a/eslint-suppressions.json
+++ b/eslint-suppressions.json
@@ -2422,21 +2422,11 @@
"count": 1
}
},
- "web/app/components/datasets/documents/create-from-pipeline/data-source/base/header.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx": {
"ts/no-explicit-any": {
"count": 1
}
},
- "web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/bucket.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/list/item.tsx": {
"no-restricted-imports": {
"count": 1
@@ -2525,11 +2515,6 @@
"count": 1
}
},
- "web/app/components/datasets/documents/detail/completed/common/summary-status.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/datasets/documents/detail/completed/components/index.ts": {
"no-barrel-files/no-barrel-files": {
"count": 3
@@ -2789,11 +2774,6 @@
"count": 2
}
},
- "web/app/components/develop/secret-key/input-copy.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/develop/secret-key/secret-key-generate.tsx": {
"no-restricted-imports": {
"count": 1
@@ -3159,16 +3139,6 @@
"count": 1
}
},
- "web/app/components/plugins/base/badges/icon-with-tooltip.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
- "web/app/components/plugins/base/key-value-item.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/plugins/card/index.tsx": {
"ts/no-non-null-asserted-optional-chain": {
"count": 1
@@ -3328,24 +3298,11 @@
"count": 2
}
},
- "web/app/components/plugins/plugin-detail-panel/detail-header/components/plugin-source-badge.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/plugins/plugin-detail-panel/detail-header/hooks/index.ts": {
"no-barrel-files/no-barrel-files": {
"count": 3
}
},
- "web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx": {
- "no-restricted-imports": {
- "count": 1
- },
- "ts/no-explicit-any": {
- "count": 2
- }
- },
"web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx": {
"no-restricted-imports": {
"count": 1
@@ -3544,11 +3501,6 @@
"count": 1
}
},
- "web/app/components/plugins/plugin-page/plugin-tasks/components/task-status-indicator.tsx": {
- "no-restricted-imports": {
- "count": 1
- }
- },
"web/app/components/plugins/readme-panel/index.tsx": {
"react/unsupported-syntax": {
"count": 1
@@ -3822,14 +3774,6 @@
"count": 1
}
},
- "web/app/components/tools/mcp/detail/content.tsx": {
- "no-restricted-imports": {
- "count": 1
- },
- "ts/no-explicit-any": {
- "count": 3
- }
- },
"web/app/components/tools/mcp/detail/tool-item.tsx": {
"no-restricted-imports": {
"count": 1
diff --git a/packages/dify-ui/src/select/__tests__/index.spec.tsx b/packages/dify-ui/src/select/__tests__/index.spec.tsx
index eab980a607..9e3e945de0 100644
--- a/packages/dify-ui/src/select/__tests__/index.spec.tsx
+++ b/packages/dify-ui/src/select/__tests__/index.spec.tsx
@@ -231,10 +231,8 @@ describe('Select wrappers', () => {
,
)
- screen.getByRole('group', { name: 'select positioner' }).element().dispatchEvent(new MouseEvent('mouseover', {
- bubbles: true,
- }))
- asHTMLElement(screen.getByRole('dialog', { name: 'select popup' }).element()).click()
+ await screen.getByRole('group', { name: 'select positioner' }).hover()
+ await screen.getByRole('dialog', { name: 'select popup' }).click()
screen.getByRole('listbox', { name: 'select list' }).element().dispatchEvent(new FocusEvent('focusin', {
bubbles: true,
}))
diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/base/__tests__/header.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/base/__tests__/header.spec.tsx
index a6abad358e..bc3b025ded 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/data-source/base/__tests__/header.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/base/__tests__/header.spec.tsx
@@ -2,18 +2,10 @@ import { render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import Header from '../header'
-vi.mock('@langgenius/dify-ui/button', () => ({
- Button: ({ children }: { children: React.ReactNode }) => ,
-}))
-
vi.mock('@/app/components/base/divider', () => ({
default: () => ,
}))
-vi.mock('@/app/components/base/tooltip', () => ({
- default: ({ children }: { children: React.ReactNode }) =>
{children}
,
-}))
-
vi.mock('../credential-selector', () => ({
default: () => ,
}))
diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/base/header.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/base/header.tsx
index a285946272..c91012bf4a 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/data-source/base/header.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/base/header.tsx
@@ -1,10 +1,9 @@
import type { CredentialSelectorProps } from './credential-selector'
import { Button } from '@langgenius/dify-ui/button'
-import { RiBookOpenLine, RiEqualizer2Line } from '@remixicon/react'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Divider from '@/app/components/base/divider'
-import Tooltip from '@/app/components/base/tooltip'
import CredentialSelector from './credential-selector'
type HeaderProps = {
@@ -22,6 +21,7 @@ const Header = ({
...rest
}: HeaderProps) => {
const { t } = useTranslation()
+ const configurationTip = t('configurationTip', { ns: 'datasetPipeline', pluginName })
return (
@@ -30,20 +30,23 @@ const Header = ({
{...rest}
/>
-
-
+
+
+
+
+ )}
+ />
+
+ {configurationTip}
+
-
+
{docTitle}
diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/__tests__/bucket.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/__tests__/bucket.spec.tsx
index 83e17e6e04..b0a49eee0d 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/__tests__/bucket.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/__tests__/bucket.spec.tsx
@@ -5,9 +5,6 @@ import Bucket from '../bucket'
vi.mock('@/app/components/base/icons/src/public/knowledge/online-drive', () => ({
BucketsGray: (props: React.SVGProps) => ,
}))
-vi.mock('@/app/components/base/tooltip', () => ({
- default: ({ children }: { children?: React.ReactNode }) => {children}
,
-}))
describe('Bucket', () => {
const defaultProps = {
@@ -32,8 +29,7 @@ describe('Bucket', () => {
it('should call handleBackToBucketList on icon button click', () => {
render()
- const buttons = screen.getAllByRole('button')
- fireEvent.click(buttons[0]!)
+ fireEvent.click(screen.getByRole('button', { name: 'datasetPipeline.onlineDrive.breadcrumbs.allBuckets' }))
expect(defaultProps.handleBackToBucketList).toHaveBeenCalledOnce()
})
diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/bucket.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/bucket.tsx
index 003aee6542..384188502b 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/bucket.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/bucket.tsx
@@ -1,9 +1,10 @@
+import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { BucketsGray } from '@/app/components/base/icons/src/public/knowledge/online-drive'
-import Tooltip from '@/app/components/base/tooltip'
type BucketProps = {
bucketName: string
@@ -27,19 +28,28 @@ const Bucket = ({
if (!disabled)
handleClickBucketName()
}, [disabled, handleClickBucketName])
+ const allBucketsLabel = t('onlineDrive.breadcrumbs.allBuckets', { ns: 'datasetPipeline' })
return (
<>
-
-
+
+
+
+
+ )}
+ />
+
+ {allBucketsLabel}
+
/
)}
@@ -262,7 +289,7 @@ const MCPDetailContent: FC = ({
-
+
{t('mcp.update', { ns: 'tools' })}
From 6c089cab6671b23c4017c8cf51d44f9b188e7529 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?=
Date: Mon, 27 Apr 2026 13:27:19 +0800
Subject: [PATCH 3/3] fix(web): migrate variable type selector overlay (#35590)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
---
eslint-suppressions.json | 8 --
.../__tests__/variable-type-select.spec.tsx | 3 +-
.../components/variable-type-select.tsx | 76 ++++++++++---------
3 files changed, 42 insertions(+), 45 deletions(-)
diff --git a/eslint-suppressions.json b/eslint-suppressions.json
index b3c7a18fea..1e7a2662ed 100644
--- a/eslint-suppressions.json
+++ b/eslint-suppressions.json
@@ -5338,14 +5338,6 @@
"count": 2
}
},
- "web/app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx": {
- "no-restricted-imports": {
- "count": 1
- },
- "ts/no-explicit-any": {
- "count": 4
- }
- },
"web/app/components/workflow/panel/chat-variable-panel/type.ts": {
"erasable-syntax-only/enums": {
"count": 1
diff --git a/web/app/components/workflow/panel/chat-variable-panel/components/__tests__/variable-type-select.spec.tsx b/web/app/components/workflow/panel/chat-variable-panel/components/__tests__/variable-type-select.spec.tsx
index 3a7df8a3bf..d0831c319c 100644
--- a/web/app/components/workflow/panel/chat-variable-panel/components/__tests__/variable-type-select.spec.tsx
+++ b/web/app/components/workflow/panel/chat-variable-panel/components/__tests__/variable-type-select.spec.tsx
@@ -36,8 +36,9 @@ describe('VariableTypeSelector', () => {
await user.keyboard('{Escape}')
await waitFor(() => {
- expect(screen.queryByText('number')).not.toBeInTheDocument()
+ expect(screen.getByRole('combobox')).toHaveAttribute('aria-expanded', 'false')
})
+ expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
})
it('keeps the custom popup class in in-cell mode', async () => {
diff --git a/web/app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx b/web/app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx
index 94a0100de2..e1f776f3d5 100644
--- a/web/app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx
+++ b/web/app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx
@@ -1,38 +1,47 @@
'use client'
import { cn } from '@langgenius/dify-ui/cn'
-import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
+import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select'
import * as React from 'react'
import { useState } from 'react'
-import {
- PortalToFollowElem,
- PortalToFollowElemContent,
- PortalToFollowElemTrigger,
-} from '@/app/components/base/portal-to-follow-elem'
-type Props = {
+type Props = {
inCell?: boolean
- value?: any
- list: any
- onSelect: (value: any) => void
+ value?: T
+ list: readonly T[]
+ onSelect: (value: T) => void
popupClassName?: string
}
-const VariableTypeSelector = ({
+const VariableTypeSelector = ({
inCell = false,
value,
list,
onSelect,
popupClassName,
-}: Props) => {
+}: Props) => {
const [open, setOpen] = useState(false)
+ const handleValueChange = (nextValue: string | null) => {
+ if (!nextValue)
+ return
+
+ const nextItem = list.find(item => item === nextValue)
+ if (!nextItem)
+ return
+
+ onSelect(nextItem)
+ }
+
return (
- setOpen(v => !v)}
- placement="bottom"
+ onOpenChange={setOpen}
+ onValueChange={handleValueChange}
>
- setOpen(v => !v)}>
+
{value}
-
+
-
-
-
- {list.map((item: any) => (
-
{
- onSelect(item)
- setOpen(false)
- }}
- >
-
{item}
- {value === item &&
}
-
- ))}
-
-
-
+
+
+ {list.map(item => (
+
+ {item}
+
+
+ ))}
+
+
)
}