feat(channels): 添加仅显示已启用渠道的过滤功能

在渠道管理页面中新增了一个按钮,允许用户选择仅查看已启用的渠道。此更改旨在提升用户体验,使用户能够更方便地管理和筛选渠道。通过引入这个过滤选项,用户可以快速找到他们所需的渠道,避免在大量无效渠道中浪费时间。此外,相关的国际化文本也已更新,以支持英文、简体中文和繁体中文的显示。
This commit is contained in:
Jeff Gu committed 2026-06-10 11:32:51 +08:00
1 parent 6cdca4a93b
commit 654a420a63
4 files changed
+27 -5

No files matched your search

+1
View File
@@ -116,6 +116,7 @@
"title": "Channels",
"description": "Configure AI provider endpoints, manage models and load balancing",
"searchPlaceholder": "Search channels...",
"enabledOnly": "Enabled only",
"addChannel": "Add Channel",
"editChannel": "Edit Channel",
"emptyTitle": "Add your first channel",
+1
View File
@@ -116,6 +116,7 @@
"title": "渠道管理",
"description": "配置 AI 服务商接口,管理模型和负载均衡策略",
"searchPlaceholder": "搜索渠道...",
"enabledOnly": "仅已启用",
"addChannel": "添加渠道",
"editChannel": "编辑渠道",
"emptyTitle": "添加您的第一个渠道",
+1
View File
@@ -116,6 +116,7 @@
"title": "渠道管理",
"description": "設定 AI 服務商介面,管理模型和負載均衡策略",
"searchPlaceholder": "搜尋渠道...",
"enabledOnly": "僅已啟用",
"addChannel": "新增渠道",
"editChannel": "編輯渠道",
"emptyTitle": "新增您的第一個渠道",
+24 -5
View File
@@ -577,6 +577,7 @@ export function Channels({ createMode = false, editRoute = false }: { createMode
const [modelRows, setModelRows] = useState<ModelRow[]>([createEmptyModelRow()]);
const [modelJsonValue, setModelJsonValue] = useState("[]");
const [searchQuery, setSearchQuery] = useState("");
const [showEnabledOnly, setShowEnabledOnly] = useState(true);
const [openMenu, setOpenMenu] = useState<string | null>(null);
const [isFetchedModelsDialogOpen, setIsFetchedModelsDialogOpen] = useState(false);
const [fetchedModelCandidates, setFetchedModelCandidates] = useState<FetchedModelCandidate[]>([]);
@@ -1086,13 +1087,20 @@ export function Channels({ createMode = false, editRoute = false }: { createMode
return channelTypes.find((item) => item.value === type)?.label || type;
};
const normalizedSearchQuery = searchQuery.trim().toLowerCase();
const filteredData = data?.filter((channel) => {
if (!searchQuery) return true;
const rawConfig = parseChannelValue(channel);
const config = normalizeChannelFormConfig(rawConfig);
if (showEnabledOnly && config.enabled === false) {
return false;
}
if (!normalizedSearchQuery) return true;
return (
config.name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
channel.key.toLowerCase().includes(searchQuery.toLowerCase())
config.name?.toLowerCase().includes(normalizedSearchQuery) ||
channel.key.toLowerCase().includes(normalizedSearchQuery)
);
});
const endpointPreview = getChannelEndpointPreview(formData.type, formData.endpoint);
@@ -1116,8 +1124,8 @@ export function Channels({ createMode = false, editRoute = false }: { createMode
}
>
{data && data.length > 0 && (
<div className="mb-4">
<div className="relative max-w-sm">
<div className="mb-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<div className="relative w-full max-w-sm">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder={t("channels.searchPlaceholder")}
@@ -1126,6 +1134,17 @@ export function Channels({ createMode = false, editRoute = false }: { createMode
className="pl-9"
/>
</div>
<Button
type="button"
variant={showEnabledOnly ? "secondary" : "outline"}
size="sm"
aria-pressed={showEnabledOnly}
onClick={() => setShowEnabledOnly((current) => !current)}
className="w-full sm:w-auto"
>
<Check className={cn("h-4 w-4", !showEnabledOnly && "opacity-0")} />
{t("channels.enabledOnly")}
</Button>
</div>
)}