Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/perky-dogs-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@read-frog/extension": minor
---

feat(translation-hub): persist selected translation providers in translation center dropdown
18 changes: 15 additions & 3 deletions src/entrypoints/translation-hub/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,24 @@ export const selectedProviderIdsAtom = atom(
const override = get(selectedProviderIdsOverrideAtom)
if (override !== null)
return override
Comment on lines 42 to 44
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop ignoring config changes after the first selection

Once setSelectedIds runs, selectedProviderIdsOverrideAtom stays non-null for the rest of the page lifetime, so this getter never re-applies filterEnabledProvidersConfig or re-reads the persisted translate.translationHubConfig.selectedIds. In the common Vivaldi-panel workflow where the hub stays mounted, disabling a provider or importing synced config from popup/options leaves the panel on stale ids; selectedProvidersAtom then resolves those ids straight from providersConfig, so a provider disabled elsewhere can still be shown and used until the page reloads.

Useful? React with 👍 / 👎.

// Default: all enabled translate providers' IDs
// Default: empty. Users must explicitly enable translation providers.
const providersConfig = get(configFieldsAtomMap.providersConfig)
const translateProviders = getTranslateProvidersConfig(providersConfig)
return filterEnabledProvidersConfig(translateProviders).map(p => p.id)
const translateEnabledProviders = filterEnabledProvidersConfig(translateProviders).map(p => p.id)
const translateConfig = get(configFieldsAtomMap.translate)
const selectedIds = translateConfig.translationHubConfig.selectedIds
return translateEnabledProviders.filter(id => selectedIds.includes(id))
},
(get, set, ids: string[]) => {
set(selectedProviderIdsOverrideAtom, ids)
const translateConfig = get(configFieldsAtomMap.translate)
void set(configFieldsAtomMap.translate, {
translationHubConfig: {
...translateConfig.translationHubConfig,
selectedIds: ids,
},
})
},
(_get, set, ids: string[]) => set(selectedProviderIdsOverrideAtom, ids),
)

// === Translation Card UI State ===
Expand Down
5 changes: 5 additions & 0 deletions src/types/config/translate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export const pageTranslationShortcutSchema = z.string().superRefine((shortcut, c
}
})

export const translationHubConfigSchema = z.object({
selectedIds: z.array(z.string()),
})

export const translateConfigSchema = z.object({
providerId: z.string().nonempty(),
mode: translationModeSchema,
Expand All @@ -106,6 +110,7 @@ export const translateConfigSchema = z.object({
requestQueueConfig: requestQueueConfigSchema,
batchQueueConfig: batchQueueConfigSchema,
translationNodeStyle: translationNodeStyleConfigSchema,
translationHubConfig: translationHubConfigSchema,
Comment on lines 111 to +113
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep startup reads compatible with pre-v67 configs

Adding a required translationHubConfig here makes every stored v66 config fail configSchema.safeParse until migration has finished. getLocalConfig() does not migrate on read—it falls back to DEFAULT_CONFIG on validation failure (src/utils/config/storage.ts)—and both src/entrypoints/translation-hub/main.tsx and src/entrypoints/popup/main.tsx hydrate from that helper. On upgrade, if the user opens the panel/popup before the background ensureInitializedConfig() completes, those UIs boot with a reset config instead of the stored one.

Useful? React with 👍 / 👎.

})

export type RequestQueueConfig = z.infer<typeof requestQueueConfigSchema>
Expand Down
Loading
Loading