From 003312f4ff958d17a08521d4eb95227b1146386c Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:27:20 -0400 Subject: [PATCH] feat(web): let schemas label enum dropdown options (#442) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(web): let schemas label enum dropdown options An enum property renders as a dropdown whose option text is derived from the value — underscores replaced, title case applied. That works when the value reads as its own label and fails when it does not: "vs" renders as "Vs", and "abbrev" tells the user nothing about the "Sep 19" it produces. Schemas had no way to say otherwise, so the label was whatever the config key happened to look like. Enum dropdowns now take their option text from x-options.labels when the schema supplies it. This is not a new convention: the checkbox-group widget has read x-options.labels since it was written, with the same humanised fallback. This extends it to plain enums and to array-table columns. Display only — the option value, and so the saved config, is unchanged. The map may be partial; unlabelled values keep the humanised fallback, so every existing schema renders exactly as before. Older cores ignore x-options entirely, which means a plugin can ship labels without requiring users to upgrade first. Array-table columns get the same lookup but keep the raw value as their fallback rather than the humanised one. Those columns hold values such as ticker symbols, where "aapl" -> "Aapl" would be wrong, and they were not being humanised before this change. Verified against the running web service: with labels the hockey plugin's date dropdown reads "Sep 19 / 9/19 / 19 Sep / 19/9 / Fri Sep 19"; with the pre-change template and the same schema it falls back to "Abbrev / Numeric / Day First / ...", confirming the degradation path. * fix(web): label enum options in dynamically added table rows, and test the shipped template Both points from the CodeRabbit review on #442. array-table.js built enum ', html, re.S + ) + } + + +def test_labels_are_used_when_supplied() -> None: + html = _render({ + 'enum': ['vs', 'date_time'], + 'x-options': {'labels': {'vs': 'VS', 'date_time': 'Date and time'}}, + }) + assert _option_labels(html) == {'vs': 'VS', 'date_time': 'Date and time'} + + +def test_unlabelled_values_keep_the_humanised_fallback() -> None: + """Schemas without labels must render exactly as they did before.""" + html = _render({'enum': ['day_first', 'weekday']}) + assert _option_labels(html) == {'day_first': 'Day First', 'weekday': 'Weekday'} + + +def test_partial_labels_fall_back_per_value() -> None: + """A labels map covering some values leaves the rest humanised.""" + html = _render({'enum': ['vs', 'day_first'], + 'x-options': {'labels': {'vs': 'VS'}}}) + assert _option_labels(html) == {'vs': 'VS', 'day_first': 'Day First'} + + +def test_option_values_are_unchanged_by_labelling() -> None: + """Labels are display-only: the submitted value stays the enum value.""" + html = _render({'enum': ['abbrev'], + 'x-options': {'labels': {'abbrev': 'Sep 19'}}}) + assert _option_labels(html) == {'abbrev': 'Sep 19'} + + +def test_selected_option_still_tracks_the_current_value() -> None: + """Labelling must not disturb which option is marked selected.""" + html = _render({'enum': ['abbrev', 'numeric'], + 'x-options': {'labels': {'abbrev': 'Sep 19'}}}, + value='numeric') + selected = re.search(r'