fix(ui): SimpleFIN transaction table fixed column sizing (batch 0.33.7.3)

- Table now uses table-fixed + colgroup for fixed column widths
- Long transaction text can no longer push action buttons off-screen
- Action buttons are compact icon-only with aria-label/title
- Long matched bill names are truncated with truncate class
- Bump v0.33.7.2 -> v0.33.7.3
This commit is contained in:
null 2026-05-29 16:51:31 -05:00
parent 32f1568515
commit 392de3264f
4 changed files with 71 additions and 20 deletions

View File

@ -1,5 +1,13 @@
# Bill Tracker — Changelog
## v0.33.7.3
### 🐛 Bug Fixes
- **SimpleFIN transaction table now uses fixed column sizing** — Long transaction text no longer pushes action buttons off-screen. Action buttons are compact icon-only with aria-label/title for accessibility. Long matched bill names are truncated.
---
## v0.33.7.2
### 🚀 Features

View File

@ -521,7 +521,14 @@ export default function TransactionMatchingSection({ refreshKey, simplefinConn }
No transactions found for this filter.
</div>
) : (
<table className="w-full text-sm">
<table className="w-full min-w-[860px] table-fixed text-sm">
<colgroup>
<col className="w-[92px]" />
<col />
<col className="w-[200px]" />
<col className="w-[120px]" />
<col className="w-[96px]" />
</colgroup>
<thead>
<tr className="border-b border-border/50 bg-muted/30 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground">
<th className="px-4 py-2 text-left">Date</th>
@ -540,7 +547,7 @@ export default function TransactionMatchingSection({ refreshKey, simplefinConn }
<td className="px-4 py-3 text-xs text-muted-foreground whitespace-nowrap">
{transactionDate(tx)}
</td>
<td className="px-4 py-3 min-w-[240px]">
<td className="max-w-0 px-4 py-3">
<div className="min-w-0">
<p className="truncate text-sm font-medium">{transactionTitle(tx)}</p>
<p className="mt-0.5 truncate text-xs text-muted-foreground">
@ -548,11 +555,11 @@ export default function TransactionMatchingSection({ refreshKey, simplefinConn }
</p>
</div>
</td>
<td className="px-4 py-3 min-w-[180px]">
<td className="px-4 py-3">
<div className="flex flex-col gap-1.5">
<TransactionStatusBadge tx={tx} />
{tx.matched_bill_name ? (
<span className="text-xs text-foreground">{tx.matched_bill_name}</span>
<span className="truncate text-xs text-foreground">{tx.matched_bill_name}</span>
) : (
<span className="text-xs text-muted-foreground">No bill linked</span>
)}
@ -564,29 +571,64 @@ export default function TransactionMatchingSection({ refreshKey, simplefinConn }
)}>
{formatTransactionAmount(tx.amount, tx.currency)}
</td>
<td className="px-4 py-3">
<div className="flex justify-end gap-1.5">
<td className="px-3 py-3">
<div className="flex justify-end gap-1.5 whitespace-nowrap">
{status === 'ignored' ? (
<Button size="sm" variant="outline" type="button" disabled={busy} onClick={() => runTransactionAction(tx, 'unignore')}>
<Button
size="icon"
variant="outline"
type="button"
disabled={busy}
onClick={() => runTransactionAction(tx, 'unignore')}
className="h-8 w-8 shrink-0"
aria-label="Unignore transaction"
title="Unignore transaction"
>
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Eye className="h-3.5 w-3.5" />}
<span className="ml-1.5 hidden xl:inline">Unignore</span>
<span className="sr-only">Unignore</span>
</Button>
) : (
<>
{status === 'matched' ? (
<Button size="sm" variant="outline" type="button" disabled={busy} onClick={() => runTransactionAction(tx, 'unmatch')}>
<Button
size="icon"
variant="outline"
type="button"
disabled={busy}
onClick={() => runTransactionAction(tx, 'unmatch')}
className="h-8 w-8 shrink-0"
aria-label="Unmatch transaction"
title="Unmatch transaction"
>
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Link2Off className="h-3.5 w-3.5" />}
<span className="ml-1.5 hidden xl:inline">Unmatch</span>
<span className="sr-only">Unmatch</span>
</Button>
) : (
<Button size="sm" type="button" disabled={busy || billsLoading} onClick={() => openMatchDialog(tx)}>
<Button
size="icon"
type="button"
disabled={busy || billsLoading}
onClick={() => openMatchDialog(tx)}
className="h-8 w-8 shrink-0"
aria-label="Match transaction"
title="Match transaction"
>
<Link2 className="h-3.5 w-3.5" />
<span className="ml-1.5 hidden xl:inline">Match</span>
<span className="sr-only">Match</span>
</Button>
)}
<Button size="sm" variant="ghost" type="button" disabled={busy} onClick={() => runTransactionAction(tx, 'ignore')}>
<Button
size="icon"
variant="ghost"
type="button"
disabled={busy}
onClick={() => runTransactionAction(tx, 'ignore')}
className="h-8 w-8 shrink-0"
aria-label="Ignore transaction"
title="Ignore transaction"
>
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <EyeOff className="h-3.5 w-3.5" />}
<span className="ml-1.5 hidden xl:inline">Ignore</span>
<span className="sr-only">Ignore</span>
</Button>
</>
)}

View File

@ -7,7 +7,13 @@ export const APP_NAME = 'BillTracker';
export const RELEASE_NOTES = {
version: APP_VERSION,
date: '2026-05-29',
version: APP_VERSION,
highlights: [
{
icon: '🔄',
title: 'SimpleFIN transaction table fix',
desc: 'Transaction table now uses fixed column sizing so long text can\'t push action buttons off-screen. Action buttons are compact icon-only with accessible labels.',
},
{
icon: '🔄',
title: 'SimpleFIN payment backfill',
@ -33,11 +39,6 @@ export const RELEASE_NOTES = {
title: 'Privacy and release notes',
desc: 'A public Privacy page is available from About, release notes can render images, and this update card now resets from the backend whenever the app version changes.',
},
{
icon: '❄️',
title: 'Ramsey Snowball mode',
desc: 'Debt Snowball now defaults to smallest-balance-first, keeps custom drag ordering behind a toggle, skips mortgages by default, and adds an inline Ramsey readiness checklist.',
},
],
image: {
src: '/img/doingmypart.jpg',

View File

@ -1,6 +1,6 @@
{
"name": "bill-tracker",
"version": "0.33.7.2",
"version": "0.33.7.3",
"description": "Monthly bill tracking system",
"main": "server.js",
"scripts": {