feat(channels): 添加渠道状态筛选功能以优化用户体验

在渠道管理页面中引入了渠道状态筛选功能,允许用户根据渠道的启用状态(全部、已启用、已停用)进行过滤。这一改动旨在提升用户在管理渠道时的灵活性和效率,使其能够更方便地找到所需的渠道。更新了相关的国际化文件,以支持多语言环境下的状态筛选描述,确保所有用户都能理解这一新功能。
This commit is contained in:
Jeff Gu committed 2026-06-10 11:46:28 +08:00
1 parent b03b660de7
commit d3d64bbb77
4 files changed
+34 -16

No files matched your search

+4 -1
View File
@@ -116,7 +116,10 @@
"title": "Channels",
"description": "Configure AI provider endpoints, manage models and load balancing",
"searchPlaceholder": "Search channels...",
"enabledOnly": "Enabled only",
"statusFilter": "Channel status filter",
"filterAll": "All",
"filterEnabled": "Enabled",
"filterDisabled": "Disabled",
"addChannel": "Add Channel",
"editChannel": "Edit Channel",
"emptyTitle": "Add your first channel",
+4 -1
View File
@@ -116,7 +116,10 @@
"title": "渠道管理",
"description": "配置 AI 服务商接口,管理模型和负载均衡策略",
"searchPlaceholder": "搜索渠道...",
"enabledOnly": "仅已启用",
"statusFilter": "渠道状态筛选",
"filterAll": "全部",
"filterEnabled": "已启用",
"filterDisabled": "已停用",
"addChannel": "添加渠道",
"editChannel": "编辑渠道",
"emptyTitle": "添加您的第一个渠道",
+4 -1
View File
@@ -116,7 +116,10 @@
"title": "渠道管理",
"description": "設定 AI 服務商介面,管理模型和負載均衡策略",
"searchPlaceholder": "搜尋渠道...",
"enabledOnly": "僅已啟用",
"statusFilter": "渠道狀態篩選",
"filterAll": "全部",
"filterEnabled": "已啟用",
"filterDisabled": "已停用",
"addChannel": "新增渠道",
"editChannel": "編輯渠道",
"emptyTitle": "新增您的第一個渠道",
+22 -13
View File
@@ -38,6 +38,7 @@ import i18n from "@/i18n";
type EditMode = "form" | "json";
type ModelEditorMode = "visual" | "json";
type ChannelStatusFilter = "all" | "enabled" | "disabled";
type JsonObject = Record<string, unknown>;
type ModelRow = { id: string; name: string; enabled: boolean; default_params?: JsonObject };
type FetchedModelCandidate = { id: string; label: string };
@@ -577,7 +578,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 [statusFilter, setStatusFilter] = useState<ChannelStatusFilter>("enabled");
const [openMenu, setOpenMenu] = useState<string | null>(null);
const [isFetchedModelsDialogOpen, setIsFetchedModelsDialogOpen] = useState(false);
const [fetchedModelCandidates, setFetchedModelCandidates] = useState<FetchedModelCandidate[]>([]);
@@ -595,6 +596,11 @@ export function Channels({ createMode = false, editRoute = false }: { createMode
{ value: "visual" as const, label: t("common.visual") },
{ value: "json" as const, label: t("common.json") },
];
const statusFilterOptions = [
{ value: "all" as const, label: t("channels.filterAll") },
{ value: "enabled" as const, label: t("channels.filterEnabled") },
{ value: "disabled" as const, label: t("channels.filterDisabled") },
];
const applyModels = (models: ChannelModelMapping[]) => {
const normalizedModels = normalizeModels(models);
@@ -1092,7 +1098,11 @@ export function Channels({ createMode = false, editRoute = false }: { createMode
const rawConfig = parseChannelValue(channel);
const config = normalizeChannelFormConfig(rawConfig);
if (showEnabledOnly && config.enabled === false) {
const isEnabled = config.enabled !== false;
if (statusFilter === "enabled" && !isEnabled) {
return false;
}
if (statusFilter === "disabled" && isEnabled) {
return false;
}
@@ -1157,17 +1167,16 @@ 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>
<ButtonGroup
aria-label={t("channels.statusFilter")}
value={statusFilter}
options={statusFilterOptions}
onValueChange={setStatusFilter}
activeVariant="secondary"
inactiveVariant="outline"
className="grid w-full grid-cols-3 sm:inline-flex sm:w-auto"
buttonClassName="h-9 rounded-sm px-3"
/>
</div>
)}