mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix: providers filter persistence and settings i18n (#970)
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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": "翻译者",
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
29
tests/unit/settings-i18n-keys.test.mjs
Normal file
29
tests/unit/settings-i18n-keys.test.mjs
Normal 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`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user