Skip to content

feat(billing): pricing feature rows wrap + explicit ✗ not-included marker - #4390

Merged
PierreBrisorgueil merged 3 commits into
masterfrom
feat/billing-pricing-section-xmark-wrap
Jul 1, 2026
Merged

PierreBrisorgueil merged 3 commits into
masterfrom
feat/billing-pricing-section-xmark-wrap

Conversation

@PierreBrisorgueil

@PierreBrisorgueil PierreBrisorgueil commented Jul 1, 2026 •

Copy link
Copy Markdown
Collaborator

What

Presentational refactor of BillingPricingFeatureSectionComponent (generic devkit pricing card section), for pricing cards that render a full comparable feature list (all features per plan, included ✓ / not-included ✗).

  • Wrap long labels. Feature rows switch from v-list / v-list-item / v-list-item-title to a d-flex row + a plain <span>. v-list-item-title forces white-space: nowrap + ellipsis, which truncated substantive descriptions (e.g. "Stacks on top of subscription quota" → "… q…"). A plain span wraps naturally, so the :deep(.v-list-item-title) scoped-CSS hack that patched this is removed.
  • Explicit not-included marker. enabled: false rows now render a fa-solid fa-xmark (✗) with dimmed text instead of a dimmed check — so excluded features read clearly as "not in this plan" in a full comparable list (icon carries the affordance, not opacity alone).
  • Iconless headline rows. highlight: true rows render bold primary text with no leading icon (unchanged intent, cleaner markup).
  • Scoped CSS dropped in favour of Vuetify utility classes.

Invariant

Presentation-only — no change to which features/props a plan declares, no change to resolvedHeading / introText / inheritsFrom priority logic. Backward-compatible: sections without enabled render exactly as before (check icon, no dimming).

Tests

Unit tests updated to assert the new DOM (xmark path, iconless bold highlight rows, wrapping span). Full suite green (2437), lint clean.

Note for reviewers

Section top spacing moves from a scoped 1.25rem to mt-3 (0.75rem) — deliberate, since a full comparable list stacks more sections per card. Flagged for visual eyeball; trivially bumpable if it reads cramped downstream.

Summary by CodeRabbit

  • Refactor

    • Updated the billing pricing feature list to use a simpler row-based layout and cleaner utility styling.
    • Adjusted the heading and feature rows for more consistent spacing, wrapping, and icon presentation.
  • Bug Fixes

    • Improved the display of enabled, disabled, and highlighted features with clearer icons and text emphasis.
    • Tooltips continue to appear alongside feature labels where available.

…rker

Feature rows in BillingPricingFeatureSectionComponent switch from
v-list/v-list-item to a flex row + plain <span>, so long labels wrap
naturally — v-list-item-title forces nowrap + ellipsis, which truncated
substantive descriptions. enabled:false rows now render an explicit
fa-xmark "not included" marker with dimmed text (was a dimmed check), so
excluded features read clearly in a full comparable feature list. Scoped
CSS dropped in favour of Vuetify utility classes.

Unit tests updated to assert the new DOM: xmark path, iconless bold
highlight rows, wrapping span.

Claude-Session: https://claude.ai/code/session_011qpcCc8bq7QpiXLZ8pFFbM
@coderabbitai

coderabbitai Bot commented Jul 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6d6381a5-50ea-452f-87ca-21f981c92650

📥 Commits

Reviewing files that changed from the base of the PR and between 6e3f850 and 2f54706.

📒 Files selected for processing (2)
  • src/modules/billing/components/billing.pricingFeatureSection.component.vue
  • src/modules/billing/tests/billing.pricingFeatureSection.component.unit.tests.js

Walkthrough

The BillingPricingFeatureSectionComponent template is refactored from v-list/v-list-item markup to a flex-row layout with a standalone icon and label span, changing disabled/highlight styling and icon selection logic, and removing scoped CSS. Corresponding unit tests are updated to match the new DOM structure.

Changes

Pricing Feature Section Refactor

Layer / File(s) Summary
Flex-row template refactor
src/modules/billing/components/billing.pricingFeatureSection.component.vue
Template restructured from v-list/v-list-item to a flex row with standalone v-icon and span; icon logic shows xmark when disabled, check/item.icon otherwise; scoped CSS removed in favor of utility classes.
Updated unit tests for new markup
src/modules/billing/tests/billing.pricingFeatureSection.component.unit.tests.js
Tests updated to check absence of h4 for null titles, validate bold/primary iconless highlighted rows, and confirm fa-xmark plus text-medium-emphasis dimming for disabled items versus default enabled rendering.

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

Possibly related issues

Possibly related PRs

  • pierreb-devkit/Vue#4102: Both PRs rework the same component's title/heading and per-item icon/disabled/highlight/tooltip markup and its tests.
  • pierreb-devkit/Vue#4123: Both PRs touch the :deep(.v-list-item-title) truncation styling on the same component, with opposing changes.
  • pierreb-devkit/Vue#4382: Both PRs modify the same component's icon/feature row rendering logic.

Suggested labels: Feat, billing

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed, but it misses most required template sections such as Summary, Scope, Validation, and Guardrails. Reformat it to the repo template and add Summary, Scope, Validation, Guardrails, and any issue links or risk details.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: wrapping feature rows and showing an explicit not-included xmark.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/billing-pricing-section-xmark-wrap

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.

@codecov

codecov Bot commented Jul 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.56%. Comparing base (ff0ed6d) to head (2f54706).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4390   +/-   ##
=======================================
  Coverage   99.56%   99.56%           
=======================================
  Files          35       35           
  Lines        1390     1390           
  Branches      435      435           
=======================================
  Hits         1384     1384           
  Misses          6        6           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@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 `@src/modules/billing/components/billing.pricingFeatureSection.component.vue`:
- Around line 59-68: The tooltip activator in
billing.pricingFeatureSection.component.vue is rendered via the v-icon inside
the v-tooltip activator slot, but it is not keyboard-focusable. Update the
tooltip trigger in that component so the icon can receive focus or is replaced
with a button-like activator, and ensure the activator props from v-tooltip are
preserved so keyboard users can open the hint without a mouse.
- Around line 44-58: The included/excluded state in the pricing feature row is
only shown by the icon, which is decorative and not announced to assistive tech.
Update the feature row in the billing pricing section component by adding a
screen-reader-only text label (or equivalent accessible label) on the
row/container near the existing v-icon and item.text rendering, and keep the
icon itself purely visual. Use the existing item.enabled, item.highlight, and
v-icon markup to locate the right place, and avoid relying on an aria-label on
v-icon alone.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d1542ca-d8a4-4722-b374-dbc55a670f3f

📥 Commits

Reviewing files that changed from the base of the PR and between ff0ed6d and 6e3f850.

📒 Files selected for processing (2)
  • src/modules/billing/components/billing.pricingFeatureSection.component.vue
  • src/modules/billing/tests/billing.pricingFeatureSection.component.unit.tests.js

Address CodeRabbit review on the pricing feature section:
- Each ✓/✗ row icon now carries role="img" + an "Included" / "Not included"
  aria-label, so the inclusion state (previously conveyed by icon shape only)
  is announced to assistive tech.
- The tooltip info-icon becomes keyboard-focusable (tabindex="0", role="img",
  aria-label = the hint text, cursor: help) — matches the meterProgress
  tooltip idiom — so keyboard users can reach the hint.

Two unit tests added for the aria-label state announcement and the focusable
tooltip trigger.

Claude-Session: https://claude.ai/code/session_011qpcCc8bq7QpiXLZ8pFFbM
…ria-label

CodeRabbit follow-up: a non-interactive Vuetify v-icon is auto-marked
aria-hidden, so an aria-label on the ✓/✗ icon is never announced. Make the
icon explicitly decorative (aria-hidden="true") and carry the included /
not-included distinction in an sr-only text node on the row instead. Vuetify
4.x ships no sr-only utility, so the standard clip pattern is defined in a
small scoped block. Headline (highlight) rows have no inclusion semantics and
are skipped.

Test updated to assert the sr-only state text + decorative icon.

Claude-Session: https://claude.ai/code/session_011qpcCc8bq7QpiXLZ8pFFbM
@PierreBrisorgueil
PierreBrisorgueil merged commit 4bc2515 into master Jul 1, 2026
7 checks passed
@PierreBrisorgueil
PierreBrisorgueil deleted the feat/billing-pricing-section-xmark-wrap branch July 1, 2026 19:48
PierreBrisorgueil pushed a commit that referenced this pull request Aug 1, 2026
# [2.3.0](v2.2.0...v2.3.0) (2026-08-01)

### Bug Fixes

* **auth,organizations:** guard soft-refresh navigation and the signout race ([#4464](#4464)) ([6a2546e](6a2546e)), closes [#4451](#4451) [#4459](#4459)
* **auth,organizations:** soft-refresh (token) at onboarding sites to prevent silent sign-out ([#4431](#4431)) ([5d88766](5d88766))
* **auth,organizations:** surface failures in org-create and email-verification flows ([#4451](#4451)) ([b161df5](b161df5)), closes [#4431](#4431) [#4447](#4447)
* **auth:** surface requestJoin failures in the org-setup alert ([#4389](#4389)) ([#4397](#4397)) ([f92003d](f92003d))
* **auth:** token() soft-refresh also carries pendingRequests ([#4436](#4436)) ([0b40e8c](0b40e8c))
* **billing:** config-source the upgrade-prompt pricing copy ([#4465](#4465)) ([9cb370d](9cb370d)), closes [#4460](#4460)
* **billing:** meter-mode upgrade prompt copy + single-entry route ([#4410](#4410)) ([df396cf](df396cf)), closes [pricing#units](https://github.com/pricing/issues/units) [pricing#units](https://github.com/pricing/issues/units)
* **billing:** migrate default packs to the V4 pricing-card schema ([#4463](#4463)) ([84789b8](84789b8)), closes [pricing#units](https://github.com/pricing/issues/units) [#4458](#4458)
* **core,organizations:** config-gate org-required header + unify first-org redirect ([#4423](#4423)) ([7adb298](7adb298)), closes [#4421](#4421) [#4422](#4422)
* **core:** wire the computed theme into Vuetify so auto dark-mode works ([#4466](#4466)) ([ed35252](ed35252)), closes [#4462](#4462)
* **prerender:** strip local server origin from captured HTML + fail-hard leak assert ([#4502](#4502)) ([#4503](#4503)) ([dbcf8d7](dbcf8d7))
* **skills:** flip PR to ready before waiting on CodeRabbit to avoid a draft deadlock ([#4473](#4473)) ([a733998](a733998)), closes [#4450](#4450)

### Features

* **billing:** pricing feature rows wrap + explicit ✗ not-included marker ([#4390](#4390)) ([4bc2515](4bc2515))
* **invitations:** show invite form when user-facing invitations enabled with open signup ([#4501](#4501)) ([daa6688](daa6688)), closes [#4500](#4500)
* **skills:** /feature non-interactive invocation — structured SKIP/STOP instead of prompts ([#4455](#4455)) ([197c5f3](197c5f3)), closes [#N](https://github.com/pierreb-devkit/Vue/issues/N) [#failure](https://github.com/pierreb-devkit/Vue/issues/failure) [#4454](#4454)
* **ui:** config-overridable loader, plan-badge set, and copy strings ([#4475](#4475)) ([688911a](688911a)), closes [#4474](#4474)
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.

1 participant