feat(agent-v2): restore roster sidebar

This commit is contained in:
yyh
2026-06-04 16:14:47 +08:00
parent f61f15371a
commit 56ed953e2a
25 changed files with 238 additions and 41 deletions

View File

@ -0,0 +1,67 @@
'use client'
import { cn } from '@langgenius/dify-ui/cn'
import { useTranslation } from 'react-i18next'
type RosterSidebarProps = {
totalAgents: number
}
export function RosterSidebar({ totalAgents }: RosterSidebarProps) {
const { t } = useTranslation('agentV2')
return (
<aside className="hidden w-[240px] shrink-0 flex-col border-r border-divider-subtle bg-background-body px-3 py-4 md:flex">
<div className="flex min-h-0 flex-1 flex-col">
<div className="px-2 pb-3">
<div className="flex items-center gap-2">
<div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-text-accent text-text-primary-on-surface shadow-xs">
<span aria-hidden className="i-custom-vender-solid-mediaAndDevices-robot size-4" />
</div>
<div className="min-w-0">
<div className="truncate system-md-semibold text-text-secondary">
{t('roster.title')}
</div>
<div className="system-2xs-medium-uppercase text-text-tertiary">
{t('roster.sidebarLabel')}
</div>
</div>
</div>
</div>
<div className="px-2 py-2">
<div className="h-px bg-linear-to-r from-divider-subtle to-background-gradient-mask-transparent" />
</div>
<nav className="flex flex-col gap-y-0.5 px-1 py-2" aria-label={t('roster.sidebarLabel')}>
<div
aria-current="page"
className="flex h-8 items-center rounded-lg border-t-[0.75px] border-r-[0.25px] border-b-[0.25px] border-l-[0.75px] border-effects-highlight-lightmode-off bg-components-menu-item-bg-active pr-1 pl-3 system-sm-semibold text-text-accent-light-mode-only"
>
<span aria-hidden className="i-custom-vender-solid-mediaAndDevices-robot size-4 shrink-0" />
<span className="ml-2 min-w-0 flex-1 truncate">
{t('roster.sidebar.agents')}
</span>
<span className="shrink-0 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-1 py-0.5 system-2xs-medium-uppercase text-text-tertiary">
{totalAgents}
</span>
</div>
<button
type="button"
disabled
className={cn(
'flex h-8 items-center rounded-lg border-t-[0.75px] border-r-[0.25px] border-b-[0.25px] border-l-[0.75px] border-transparent pr-1 pl-3 text-left system-sm-medium text-text-disabled',
'cursor-not-allowed',
)}
>
<span aria-hidden className="i-ri-user-smile-line size-4 shrink-0" />
<span className="ml-2 min-w-0 flex-1 truncate">
{t('roster.sidebar.humans')}
</span>
<span className="shrink-0 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-1 py-0.5 system-2xs-medium-uppercase text-text-tertiary">
{t('roster.sidebar.soon')}
</span>
</button>
</nav>
</div>
</aside>
)
}

View File

@ -1,5 +1,6 @@
'use client'
import { ScrollArea } from '@langgenius/dify-ui/scroll-area'
import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query'
import { useDebounce } from 'ahooks'
import { debounce, parseAsString, useQueryState } from 'nuqs'
@ -7,6 +8,7 @@ import { useTranslation } from 'react-i18next'
import useDocumentTitle from '@/hooks/use-document-title'
import { consoleQuery } from '@/service/client'
import { AgentRosterList } from './components/agent-roster-list'
import { RosterSidebar } from './components/roster-sidebar'
import { RosterToolbar } from './components/roster-toolbar'
const ROSTER_PAGE_SIZE = 30
@ -52,49 +54,62 @@ export default function RosterPage() {
useDocumentTitle(t('menus.roster', { ns: 'common' }))
return (
<main className="flex h-0 min-w-0 grow flex-col overflow-y-auto bg-background-body">
<div className="sticky top-0 z-10 bg-background-body px-8 pt-4 pb-3">
<header className="flex min-w-0 flex-col gap-2">
<div className="flex min-w-0 items-center gap-2">
<h1 className="truncate text-[18px]/[21.6px] font-semibold text-text-primary">
{tAgentV2('roster.title')}
</h1>
<a
href="https://docs.dify.ai/"
target="_blank"
rel="noreferrer"
className="inline-flex shrink-0 items-center gap-1 rounded-md system-xs-semibold text-text-accent hover:underline focus-visible:ring-2 focus-visible:ring-state-accent-solid focus-visible:outline-hidden"
>
{tAgentV2('roster.learnMore')}
<span aria-hidden className="i-ri-arrow-right-up-line size-3" />
</a>
</div>
<p className="max-w-3xl system-sm-regular text-text-tertiary">
{tAgentV2('roster.description')}
</p>
</header>
<RosterToolbar
keyword={keyword}
totalAgents={totalAgents}
onKeywordChange={(value) => {
void setKeyword(value)
<main className="flex h-0 min-w-0 grow overflow-hidden bg-background-body">
<RosterSidebar totalAgents={totalAgents} />
<section className="flex h-full min-w-0 flex-1 flex-col overflow-hidden bg-background-body">
<ScrollArea
className="min-h-0 flex-1 overflow-hidden"
label={tAgentV2('roster.listLabel')}
slotClassNames={{
viewport: 'overscroll-contain',
content: 'min-h-full',
scrollbar: 'data-[orientation=vertical]:my-1 data-[orientation=vertical]:me-1',
}}
/>
</div>
>
<div className="sticky top-0 z-10 bg-background-body px-8 pt-4 pb-3">
<header className="flex min-w-0 flex-col gap-2">
<div className="flex min-w-0 items-center gap-2">
<h1 className="truncate text-[18px]/[21.6px] font-semibold text-text-primary">
{tAgentV2('roster.title')}
</h1>
<a
href="https://docs.dify.ai/"
target="_blank"
rel="noreferrer"
className="inline-flex shrink-0 items-center gap-1 rounded-md system-xs-semibold text-text-accent hover:underline focus-visible:ring-2 focus-visible:ring-state-accent-solid focus-visible:outline-hidden"
>
{tAgentV2('roster.learnMore')}
<span aria-hidden className="i-ri-arrow-right-up-line size-3" />
</a>
</div>
<p className="max-w-3xl system-sm-regular text-text-tertiary">
{tAgentV2('roster.description')}
</p>
</header>
<div className="px-8 pb-8">
<AgentRosterList
agents={rosterItems}
hasMore={!!hasNextPage}
isEmptySearch={!!debouncedKeyword}
isError={!!error}
isFetching={isFetching}
isFetchingNextPage={isFetchingNextPage}
isPending={isPending}
onLoadMore={() => fetchNextPage()}
/>
</div>
<RosterToolbar
keyword={keyword}
totalAgents={totalAgents}
onKeywordChange={(value) => {
void setKeyword(value)
}}
/>
</div>
<div className="px-8 pb-8">
<AgentRosterList
agents={rosterItems}
hasMore={!!hasNextPage}
isEmptySearch={!!debouncedKeyword}
isError={!!error}
isFetching={isFetching}
isFetchingNextPage={isFetchingNextPage}
isPending={isPending}
onLoadMore={() => fetchNextPage()}
/>
</div>
</ScrollArea>
</section>
</main>
)
}

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -122,10 +122,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "Learn more",
"roster.listLabel": "Agent roster list",
"roster.loadMore": "Load more",
"roster.loadingError": "Failed to load agents. Refresh and try again.",
"roster.searchLabel": "Search agents",
"roster.searchPlaceholder": "Search agents by name…",
"roster.sidebar.agents": "Agents",
"roster.sidebar.humans": "Humans",
"roster.sidebar.soon": "Soon",
"roster.sidebarLabel": "Roster navigation",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",

View File

@ -122,10 +122,15 @@
"roster.emptySearch": "没有匹配的智能体",
"roster.emptySearchDescription": "请尝试其他智能体名称。",
"roster.learnMore": "了解更多",
"roster.listLabel": "智能体 Roster 列表",
"roster.loadMore": "加载更多",
"roster.loadingError": "智能体加载失败。请刷新后重试。",
"roster.searchLabel": "搜索智能体",
"roster.searchPlaceholder": "按名称搜索智能体…",
"roster.sidebar.agents": "智能体",
"roster.sidebar.humans": "人工成员",
"roster.sidebar.soon": "后续推出",
"roster.sidebarLabel": "Roster 导航",
"roster.sources.agent_app": "智能体应用",
"roster.sources.imported": "导入",
"roster.sources.system": "系统",

View File

@ -71,10 +71,15 @@
"roster.emptySearch": "No matching agents",
"roster.emptySearchDescription": "Try another agent name.",
"roster.learnMore": "瞭解更多",
"roster.listLabel": "智能體 Roster 列表",
"roster.loadMore": "載入更多",
"roster.loadingError": "智能體載入失敗。請重新整理後重試。",
"roster.searchLabel": "搜尋智能體",
"roster.searchPlaceholder": "按名稱搜尋智能體…",
"roster.sidebar.agents": "智能體",
"roster.sidebar.humans": "人工成員",
"roster.sidebar.soon": "後續推出",
"roster.sidebarLabel": "Roster 導航",
"roster.sources.agent_app": "Agent app",
"roster.sources.imported": "Imported",
"roster.sources.system": "System",