Skip to content

Fix providers filter persistence and settings translations - #970

Merged
diegosouzapw merged 1 commit into
cheaper-inference:mainfrom
rdself:coder/fix-providers-settings-i18n
Apr 4, 2026
Merged

diegosouzapw merged 1 commit into
cheaper-inference:mainfrom
rdself:coder/fix-providers-settings-i18n

Conversation

@rdself

@rdself rdself commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • persist the Providers page Configured only toggle with localStorage so the filter survives refreshes
  • add the missing settings translation keys for LKGP and maintenance-related UI in English and Simplified Chinese
  • add regression tests for the providers preference storage and the required settings i18n keys

Root Cause

  • the Configured only state only lived in component memory, so it reset to false after every page reload
  • the LKGP and maintenance sections referenced settings translation keys that were never added to the locale message files, so the UI fell back to inline strings or showed missing localized content

Impact

  • dashboard users keep their Providers filter preference across reloads
  • the Settings UI now has complete EN/ZH-CN copy for the LKGP block and maintenance actions
  • future regressions are covered by targeted unit tests

Validation

  • node --import tsx/esm --test tests/unit/providers-page-utils.test.mjs tests/unit/settings-i18n-keys.test.mjs
  • npx eslint 'src/app/(dashboard)/dashboard/providers/page.tsx' 'src/app/(dashboard)/dashboard/providers/providerPageStorage.ts' 'tests/unit/providers-page-utils.test.mjs' 'tests/unit/settings-i18n-keys.test.mjs'
  • npm run typecheck:core -- --pretty false

Copilot AI review requested due to automatic review settings April 4, 2026 00:35

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements persistent storage for the "show configured only" preference on the providers page using localStorage. It also updates the English and Simplified Chinese translation files with new keys for LKGP and maintenance settings, and adds corresponding unit tests. Feedback suggests optimizing the storage update logic to avoid redundant writes on initialization and ensuring all relevant translation keys are included in the Chinese locale.

Comment on lines +155 to +159
useEffect(() => {
if (!configuredOnlyPreferenceReady) return;

writeConfiguredOnlyPreference(showConfiguredOnly);
}, [configuredOnlyPreferenceReady, showConfiguredOnly]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation causes a redundant write to localStorage on every page load. When the component mounts, the first useEffect reads the preference and updates showConfiguredOnly. This update, combined with configuredOnlyPreferenceReady becoming true, triggers this second useEffect, which then writes the same value back to storage. It is better to check if the value has actually changed before writing.

  useEffect(() => {
    if (!configuredOnlyPreferenceReady) return;

    if (showConfiguredOnly !== readConfiguredOnlyPreference()) {
      writeConfiguredOnlyPreference(showConfiguredOnly);
    }
  }, [configuredOnlyPreferenceReady, showConfiguredOnly]);

Comment on lines +2176 to +2177
"lkgpCacheClearFailed": "清除 LKGP 缓存失败",
"maintenance": "维护",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Several translation keys related to LKGP (days, lkgp, lkgpDesc) are present in the English settings block but were omitted from the Simplified Chinese version in this PR. Since the objective is to fix settings translations, these should be included to ensure a complete localized experience.

    "lkgpCacheClearFailed": "清除 LKGP 缓存失败",
    "days": "天",
    "lkgp": "LKGP 模式",
    "lkgpDesc": "最后已知良好提供商(可预测的韧性)",
    "maintenance": "维护",

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR persists the Providers page “Configured only” filter across reloads and fills in missing Settings i18n strings related to LKGP and maintenance actions, with unit tests to guard against regressions.

Changes:

  • Persist Configured only on the Providers page via a small localStorage wrapper.
  • Add missing settings.* translation keys for LKGP + maintenance UI in en and zh-CN.
  • Add unit tests for provider filter preference parsing/storage and presence of required settings keys.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit/settings-i18n-keys.test.mjs Adds a unit test asserting required settings.* translation keys exist (currently only EN + ZH-CN).
tests/unit/providers-page-utils.test.mjs Adds tests for configured-only preference parsing and storage round-trip behavior.
src/i18n/messages/zh-CN.json Adds missing Simplified Chinese settings.* strings for cache/maintenance/LKGP UI.
src/i18n/messages/en.json Adds missing English settings.* strings for cache/maintenance/LKGP UI.
src/app/(dashboard)/dashboard/providers/providerPageStorage.ts Introduces localStorage helpers for reading/writing the configured-only preference.
src/app/(dashboard)/dashboard/providers/page.tsx Reads configured-only preference on mount and writes changes back to storage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +36 to +41
if (enabled) {
storage.setItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY, "true");
return;
}

storage.removeItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY);

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localStorage.setItem / removeItem can throw (e.g., Safari private mode or quota exceeded). Even if getBrowserStorage() returns a storage object, an unhandled DOMException here would crash the Providers page. Wrap these storage writes in try/catch and treat failures as a no-op.

Suggested change
if (enabled) {
storage.setItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY, "true");
return;
}
storage.removeItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY);
try {
if (enabled) {
storage.setItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY, "true");
return;
}
storage.removeItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY);
} catch {
return;
}

Copilot uses AI. Check for mistakes.
export function readConfiguredOnlyPreference(storage: StorageReader | null = getBrowserStorage()) {
if (!storage) return false;

return parseConfiguredOnlyPreference(storage.getItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY));

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

storage.getItem(...) can also throw in some browser modes. Consider wrapping the read in try/catch and returning the default (false) on failure, so initialization can't crash the page when storage is blocked/unavailable.

Suggested change
return parseConfiguredOnlyPreference(storage.getItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY));
try {
return parseConfiguredOnlyPreference(storage.getItem(SHOW_CONFIGURED_ONLY_STORAGE_KEY));
} catch {
return false;
}

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +28
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`);
}

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only checks en and zh-CN, but the app supports many locales and loads one messages/<locale>.json per request. Since the new settings keys are not present in the other locale JSON files, consider iterating through all locale message files and asserting these keys exist (or explicitly enforce a fallback strategy).

Copilot uses AI. Check for mistakes.
Comment thread src/i18n/messages/en.json
Comment on lines +2253 to +2257
"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",

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These newly added settings.* keys (LKGP/maintenance) currently exist only in en.json and zh-CN.json (verified via repo-wide search), but the app supports many locales under src/i18n/messages/. For other locales, these messages will still be missing and may cause runtime missing-message errors. Please add the same keys to the other locale JSON files (placeholders OK) or implement a deterministic fallback.

Copilot uses AI. Check for mistakes.
@rdself rdself changed the title [codex] Fix providers filter persistence and settings translations Fix providers filter persistence and settings translations Apr 4, 2026
@diegosouzapw
diegosouzapw merged commit 606824d into cheaper-inference:main Apr 4, 2026
44 checks passed
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks @rdself for this clean contribution! 🎉 The providers filter persistence and missing i18n keys have been merged into main and will be part of v3.5.1. Great job on the DI-friendly storage module and comprehensive tests. We appreciate your effort!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants