Browser picker - offer each browser once, not twice

On any upgraded install update_35 has migrated the old per-engine request timeout and
User-Agent into browser configs keyed by the engine name ('html_requests',
'html_webdriver'), so those ids exist in BOTH the built-in engine list and browsers.json.
list_watch_browser_choices() concatenated the two sources, so the watch edit page rendered
the same browser as two radios with the same label - and the group override select did the
same, from its own copy of that concatenation.

Deduplicated by value at the source, keeping each value's first position (built-ins stay in
engine order) with its last label - the saved one, since it is the same browser under the
name the user can actually change. The group override select and the Add-Watch list now
derive from that single list instead of rebuilding or re-deduplicating it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dgtlmoon
2026-09-17 20:15:20 +02:00
co-authored by Claude Opus 5
parent ba2280ba81
commit e4c75bf486
4 changed files with 49 additions and 22 deletions
+10 -4
View File
@@ -485,13 +485,19 @@ def is_valid_browser_selector(value, datastore, allow_empty=True):
def list_watch_browser_choices(datastore):
"""(value, label) choices for the watch-level 'Browser' picker:
system default, the always-present built-in engine browsers, then the user's saved browsers.
Deduplicated by value, because a saved config legitimately shares a built-in engine's id -
update_35 migrated the old per-engine request timeout / User-Agent into configs keyed
'html_requests' and 'html_webdriver' - and listing one browser twice is not a choice. The
saved label wins: it is the same browser, and that is the name the user can change.
"""
choices = [('system', _system_default_label(datastore))]
choices = {'system': _system_default_label(datastore)}
for b in list_builtin_browsers():
choices.append((b['id'], b['label']))
choices[b['id']] = b['label']
for cid, entry in datastore.browser_config_store.all().items():
choices.append((cid, entry.get('label') or cid))
return choices
choices[cid] = entry.get('label') or cid
# dict keeps each value's first position (built-ins stay in engine order) with its last label
return list(choices.items())
def _system_default_label(datastore):