feat: implement TagSelector component for improved tag management across dashboard features

- Added TagSelector component to streamline tag selection in various components.
- Refactored existing tag handling in DashboardConversationsPage, ConversationTagPicker, EditDialog, and TicketsPage to utilize the new TagSelector.
- Removed redundant tag handling functions and optimized state management for tags.
- Updated tests to ensure proper functionality of the new tag handling logic.
This commit is contained in:
mlogclub
2026-05-30 11:23:05 +08:00
parent d2da9de641
commit 8398cd6f91
9 changed files with 653 additions and 354 deletions
@@ -11,8 +11,10 @@ import {
} from "@/components/dashboard-page"
import { ListPagination } from "@/components/list-pagination"
import { OptionCombobox } from "@/components/option-combobox"
import { TagSelector } from "@/components/tag-selector"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import type { TagTree } from "@/lib/api/admin"
import {
Table,
TableBody,
@@ -34,10 +36,11 @@ export type DashboardListFilter = DashboardCrudQueryFilter & {
label: string
placeholder?: string
defaultValue: string | number
type?: "text" | "select" | "segment"
type?: "text" | "select" | "segment" | "tag"
className?: string
inputClassName?: string
options?: ReadonlyArray<{ value: string; label: string }>
tags?: TagTree[]
searchPlaceholder?: string
emptyText?: string
icon?: ReactNode
@@ -172,6 +175,25 @@ export function DashboardListPage<TItem>({
</div>
)
}
if (filter.type === "tag") {
return (
<div key={filter.name} className={filter.className ?? "w-full sm:w-48"}>
<TagSelector
mode="single"
value={Number(value ?? filter.defaultValue)}
onChange={(nextValue) => list.setDraftFilter(filter.name, nextValue)}
tags={filter.tags ?? []}
placeholder={filter.placeholder ?? filter.label}
searchPlaceholder={filter.searchPlaceholder}
emptyText={filter.emptyText}
rootOption={{
value: Number(filter.allValue ?? filter.defaultValue),
label: filter.placeholder ?? filter.label,
}}
/>
</div>
)
}
return (
<div key={filter.name} className={filter.className ?? "w-full sm:w-64"}>