fix: form field alignment, raw maintenance text, and static movements list

- .form-grid labels (missing-field form, odometer-regression correction fields)
  and the odometer/overlap note textareas had no stacked label-above-input
  styling at all -- the shared rule only covered .filters/.return-form, so these
  fell back to default inline browser layout with mismatched input widths.
  Extended the existing rule to cover .form-grid and label:has(> textarea).

- Vehicle maintenance list showed the raw, untranslated seed text
  ("Synthetic scheduled service record") regardless of locale -- purely
  decorative and 1:1 redundant with the (already-translated) category. Replaced
  it with the record's real odometer reading, mirroring the sibling
  Inspections tab's pattern.

- "Today's movements" was always the same fixed 4 bookings (2 returns, 2
  departures) on every reset, reading as a static mockup rather than live
  fleet activity. Added 8 more bookings anchored to land on "today" across 8
  additional vehicles, spread through the day.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
NuklearRabbit
2026-08-05 18:29:56 +02:00
co-authored by Claude Sonnet 5
parent 9e9dd8e0e3
commit c2b8268927
4 changed files with 22 additions and 9 deletions
+11 -6
View File
@@ -22,7 +22,9 @@ def test_seed_counts_match_deterministic_dataset():
reset_and_seed(db)
assert db.scalar(select(func.count()).select_from(Vehicle)) == 50
assert db.scalar(select(func.count()).select_from(Customer)) == 180
assert db.scalar(select(func.count()).select_from(Booking)) == 246
# 246 original plus 8 (BK-T-001..008) added so "Today's movements" reads as a
# real day of traffic rather than the same fixed 4 rows on every reset.
assert db.scalar(select(func.count()).select_from(Booking)) == 254
# 21 from the CSV (15 original + 6 giving every unexplained blocked vehicle a
# real open issue) plus a deterministic set discovered by the post-seed scan. The
# shared vehicle-status evaluator (app.services.vehicle_status) also catches
@@ -181,9 +183,10 @@ def test_seed_dates_are_anchored_to_reset_moment():
def test_seed_today_movements_are_a_credible_mix():
"""A fresh reset must not land on a dead 'Today's movements' dashboard section:
at least two departures and two returns should fall on the reset day, mirroring
the same status/date rule the dashboard router uses to build the today list."""
"""A fresh reset must not land on a thin, always-identical 'Today's movements'
dashboard section: a real day of fleet traffic (>=5 departures, >=5 returns, across
more than 4 distinct vehicles) should fall on the reset day, mirroring the same
status/date rule the dashboard router uses to build the today list."""
db = SessionLocal()
try:
reset_and_seed(db)
@@ -197,8 +200,10 @@ def test_seed_today_movements_are_a_credible_mix():
returns = [
b for b in bookings if b.ends_at.date() == today and b.status in ("active", "returned")
]
assert len(departures) >= 2
assert len(returns) >= 2
assert len(departures) >= 5
assert len(returns) >= 5
vehicles_involved = {b.vehicle_id for b in departures} | {b.vehicle_id for b in returns}
assert len(vehicles_involved) > 4
finally:
db.close()
+1 -1
View File
@@ -100,7 +100,7 @@ export function VehicleDetail() {
{vehicle.maintenance.map((m) => (
<li key={m.public_ref}>
<span>{t(`fleet:detail.maintenanceCategories.${m.category}`, { defaultValue: m.category })}</span>
<span>{m.summary}</span>
<span>{formatNumber(m.odometer_km)} km</span>
<time dateTime={m.occurred_at}>{formatShortDate(m.occurred_at)}</time>
</li>
))}
+2 -2
View File
@@ -216,8 +216,8 @@ a:hover { color: var(--teal); }
.badge-dot { display: inline-block; }
.filters { display: flex; flex-wrap: wrap; align-items: end; gap: 12px; margin-bottom: 16px; padding: 14px 16px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.filters label, .return-form label { display: flex; flex-direction: column; gap: 6px; color: var(--ink-soft); font-size: .67rem; font-weight: 700; letter-spacing: .01em; }
.filters input[type="text"], .filters select, .return-form input[type="number"], .return-form textarea, .knowledge-input-row input { min-height: 40px; padding: 8px 11px; color: var(--ink); background: white; border: 1px solid var(--line-strong); border-radius: var(--radius); font-size: .78rem; }
.filters label, .return-form label, .form-grid label, .panel label:has(> textarea) { display: flex; flex-direction: column; gap: 6px; color: var(--ink-soft); font-size: .67rem; font-weight: 700; letter-spacing: .01em; }
.filters input[type="text"], .filters select, .return-form input[type="number"], .return-form textarea, .knowledge-input-row input, .form-grid input, .form-grid select, .panel label:has(> textarea) textarea { min-height: 40px; padding: 8px 11px; color: var(--ink); background: white; border: 1px solid var(--line-strong); border-radius: var(--radius); font-size: .78rem; }
.filters input[type="text"] { min-width: 230px; }.filters select { min-width: 160px; }
.checkbox-label { flex-direction: row !important; align-items: center; gap: 8px !important; }
input[type="checkbox"], input[type="radio"] { width: 17px; height: 17px; accent-color: var(--teal-dark); }
+8
View File
@@ -245,3 +245,11 @@ BK-F-022,CUS-0107,MO-049,2026-08-24T11:00:00Z,2026-09-02T11:00:00Z,reserved,,,tr
BK-DEMO-NEXT,CUS-0088,MO-031,2026-08-02T10:00:00Z,2026-08-07T09:00:00Z,reserved,,,true
BK-DEMO-OVERLAP-A,CUS-0101,MO-016,2026-08-03T09:00:00Z,2026-08-08T09:00:00Z,reserved,,,true
BK-DEMO-OVERLAP-B,CUS-0102,MO-016,2026-08-05T09:00:00Z,2026-08-10T09:00:00Z,reserved,,,true
BK-T-001,CUS-0033,MO-003,2026-07-24T05:30:00Z,2026-08-01T05:30:00Z,returned,20200,20850,true
BK-T-002,CUS-0055,MO-011,2026-07-27T06:30:00Z,2026-08-01T06:30:00Z,returned,25400,25980,true
BK-T-003,CUS-0077,MO-020,2026-07-22T08:45:00Z,2026-08-01T08:45:00Z,returned,31800,32350,true
BK-T-004,CUS-0099,MO-033,2026-07-30T12:00:00Z,2026-08-01T12:00:00Z,returned,41700,42200,true
BK-T-005,CUS-0111,MO-006,2026-08-01T07:15:00Z,2026-08-04T07:15:00Z,reserved,,,true
BK-T-006,CUS-0123,MO-017,2026-08-01T10:30:00Z,2026-08-06T10:30:00Z,reserved,,,true
BK-T-007,CUS-0141,MO-029,2026-08-01T13:15:00Z,2026-08-08T13:15:00Z,reserved,,,true
BK-T-008,CUS-0155,MO-038,2026-08-01T14:30:00Z,2026-08-09T14:30:00Z,reserved,,,true
1 public_ref customer_ref vehicle_ref starts_at ends_at status start_odometer_km end_odometer_km requirements_complete
245 BK-DEMO-NEXT CUS-0088 MO-031 2026-08-02T10:00:00Z 2026-08-07T09:00:00Z reserved true
246 BK-DEMO-OVERLAP-A CUS-0101 MO-016 2026-08-03T09:00:00Z 2026-08-08T09:00:00Z reserved true
247 BK-DEMO-OVERLAP-B CUS-0102 MO-016 2026-08-05T09:00:00Z 2026-08-10T09:00:00Z reserved true
248 BK-T-001 CUS-0033 MO-003 2026-07-24T05:30:00Z 2026-08-01T05:30:00Z returned 20200 20850 true
249 BK-T-002 CUS-0055 MO-011 2026-07-27T06:30:00Z 2026-08-01T06:30:00Z returned 25400 25980 true
250 BK-T-003 CUS-0077 MO-020 2026-07-22T08:45:00Z 2026-08-01T08:45:00Z returned 31800 32350 true
251 BK-T-004 CUS-0099 MO-033 2026-07-30T12:00:00Z 2026-08-01T12:00:00Z returned 41700 42200 true
252 BK-T-005 CUS-0111 MO-006 2026-08-01T07:15:00Z 2026-08-04T07:15:00Z reserved true
253 BK-T-006 CUS-0123 MO-017 2026-08-01T10:30:00Z 2026-08-06T10:30:00Z reserved true
254 BK-T-007 CUS-0141 MO-029 2026-08-01T13:15:00Z 2026-08-08T13:15:00Z reserved true
255 BK-T-008 CUS-0155 MO-038 2026-08-01T14:30:00Z 2026-08-09T14:30:00Z reserved true