diff --git a/oxlint-suppressions.json b/oxlint-suppressions.json
index 80f50724af9..c71ba7bc5ef 100644
--- a/oxlint-suppressions.json
+++ b/oxlint-suppressions.json
@@ -3017,11 +3017,6 @@
"count": 2
}
},
- "web/app/components/integrations/index.tsx": {
- "better-tailwindcss/enforce-logical-properties": {
- "count": 4
- }
- },
"web/app/components/integrations/sidebar-nav-item.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 2
@@ -3463,11 +3458,6 @@
"count": 2
}
},
- "web/app/components/plugins/plugin-page/plugins-panel-results.tsx": {
- "better-tailwindcss/enforce-logical-properties": {
- "count": 1
- }
- },
"web/app/components/plugins/plugin-tags-filter/compact-trigger.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 4
@@ -6451,11 +6441,6 @@
"count": 2
}
},
- "web/features/agent-v2/roster/components/agent-roster-list.tsx": {
- "better-tailwindcss/enforce-logical-properties": {
- "count": 5
- }
- },
"web/features/agent-v2/roster/components/agent-workflow-references-menu.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 1
@@ -6776,11 +6761,6 @@
"count": 13
}
},
- "web/features/skills/page.tsx": {
- "better-tailwindcss/enforce-logical-properties": {
- "count": 4
- }
- },
"web/features/tag-management/components/tag-filter.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 3
diff --git a/web/app/components/apps/list.tsx b/web/app/components/apps/list.tsx
index 32b052748b4..f98f3ecd5fb 100644
--- a/web/app/components/apps/list.tsx
+++ b/web/app/components/apps/list.tsx
@@ -4,13 +4,6 @@ import type { GetAppsData } from '@dify/contracts/api/console/apps/types.gen'
import type { RecommendedAppResponse } from '@dify/contracts/api/console/explore/types.gen'
import type { AppListCreationDialog } from './app-list-creation-modals'
import type { AppListUrlQuery } from './query-params'
-import {
- ScrollArea,
- ScrollAreaContent,
- ScrollAreaScrollbar,
- ScrollAreaThumb,
- ScrollAreaViewport,
-} from '@langgenius/dify-ui/scroll-area'
import { useDebounce } from 'ahooks'
import { useAtomValue } from 'jotai'
import { throttle, useQueryStates } from 'nuqs'
@@ -132,57 +125,44 @@ export function List({ onCreateLearnDify, onTryLearnDify }: Props) {
)}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/web/app/components/integrations/index.tsx b/web/app/components/integrations/index.tsx
index 18efdc41af2..8483e1894ad 100644
--- a/web/app/components/integrations/index.tsx
+++ b/web/app/components/integrations/index.tsx
@@ -19,13 +19,6 @@ import {
DrawerViewport,
} from '@langgenius/dify-ui/drawer'
import { IconButton } from '@langgenius/dify-ui/icon-button'
-import {
- ScrollArea,
- ScrollAreaContent,
- ScrollAreaScrollbar,
- ScrollAreaThumb,
- ScrollAreaViewport,
-} from '@langgenius/dify-ui/scroll-area'
import { Suspense, useId, useRef, useState, useSyncExternalStore } from 'react'
import { useTranslation } from 'react-i18next'
import { UpdateSettingDialog } from '@/app/components/header/account-setting/update-setting-dialog'
@@ -278,7 +271,7 @@ export default function IntegrationsPage({
'flex shrink-0 flex-col bg-components-panel-bg px-2 py-2 transition-[width]',
isCompact
? 'h-full w-full items-stretch overflow-y-auto'
- : 'w-50 items-end border-r border-divider-burn',
+ : 'w-50 items-end border-e border-divider-burn',
)}
data-step-by-step-tour-target={STEP_BY_STEP_TOUR_TARGETS.integration}
>
@@ -287,7 +280,7 @@ export default function IntegrationsPage({
>
@@ -328,7 +321,7 @@ export default function IntegrationsPage({
>
{toolsNavItemContent}
-
+
{toolItems.map((item) => (
) : (
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
)}
diff --git a/web/app/components/integrations/section-layout.tsx b/web/app/components/integrations/section-layout.tsx
index 602aac5ac31..2c6ae07c960 100644
--- a/web/app/components/integrations/section-layout.tsx
+++ b/web/app/components/integrations/section-layout.tsx
@@ -1,13 +1,6 @@
'use client'
import type { ReactNode } from 'react'
-import {
- ScrollArea,
- ScrollAreaContent,
- ScrollAreaScrollbar,
- ScrollAreaThumb,
- ScrollAreaViewport,
-} from '@langgenius/dify-ui/scroll-area'
type IntegrationSectionLayoutProps = {
bodyClassName?: string
@@ -21,19 +14,12 @@ export function IntegrationSectionLayout({
label,
}: IntegrationSectionLayoutProps) {
return (
-
-
-
- {children}
-
-
-
-
-
-
+
)
}
diff --git a/web/app/components/integrations/tool-provider-list.tsx b/web/app/components/integrations/tool-provider-list.tsx
index d3ad4fd87f9..30ab5710582 100644
--- a/web/app/components/integrations/tool-provider-list.tsx
+++ b/web/app/components/integrations/tool-provider-list.tsx
@@ -4,13 +4,6 @@ import type { ToolCategory } from '@/app/components/integrations/routes'
import type { ToolsContentInset } from '@/app/components/tools/content-inset'
import type { Collection } from '@/app/components/tools/types'
import { cn } from '@langgenius/dify-ui/cn'
-import {
- ScrollArea,
- ScrollAreaContent,
- ScrollAreaScrollbar,
- ScrollAreaThumb,
- ScrollAreaViewport,
-} from '@langgenius/dify-ui/scroll-area'
import { useQuery } from '@tanstack/react-query'
import { useCallback, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -198,69 +191,62 @@ const ProviderList = ({ category, contentInset = 'default', layout }: ProviderLi
const body = (
<>
-
- $['menus.tools'], { ns: 'navigation' })}
- className="overscroll-contain"
- role="region"
- >
-
- {activeTab !== 'mcp' && (
- 0}
- isLoading={isCollectionListLoading}
- useIntegrationsCard={contentInset === 'compact'}
- isSearchResultEmpty={isCollectionSearchEmpty}
- showCreateCard={shouldShowCustomToolCreateCard}
- onRefreshData={refetch}
- onSelectProvider={setCurrentProviderId}
- />
- )}
- {!isCollectionListLoading &&
- !activeTabCollectionList.length &&
- activeTab === 'builtin' && (
- $.noTools, { ns: 'tools' })}
- className={cn('h-56 shrink-0', toolListFrameClassName)}
- />
- )}
- {isCollectionSearchEmpty && activeTab === 'builtin' && (
-
- )}
- {marketplace && activeTab === 'builtin' && (
-
- )}
- {activeTab === 'mcp' && (
-
- )}
-
-
-
-
-
-
+
$['menus.tools'], { ns: 'navigation' })}
+ className="flex min-h-0 grow flex-col overflow-y-auto overscroll-contain bg-components-panel-bg"
+ role="region"
+ >
+ {activeTab !== 'mcp' && (
+
0}
+ isLoading={isCollectionListLoading}
+ useIntegrationsCard={contentInset === 'compact'}
+ isSearchResultEmpty={isCollectionSearchEmpty}
+ showCreateCard={shouldShowCustomToolCreateCard}
+ onRefreshData={refetch}
+ onSelectProvider={setCurrentProviderId}
+ />
+ )}
+ {!isCollectionListLoading &&
+ !activeTabCollectionList.length &&
+ activeTab === 'builtin' && (
+ $.noTools, { ns: 'tools' })}
+ className={cn('h-56 shrink-0', toolListFrameClassName)}
+ />
+ )}
+ {isCollectionSearchEmpty && activeTab === 'builtin' && (
+
+ )}
+ {marketplace && activeTab === 'builtin' && (
+
+ )}
+ {activeTab === 'mcp' && (
+
+ )}
+
{currentProvider && !currentProvider.plugin_id && (
+ <>
{isFetching
? t(($) => $.loading, { ns: 'common' })
@@ -134,85 +122,82 @@ const PluginsPanelResults = ({
(hasVisibleBuiltinTools ? filteredBuiltinTools.length : 0),
})}
-
-
- {showCategoryEmptyState && categoryEmptyState && (
-
- )}
- {(hasVisiblePlugins || hasVisibleBuiltinTools) && (
-
- {filteredBuiltinTools.map((collection, index) => (
-
- ))}
-
- )}
- {!isLastPage && (
-
- {isFetching ? (
-
- ) : autoLoadNextPage ? null : (
-
- )}
- {autoLoadNextPage && (
-
- )}
-
- )}
- {marketplace && hasToolMarketplacePanel && (
-
- )}
- {marketplace && categoryMarketplace && (
-
- )}
-
-
-
-
-
-
+ {showCategoryEmptyState && categoryEmptyState && (
+
+ )}
+ {(hasVisiblePlugins || hasVisibleBuiltinTools) && (
+
+ {filteredBuiltinTools.map((collection, index) => (
+
+ ))}
+
+ )}
+ {!isLastPage && (
+
+ {isFetching ? (
+
+ ) : autoLoadNextPage ? null : (
+
+ )}
+ {autoLoadNextPage && (
+
+ )}
+
+ )}
+ {marketplace && hasToolMarketplacePanel && (
+
+ )}
+ {marketplace && categoryMarketplace && (
+
+ )}
+
+ >
)
}
diff --git a/web/features/agent-v2/__tests__/delete-agent.browser.spec.tsx b/web/features/agent-v2/__tests__/delete-agent.browser.spec.tsx
index 6dc5b463912..96406bb5fcd 100644
--- a/web/features/agent-v2/__tests__/delete-agent.browser.spec.tsx
+++ b/web/features/agent-v2/__tests__/delete-agent.browser.spec.tsx
@@ -180,7 +180,9 @@ it('focuses the next card without moving the roster scroll position', async () =
const targetName = 'Agent 15'
const { screen, queryClient, openDelete } = await setup(agents)
try {
- const viewport = screen.getByRole('region', { name: 'Agents', exact: true }).element()
+ const viewport = screen
+ .getByRole('region', { name: 'Agents', exact: true })
+ .element().parentElement!
await expect.poll(() => viewport.scrollHeight).toBeGreaterThan(viewport.clientHeight)
viewport.scrollTo({ top: 600 })
await expect.poll(() => viewport.scrollTop).toBeGreaterThan(0)
diff --git a/web/features/agent-v2/roster/components/agent-roster-list.tsx b/web/features/agent-v2/roster/components/agent-roster-list.tsx
index 93c5d8e90be..0759c16abeb 100644
--- a/web/features/agent-v2/roster/components/agent-roster-list.tsx
+++ b/web/features/agent-v2/roster/components/agent-roster-list.tsx
@@ -1,8 +1,7 @@
'use client'
import type { AgentAppPartial } from '@dify/contracts/api/console/agent/types.gen'
-import type { ScrollAreaViewportProps } from '@langgenius/dify-ui/scroll-area'
-import type { RefObject } from 'react'
+import type { ComponentProps, RefObject } from 'react'
import {
AlertDialog,
AlertDialogContent,
@@ -19,13 +18,6 @@ import {
} from '@langgenius/dify-ui/context-menu'
import { IconButton } from '@langgenius/dify-ui/icon-button'
import { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger } from '@langgenius/dify-ui/menu'
-import {
- ScrollArea,
- ScrollAreaContent,
- ScrollAreaScrollbar,
- ScrollAreaThumb,
- ScrollAreaViewport,
-} from '@langgenius/dify-ui/scroll-area'
import { useMutation } from '@tanstack/react-query'
import { useId, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -63,7 +55,7 @@ export type AgentRosterListState =
type AgentRosterListProps = {
state: AgentRosterListState
-} & Pick
+} & Pick, 'aria-labelledby'>
type DeleteAgentDialogPayload = Pick & {
fallbackFocus: RefObject
@@ -106,9 +98,9 @@ function AgentRosterSkeleton() {
-
))}
@@ -412,7 +404,7 @@ function AgentRosterItem({
)}
-
+
{hasPublishedReferences ? (
createAlertDialogHandle())
- const scrollViewportRef = useRef(null)
+ const regionRef = useRef(null)
const deletion = useMutation(
consoleQuery.agent.byAgentId.delete.mutationOptions({ context: { silent: true } }),
)
return (
<>
-
-
-
+ {state.status === 'pending' && (
+
+ )}
+ {state.status === 'error' && (
+ $['roster.loadingError'], { ns: 'agentRoster' })}
+ />
+ )}
+ {state.status === 'ready' && state.agents.length === 0 && (
+ $['roster.emptySearch'], { ns: 'agentRoster' })
+ : t(($) => $['roster.empty'], { ns: 'agentRoster' })
+ }
+ />
+ )}
+ {state.status === 'ready' && state.agents.length > 0 && (
+ $['roster.listLabel'])}
+ className={AGENT_ROSTER_GRID_CLASS_NAME}
>
- {state.status === 'pending' && (
-
- )}
- {state.status === 'error' && (
- $['roster.loadingError'], { ns: 'agentRoster' })}
+ {state.agents.map((agent) => (
+ {
+ deleteDialog.openWithPayload({
+ id: agent.id,
+ name: agent.name,
+ adjacentFocusTargets: getAdjacentFocusTargets(item, (sibling) =>
+ sibling.querySelector(':scope > a[href], :scope > button'),
+ ),
+ fallbackFocus: { current: null },
+ })
+ }}
/>
- )}
- {state.status === 'ready' && state.agents.length === 0 && (
- $['roster.emptySearch'], { ns: 'agentRoster' })
- : t(($) => $['roster.empty'], { ns: 'agentRoster' })
- }
- />
- )}
- {state.status === 'ready' && state.agents.length > 0 && (
- $['roster.listLabel'])}
- className={AGENT_ROSTER_GRID_CLASS_NAME}
- >
- {state.agents.map((agent) => (
- {
- deleteDialog.openWithPayload({
- id: agent.id,
- name: agent.name,
- adjacentFocusTargets: getAdjacentFocusTargets(item, (sibling) =>
- sibling.querySelector(':scope > a[href], :scope > button'),
- ),
- fallbackFocus: { current: null },
- })
- }}
- />
- ))}
-
- )}
- {state.status === 'ready' && state.footer.status === 'error' && (
-
- {t(($) => $['roster.loadingError'], { ns: 'agentRoster' })}
-
-
- )}
- {state.status === 'ready' && state.footer.status === 'load-more' && (
-
-
-
- )}
-
-
-
-
-
-
+ ))}
+
+ )}
+ {state.status === 'ready' && state.footer.status === 'error' && (
+
+ {t(($) => $['roster.loadingError'], { ns: 'agentRoster' })}
+
+
+ )}
+ {state.status === 'ready' && state.footer.status === 'load-more' && (
+
+
+
+ )}
+
{
@@ -593,7 +575,7 @@ export function AgentRosterList({
{ params: { agent_id: payload.id } },
{
onSuccess: () => {
- payload.fallbackFocus.current = scrollViewportRef.current
+ payload.fallbackFocus.current = regionRef.current
deleteDialog.close()
},
},
diff --git a/web/features/agent-v2/roster/page.tsx b/web/features/agent-v2/roster/page.tsx
index 3e8382f25cf..cd46aa67edf 100644
--- a/web/features/agent-v2/roster/page.tsx
+++ b/web/features/agent-v2/roster/page.tsx
@@ -99,8 +99,8 @@ export default function RosterPage() {
useDocumentTitle(pageTitle)
return (
-
-
+
+
)
}
diff --git a/web/features/skills/page.tsx b/web/features/skills/page.tsx
index c2cf4ae4d83..403a6d7d8e4 100644
--- a/web/features/skills/page.tsx
+++ b/web/features/skills/page.tsx
@@ -31,13 +31,6 @@ import { Field, FieldLabel } from '@langgenius/dify-ui/field'
import { IconButton } from '@langgenius/dify-ui/icon-button'
import { InputGroup, InputGroupAddon, InputGroupInput } from '@langgenius/dify-ui/input-group'
import { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger } from '@langgenius/dify-ui/menu'
-import {
- ScrollArea,
- ScrollAreaContent,
- ScrollAreaScrollbar,
- ScrollAreaThumb,
- ScrollAreaViewport,
-} from '@langgenius/dify-ui/scroll-area'
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useDebounce } from 'ahooks'
import { useQueryState } from 'nuqs'
@@ -201,7 +194,7 @@ function SkillPlaceholderState({
-