dify/web/features/agent-v2/roster/components/roster-toolbar.tsx
yyh 1b3e8e9943
chore(agent-v2): sync daily changes (#38298)
Signed-off-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: 盐粒 Yanli <mail@yanli.one>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: zyssyz123 <916125788@qq.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: 盐粒 Yanli <yanli@dify.ai>
Co-authored-by: 林玮 (Jade Lin) <linw1995@icloud.com>
2026-07-05 08:09:38 +00:00

144 lines
3.9 KiB
TypeScript

'use client'
import type { RosterFilterValue } from './roster-filter'
import { Checkbox } from '@langgenius/dify-ui/checkbox'
import { SegmentedControl, SegmentedControlItem } from '@langgenius/dify-ui/segmented-control'
import { useQueryState } from 'nuqs'
import { useTranslation } from 'react-i18next'
import { SearchInput } from '@/app/components/base/search-input'
import {
rosterCreatedByMeQueryParser,
rosterFilterQueryParser,
rosterKeywordQueryParser,
rosterQueryParamNames,
} from '../query-params'
import { CreateAgentDialog } from './create-agent-dialog'
import { RosterSortSelect } from './roster-sort-select'
type RosterToolbarProps = {
draftAgents: number
publishedAgents: number
}
type RosterFilterItemProps = {
count?: number
label: string
value: RosterFilterValue
}
function RosterFilterItem({
count,
label,
value,
}: RosterFilterItemProps) {
return (
<SegmentedControlItem
value={value}
className="gap-1 data-pressed:text-text-secondary"
>
<span>{label}</span>
{count !== undefined && (
<span className="flex min-w-4 shrink-0 items-center justify-center rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-1 py-0.5 system-2xs-medium-uppercase text-text-tertiary tabular-nums">
<span className="min-w-px flex-1 text-center">
{count}
</span>
</span>
)}
</SegmentedControlItem>
)
}
function RosterStatusFilter({
draftAgents,
publishedAgents,
}: RosterToolbarProps) {
const { t } = useTranslation('agentV2')
const [filter, setFilter] = useQueryState(rosterQueryParamNames.filter, rosterFilterQueryParser)
return (
<SegmentedControl
aria-label={t('roster.filters.label')}
className="shrink-0"
value={[filter]}
onValueChange={(value) => {
const nextFilter = value[0]
if (nextFilter)
void setFilter(nextFilter)
}}
>
<RosterFilterItem
value="all"
label={t('roster.filters.all')}
/>
<RosterFilterItem
value="published"
label={t('roster.filters.published')}
count={publishedAgents}
/>
<RosterFilterItem
value="drafts"
label={t('roster.filters.drafts')}
count={draftAgents}
/>
</SegmentedControl>
)
}
function RosterSearchFilter() {
const { t } = useTranslation('agentV2')
const [keyword, setKeyword] = useQueryState(rosterQueryParamNames.keyword, rosterKeywordQueryParser)
return (
<SearchInput
aria-label={t('roster.searchLabel')}
className="h-8 w-50 min-w-0 shrink"
placeholder={t('roster.searchPlaceholder')}
value={keyword}
onValueChange={(value) => {
void setKeyword(value)
}}
/>
)
}
function RosterCreatedByMeFilter() {
const { t } = useTranslation('agentV2')
const [createdByMe, setCreatedByMe] = useQueryState(rosterQueryParamNames.createdByMe, rosterCreatedByMeQueryParser)
return (
<label className="flex h-8 shrink-0 cursor-pointer items-center gap-1 rounded-lg bg-components-input-bg-normal px-2 py-1 whitespace-nowrap">
<Checkbox
checked={createdByMe}
onCheckedChange={(checked) => {
void setCreatedByMe(checked === true)
}}
/>
<span className="p-1 system-sm-regular text-text-tertiary">{t('roster.filters.createdByMe')}</span>
</label>
)
}
export function RosterToolbar({
draftAgents,
publishedAgents,
}: RosterToolbarProps) {
return (
<div className="flex min-w-0 items-center gap-2">
<RosterStatusFilter
draftAgents={draftAgents}
publishedAgents={publishedAgents}
/>
<RosterSearchFilter />
<div className="flex h-4 shrink-0 px-1" aria-hidden="true">
<div className="h-full w-px bg-divider-regular" />
</div>
<RosterCreatedByMeFilter />
<div className="ml-auto flex shrink-0 items-center gap-2">
<RosterSortSelect />
<CreateAgentDialog />
</div>
</div>
)
}