refactor(transactions): migrate 5 transaction badges to DS::Pill (#1751 PR B) (#1917)

Migrates the hand-rolled "Pending" / "Review recommended" / "Potential
duplicate" / "Split" badges across the transaction views to the
extended DS::Pill primitive from #1902.

**Visual contract for badge mode**

In #1902 the badge mode (`marker: false`) used `rounded-md` (chip shape)
because the marker mode does. But every existing pill / status badge
in the codebase uses `rounded-full` — see
`settings/providers/_status_pill.html.erb`,
`settings/providers/_maturity_badge.html.erb`, and the inline
transaction badges this PR is migrating. To keep the visual contract
consistent, this PR shifts `DS::Pill`'s badge mode to `rounded-full`
(marker mode stays `rounded-md`, unchanged from #1829). The shape
distinction now reads: markers are tags, badges are pills.

**Callsites migrated** (5):

- `app/views/transactions/_transaction.html.erb` — Pending,
  Review-recommended, Possible-duplicate, Split badges
- `app/views/transactions/_header.html.erb` — Pending badge
- `app/views/transactions/_split_parent_row.html.erb` — Split badge

**Tone mapping**

| Badge | Tone | Notes |
|---|---|---|
| Pending | `:neutral` | unchanged copy/icon, gains subtle DS-controlled bg |
| Review recommended | `:neutral` | matches existing `bg-surface-inset` look |
| Possible duplicate | `:warning` | DS semantic alias for the existing `text-warning` |
| Split | `:neutral` | matches existing `bg-surface-inset` look |

**Deferred to follow-up PRs**

- `app/views/transactions/_transfer_match.html.erb` — uses two
  responsive-visibility variants (`hidden lg:inline-flex` for long
  copy, `inline-flex lg:hidden` for short). DS::Pill currently has no
  `class:` arg for caller-controlled wrapper classes; deferring until
  that lands.
- `app/views/transactions/searches/filters/_badge.html.erb` — has a
  close button alongside the label (`button_to clear_filter_*`) and
  uses `rounded-3xl p-1.5` instead of a true pill. Closer to a
  removable filter chip — better fit for a separate `DS::FilterChip`
  primitive than for `DS::Pill`.

Refs #1751.
This commit is contained in:
Guillem Arias Fauste
2026-05-23 08:46:55 +02:00
committed by GitHub
parent 814505c5ea
commit 20844923e6
5 changed files with 67 additions and 42 deletions

View File

@@ -1,16 +1,19 @@
require "test_helper"
class DS::PillTest < ViewComponent::TestCase
test "marker mode (default) renders uppercase sub-12px chrome" do
test "marker mode (default) renders uppercase sub-12px chrome with rounded-md" do
render_inline(DS::Pill.new(label: "Beta", tone: :violet))
pill = page.find("span", text: "Beta")
assert_includes pill[:class], "uppercase"
# Marker keeps sub-12px text via arbitrary value (intentional — see component docs).
assert_match(/text-\[1[01]px\]/, pill[:class])
# Marker uses rounded-md (chip shape).
assert_includes pill[:class], "rounded-md"
refute_includes pill[:class], "rounded-full"
end
test "marker: false renders normal-case DS-scale chrome" do
test "marker: false renders normal-case DS-scale chrome with rounded-full" do
render_inline(DS::Pill.new(label: "Active", tone: :success, marker: false))
pill = page.find("span", text: "Active")
@@ -18,6 +21,9 @@ class DS::PillTest < ViewComponent::TestCase
# Badge mode snaps to text-xs / text-sm — no sub-12px arbitrary values.
assert_match(/text-(xs|sm)/, pill[:class])
refute_match(/text-\[1[01]px\]/, pill[:class])
# Badge uses rounded-full to match the existing _status_pill / _maturity_badge convention.
assert_includes pill[:class], "rounded-full"
refute_includes pill[:class], "rounded-md"
end
test "semantic tone aliases resolve to visual palette tones" do
@@ -51,9 +57,9 @@ class DS::PillTest < ViewComponent::TestCase
# Lucide icon helper renders the inline SVG; verifying we see at least one <svg>
# is enough — the icon helper is covered by its own tests.
assert_selector "svg"
# And the dot is suppressed when an icon takes its place. `refute_selector
# ..., count: N` only fails when there are exactly N matches, so use
# `assert_no_selector` to strictly assert zero dots.
assert_no_selector "span.rounded-full[style*='background-color']"
# And the dot is suppressed when an icon takes its place. The dot is an
# `inline-block` span (parent pill is `inline-flex`), so target it by
# `inline-block.rounded-full` to avoid matching the parent pill.
assert_no_selector "span.inline-block.rounded-full"
end
end