fix: providers filter persistence and settings i18n (#970)

This commit is contained in:
Randi
2026-04-04 06:32:31 -04:00
committed by GitHub
parent c96221c705
commit 606824d282
6 changed files with 139 additions and 1 deletions

View File

@@ -31,6 +31,7 @@ import {
buildProviderEntries,
filterConfiguredProviderEntries,
} from "./providerPageUtils";
import { readConfiguredOnlyPreference, writeConfiguredOnlyPreference } from "./providerPageStorage";
const CC_COMPATIBLE_LABEL = "CC Compatible";
const ADD_CC_COMPATIBLE_LABEL = "Add CC Compatible";
@@ -115,10 +116,16 @@ export default function ProvidersPage() {
const [testResults, setTestResults] = useState<any>(null);
const [importingZed, setImportingZed] = useState(false);
const [showConfiguredOnly, setShowConfiguredOnly] = useState(false);
const [configuredOnlyPreferenceReady, setConfiguredOnlyPreferenceReady] = useState(false);
const notify = useNotificationStore();
const t = useTranslations("providers");
const tc = useTranslations("common");
useEffect(() => {
setShowConfiguredOnly(readConfiguredOnlyPreference());
setConfiguredOnlyPreferenceReady(true);
}, []);
useEffect(() => {
const fetchData = async () => {
try {
@@ -145,6 +152,12 @@ export default function ProvidersPage() {
fetchData();
}, []);
useEffect(() => {
if (!configuredOnlyPreferenceReady) return;
writeConfiguredOnlyPreference(showConfiguredOnly);
}, [configuredOnlyPreferenceReady, showConfiguredOnly]);
const handleZedImport = async () => {
setImportingZed(true);
try {

View File

@@ -0,0 +1,42 @@
export const SHOW_CONFIGURED_ONLY_STORAGE_KEY = "omniroute-providers-show-configured-only";
interface StorageReader {
getItem(key: string): string | null;
}
interface StorageWriter extends StorageReader {
setItem(key: string, value: string): void;
removeItem(key: string): void;
}
export function parseConfiguredOnlyPreference(value: string | null | undefined): boolean {
return value === "true";
}
function getBrowserStorage(): StorageWriter | null {
try {
return globalThis.localStorage ?? null;
} catch {
return null;
}
}
export function readConfiguredOnlyPreference(storage: StorageReader | null = getBrowserStorage()) {
if (!storage) return false;
return parseConfiguredOnlyPreference(storage.getItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY));
}
export function writeConfiguredOnlyPreference(
enabled: boolean,
storage: StorageWriter | null = getBrowserStorage()
) {
if (!storage) return;
if (enabled) {
storage.setItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY, "true");
return;
}
storage.removeItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY);
}

View File

@@ -1834,6 +1834,8 @@
"cacheTTL": "Cache TTL",
"maxCacheSize": "Max Cache Size",
"clearCache": "Clear Cache",
"cacheCleared": "Cache cleared successfully",
"clearCacheFailed": "Failed to clear cache",
"cacheHits": "Cache Hits",
"cacheMisses": "Cache Misses",
"hitRate": "Hit Rate",
@@ -2248,9 +2250,15 @@
"themeCoral": "Coral",
"adaptiveVolumeRouting": "Adaptive Volume Routing",
"adaptiveVolumeRoutingDesc": "Scale connections dynamically based on payload volume and throughput pressure.",
"lkgpToggleTitle": "Last Known Good Provider (LKGP)",
"lkgpToggleDesc": "When enabled, the router remembers which provider last served a successful response and tries it first on subsequent requests.",
"clearLkgpCache": "Clear LKGP Cache",
"lkgpCacheCleared": "LKGP cache cleared successfully",
"lkgpCacheClearFailed": "Failed to clear LKGP cache",
"days": "Days",
"lkgp": "LKGP Mode",
"lkgpDesc": "Last Known Good Provider (Predictable resilience)",
"maintenance": "Maintenance",
"purgeExpiredLogs": "Purge Expired Logs",
"purgeLogsFailed": "Failed to purge logs"
},

View File

@@ -1753,6 +1753,8 @@
"cacheTTL": "缓存生存时间",
"maxCacheSize": "最大缓存大小",
"clearCache": "清除缓存",
"cacheCleared": "缓存已成功清除",
"clearCacheFailed": "清除缓存失败",
"cacheHits": "缓存命中",
"cacheMisses": "缓存未命中",
"hitRate": "命中率",
@@ -2164,7 +2166,17 @@
"customPricingNote": "你可以覆盖特定模型的默认定价。自定义覆盖会优先于自动检测到的定价。",
"editPricing": "编辑定价",
"viewFullDetails": "查看完整详情",
"themeCoral": "珊瑚色"
"themeCoral": "珊瑚色",
"adaptiveVolumeRouting": "自适应流量路由",
"adaptiveVolumeRoutingDesc": "根据实时负载量和吞吐压力,动态调整各提供商连接承载的流量。",
"lkgpToggleTitle": "最后已知良好提供商LKGP",
"lkgpToggleDesc": "启用后,路由器会记住上一次成功返回响应的提供商,并在后续请求中优先尝试它。",
"clearLkgpCache": "清除 LKGP 缓存",
"lkgpCacheCleared": "LKGP 缓存已成功清除",
"lkgpCacheClearFailed": "清除 LKGP 缓存失败",
"maintenance": "维护",
"purgeExpiredLogs": "清理过期日志",
"purgeLogsFailed": "清理日志失败"
},
"translator": {
"title": "翻译者",

View File

@@ -3,6 +3,8 @@ import assert from "node:assert/strict";
const providerPageUtils =
await import("../../src/app/(dashboard)/dashboard/providers/providerPageUtils.ts");
const providerPageStorage =
await import("../../src/app/(dashboard)/dashboard/providers/providerPageStorage.ts");
const providers = await import("../../src/shared/constants/providers.ts");
test("merged OAuth providers keep free-tier providers in the OAuth section", () => {
@@ -72,3 +74,35 @@ test("configured-only filter keeps only providers with saved connections", () =>
);
assert.equal(providerPageUtils.filterConfiguredProviderEntries(entries, false).length, 3);
});
test("configured-only preference parser only enables explicit true values", () => {
assert.equal(providerPageStorage.parseConfiguredOnlyPreference("true"), true);
assert.equal(providerPageStorage.parseConfiguredOnlyPreference("false"), false);
assert.equal(providerPageStorage.parseConfiguredOnlyPreference(null), false);
assert.equal(providerPageStorage.parseConfiguredOnlyPreference(undefined), false);
});
test("configured-only preference storage round-trips correctly", () => {
const storage = new Map();
const mockStorage = {
getItem(key) {
return storage.has(key) ? storage.get(key) : null;
},
setItem(key, value) {
storage.set(key, value);
},
removeItem(key) {
storage.delete(key);
},
};
assert.equal(providerPageStorage.readConfiguredOnlyPreference(mockStorage), false);
providerPageStorage.writeConfiguredOnlyPreference(true, mockStorage);
assert.equal(storage.get(providerPageStorage.SHOW_CONFIGURED_ONLY_STORAGE_KEY), "true");
assert.equal(providerPageStorage.readConfiguredOnlyPreference(mockStorage), true);
providerPageStorage.writeConfiguredOnlyPreference(false, mockStorage);
assert.equal(storage.has(providerPageStorage.SHOW_CONFIGURED_ONLY_STORAGE_KEY), false);
assert.equal(providerPageStorage.readConfiguredOnlyPreference(mockStorage), false);
});

View File

@@ -0,0 +1,29 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const en = require("../../src/i18n/messages/en.json");
const zhCn = require("../../src/i18n/messages/zh-CN.json");
const requiredSettingsKeys = [
"adaptiveVolumeRouting",
"adaptiveVolumeRoutingDesc",
"lkgpToggleTitle",
"lkgpToggleDesc",
"clearLkgpCache",
"lkgpCacheCleared",
"lkgpCacheClearFailed",
"maintenance",
"cacheCleared",
"clearCacheFailed",
"purgeExpiredLogs",
"purgeLogsFailed",
];
test("settings translations include LKGP and maintenance keys in English and Simplified Chinese", () => {
for (const key of requiredSettingsKeys) {
assert.equal(typeof en.settings?.[key], "string", `en.settings.${key} should exist`);
assert.equal(typeof zhCn.settings?.[key], "string", `zh-CN.settings.${key} should exist`);
}
});