Skip to content

feat(web): let schemas label enum dropdown options - #442

Merged
ChuckBuilds merged 3 commits into
mainfrom
feat/enum-option-labels
Aug 7, 2026
Merged

feat(web): let schemas label enum dropdown options#442
ChuckBuilds merged 3 commits into
mainfrom
feat/enum-option-labels

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Problem

An enum property renders as a dropdown whose option text is derived from the value:

{{ option|replace('_', ' ')|title }}

That works when the value reads as its own label, and fails when it doesn't:

enum value rendered as wanted
vs Vs VS
abbrev Abbrev Sep 19
numeric_day_first Numeric Day First 19/9

A schema had no way to say otherwise, so the visible label was whatever the config key happened to look like — and config keys are chosen for the API, not the UI.

Change

Enum dropdowns now take their option text from x-options.labels when supplied.

This is not a new convention. The checkbox-group widget has read x-options.labels since it was written, with the same humanised fallback (plugin_config.html, checkbox-group branch). This extends it to plain enums and to array-table columns.

"date_format": {
  "type": "string",
  "enum": ["abbrev", "numeric", "day_first"],
  "x-options": {
    "labels": {"abbrev": "Sep 19", "numeric": "9/19", "day_first": "19 Sep"}
  }
}

Compatibility

  • Display only. The option value is untouched, so a saved config never changes.
  • Partial maps work. Unlabelled values keep the humanised fallback.
  • Existing schemas are byte-identical. No labels supplied → same output as before.
  • Old cores ignore it. A plugin can ship labels without requiring a core upgrade first.

Array-table columns get the same lookup, but their fallback stays the raw value rather than the humanised one — those columns hold values like ticker symbols, where aapl → "Aapl" would be wrong. They were not humanised before this change and still aren't.

Verification

Checked against the running web service on a real device, not just unit tests:

  • with labels → Sep 19 / 9/19 / 19 Sep / 19/9 / Fri Sep 19
  • pre-change template, same schema → Abbrev / Numeric / Day First / ... (degradation path confirmed)
  • no-labels schema → output byte-identical to before

8 new tests in test/test_enum_option_labels.py, enrolled in CI. They render the real Jinja expression rather than a paraphrase, so dropping the lookup fails the suite. Existing template guards (test_template_targets, test_widget_scripts, test_doc_links) still pass — 12/12.

Convention documented in docs/widget-guide.md.

Summary by CodeRabbit

  • New Features

    • Added support for custom labels on enum options in configuration dropdowns.
    • Supports both x-options.labels and x_options.labels formats.
    • Unlabeled options retain appropriate fallback formatting while submitted values remain unchanged.
    • Added fallback handling for enum values in array-table columns.
  • Documentation

    • Documented enum option labels, partial mappings, backward compatibility, and array-table behavior.
  • Tests

    • Added coverage for custom labels, fallbacks, key formats, and preserved option values.

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.
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ChuckBuilds, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c42259e-3fb1-41a4-8ea5-2b2e89d7a16f

📥 Commits

Reviewing files that changed from the base of the PR and between 38a0ea8 and 14a17ff.

📒 Files selected for processing (3)
  • docs/widget-guide.md
  • test/test_enum_option_labels.py
  • web_interface/static/v3/js/widgets/array-table.js
📝 Walkthrough

Walkthrough

The plugin configuration template now supports custom enum display labels through x-options.labels. Standard dropdowns retain humanized fallbacks, while array-table columns retain raw values when labels are missing. Tests, documentation, and workflow coverage were added.

Changes

Enum option labels

Layer / File(s) Summary
Enum label rendering
web_interface/templates/v3/partials/plugin_config.html
Standard dropdowns use configured labels with humanized fallback. Array-table enum cells use configured labels with raw-value fallback.
Label behavior validation and documentation
test/test_enum_option_labels.py, docs/widget-guide.md, .github/workflows/test.yml
Tests cover label lookup, partial mappings, value preservation, both option-key spellings, and array-table fallback. The guide documents the behavior, and the workflow runs the new test module.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: schema-defined labels for enum dropdown options.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch feat/enum-option-labels
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/enum-option-labels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

codacy-production Bot commented Aug 6, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 2 high

Alerts:
⚠ 2 issues (≤ 0 issues of at least minor severity)

Results:
2 new issues

Category Results
Security 2 high

View in Codacy

🟢 Metrics 5 complexity · -2 duplication

Metric Results
Complexity 5
Duplication -2

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@ChuckBuilds

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/test_enum_option_labels.py`:
- Around line 21-33: The tests currently render the copied SELECT_FRAGMENT
instead of the shipped template, so they can miss production changes. Update
_render and the related tests in test_enum_option_labels.py to load and render
the production configuration template with a minimal fixture, or assert the
complete active enum-label expression in CONFIG_FORM; remove reliance on the
duplicated expression while preserving coverage of custom labels and the
fallback formatting.

In `@web_interface/templates/v3/partials/plugin_config.html`:
- Around line 582-586: Update the dynamic enum option creation in createCell()
used by addArrayTableRow so each option’s displayed text resolves the column
labels from x-options or x_options, falling back to the raw value when no label
exists. Keep the option value unchanged and match the server-rendered col_labels
behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 990f2308-322e-4509-bc1d-59bf48cf7ee5

📥 Commits

Reviewing files that changed from the base of the PR and between d9683e2 and 38a0ea8.

📒 Files selected for processing (4)
  • .github/workflows/test.yml
  • docs/widget-guide.md
  • test/test_enum_option_labels.py
  • web_interface/templates/v3/partials/plugin_config.html

Comment thread test/test_enum_option_labels.py Outdated
Comment thread web_interface/templates/v3/partials/plugin_config.html
ChuckBuilds and others added 2 commits August 7, 2026 13:00
…t the

shipped template

Both points from the CodeRabbit review on #442.

array-table.js built enum <option> elements with o.textContent = opt, so a
row added with "Add row" showed the raw value while the server-rendered
rows above it showed the schema's label — the same column reading two
different ways until the page was reloaded. Both option-building sites now
go through a shared enumOptionLabel(), which mirrors the template exactly:
x-options or x_options, labels map, raw value as the fallback.

The tests rendered a copy of the template expression, so they could pass
while production drifted. They now extract the live enum <select> block
out of plugin_config.html and render that, and assert on the full
value -> label map rather than substring presence.

Mutation-checked, since a guard that cannot fail is not a guard:
  - remove the labels lookup      -> 5 of 9 fail
  - change only the fallback to   -> 2 of 9 fail
    option|upper (keeping the
    enum_labels.get call intact)
  - revert the JS to raw values   -> 1 of 9 fails
The middle case is the one the review called out as able to slip through.
@ChuckBuilds
ChuckBuilds merged commit 003312f into main Aug 7, 2026
8 of 9 checks passed
@ChuckBuilds
ChuckBuilds deleted the feat/enum-option-labels branch August 7, 2026 17:27
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.

2 participants