Catalogs systemic UI issues by pattern (root causes), what was already fixed in this session, and prioritized recommendations for further work. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
13 KiB
Trading Web UI Audit
Last updated: 2026-05-10 Scope:
learning_ai_invt_trdg/web/src(~13,000 lines of UI code across views/tabs/components) Method: Pattern-based grep audit + manual inspection of fixed components
This doc catalogs UI issues by pattern (so you fix root causes, not symptoms), tells you which files are affected, and recommends concrete fixes.
1. Summary — what's the state of the codebase?
| Metric | Count | Note |
|---|---|---|
Files using style={{...}} inline blocks |
25 | A few have 50–72 blocks each — major drift source |
!important declarations in index.css |
122 | Indicates repeated style-override fights |
<Button> (primitive) usages |
31 files | Has known overlap-with-block-children issue (we hit it in Copilot) |
<table> direct usages |
6 files | Several without scroll containers |
| Largest views | PositionsTab 2035, SimpleView 1635, OverviewTab 1061, AdminTab 990, HomeView 917 |
High UI surface = high bug surface |
The codebase has pattern bugs, not just one-off issues. The same root causes recur across files. Fixing them centrally (CSS overrides, lint rules) is much cheaper than file-by-file.
2. Already fixed in this session
| # | Issue | Fix | Commit |
|---|---|---|---|
| 1 | Plans page: saved-setup cards clipped Edit/Delete buttons; chips truncated with ellipsis instead of wrapping; outer grid forced 380px on saved column | Refactored saved-setup-card to overflow: visible, flex-wrap topline, real chip wrap, single-column form below 1440px |
46a357c |
| 2 | Critical alert banner overflowed at narrow widths; loud red styling | Restructured into wrapper + inner row with min-width:0 text + shrink-0 CTA, max-width 1280px, soft tinted background | 1fa2bcd |
| 3 | Sidebar logo: "ByteLyst / Trading OS" clipped due to two competing CSS rules (44×44 grid vs 56px flex) | Forced flex layout with min-height 60px, brand text ellipsis-only | 1fa2bcd |
| 4 | AI Trading Copilot: Quick Action title and prompt overlapped; not responsive | Replaced <Button> with native <button> with explicit flex-column; responsive 1/2-col grid; line-clamp on prompt |
343ffb4 |
| 5 | DevOps panel tables overflowed | Wrapped in overflow-x: auto, table-layout: fixed, break-word on cells |
d2420f5d |
| 6 | Global: .dashboard-main { overflow: hidden } clipped popovers/modals |
overflow: visible !important |
f463ff6 |
| 7 | Global: right panel covers main on narrow viewports | Collapses to 260px below 1280px, hidden below 1024px | f463ff6 |
| 8 | Global: tables push layout horizontally | .dashboard-content table wrapped with overflow-x: auto |
f463ff6 |
| 9 | Global: header search/indices crowd each other | flex-wrap, search shrinks 240–360px, indices wrap | f463ff6 |
All centralized in web/src/layout-fixes.css (495 lines). Single file = single review surface.
3. Issue patterns (root causes)
Pattern A — <Button> primitive ate block children
Symptom: Two <span style={{display:block}}> inside a <Button> overlap each other.
Root cause: <Button> from @bytelyst/ui is inline-flex internally; block children get treated as inline-flex items.
Fix pattern: Use native <button> with explicit display: flex; flex-direction: column for cards-as-buttons.
Where to look: any <Button> containing 2+ stacked text spans/divs.
grep -rn "<Button" --include="*.tsx" web/src | wc -l # 31 files
Pattern B — Inline styles instead of classes
Symptom: Style drift, no responsive breakpoints, can't override via CSS without !important.
Files: OverviewTab (72 blocks), MyStrategiesTab (64), HomeView (55), ChatControl (28), MembershipTab (26), MarketplaceTab (23), VisualRuleBuilder (22).
Why bad: Inline styles can't have @media queries, can't be tweaked via theme, fight index.css for specificity.
Fix pattern: Lift repeated patterns into named CSS classes; keep one-off positional styles inline.
Pattern C — Hardcoded pixel widths in JSX
Symptom: Doesn't shrink on narrow viewports → horizontal overflow. Findings:
App.tsx:226maxWidth: 420(toast container)Header.tsx:77width: 300(search) — already fixed via CSS overrideMembershipTab.tsx:48,160width: 44,maxWidth: 1400VisualRuleBuilder.tsx:111,326width: 70,width: 260RightPanel.tsx:109width: 52, height: 44(image — fine, intentional thumbnail)PositionsTab.tsxmultipletruncate max-w-[80px/120px/180px/220px/260px]
Fix pattern: Replace fixed widths with flex/grid + min-width: 0 + flex: 0 1 <basis>. For images, keep fixed but add flex-shrink: 0.
Pattern D — overflow: hidden on cards that have anchored children
Symptom: Buttons, badges, dropdowns clipped. Findings (current):
ReconciliationAuditPanel.tsx:447,509,579—<Card className="overflow-hidden rounded-2xl">× 3AdminTab.tsx:372,608,843— admin panel sections with overflow-hiddenPositionsTab.tsx:1392,1578—table-container ... overflow-hidden(this one is correct — it's the wrapper for a horizontal-scroll table)
Fix pattern: Use overflow: hidden only when intentionally clipping (e.g. rounded corners over images). For cards that contain actionable children, prefer overflow: visible and let children manage their own bounds.
Pattern E — Truncation without title attribute
Symptom: User sees "PKRBKDW7…" with no way to read the full value.
Findings: 11 instances of className="...truncate..." without a sibling title= attribute (a11y + UX regression).
Fix pattern: Always pair truncate with title={value} so hover/focus shows full content.
Pattern F — Grid templates without minmax(0, 1fr)
Symptom: Grid children with content wider than 1fr push past container.
Findings:
index.css:1230grid-template-columns: 2fr 1.2fr 1fr 1.2fr(no minmax)index.css:1895grid-template-columns: repeat(3, 1fr)(no minmax)index.css:2325grid-template-columns: 100px minmax(220px, 1fr) 90px ...— fineMarketplaceTab.tsx:36,86,MembershipTab.tsx:100,MyStrategiesTab.tsx:127—gridTemplateColumns: '1fr 1fr'inline
Fix pattern: Always use minmax(0, 1fr) not bare 1fr in grid templates. Default min-width is auto which equals min-content of children; minmax(0,...) lets the column shrink.
Pattern G — Two competing CSS rules for the same class
Symptom: Styles you can't reason about; depends on rule order in 3000-line stylesheet.
Where seen: .trading-sidebar-logo (44×44 grid block at line 349 + 56px flex block at line 1546). The logo bug we fixed was a direct consequence.
Likely more: index.css has 122 !important declarations — each one suggests a fight between two rules. Worth a future cleanup pass.
Pattern H — 100vw / vw units inside layouts with a fixed sidebar
Symptom: Element widths don't subtract sidebar/scrollbar width → overflow. Findings:
index.css:1620width: min(42vw, 460px) !important;index.css:1791,1798,1822,1832—clamp(... vw ...)for fluid typography (these are fine)ChatControl.tsx:635maxWidth: 'calc(100vw - 32px)'(acceptable — modal portaled to body, no sidebar offset)TradeProfileManager.tsx:908max-w-[92vw](also portaled side-drawer — acceptable)
Fix pattern: Inside the dashboard shell use 100% not 100vw. vw only safe for elements outside the sidebar layout (modals, banners).
4. High-impact components still to address
4.1 PositionsTab.tsx (2035 lines, Portfolio page)
Issues:
- 6+ instances of
truncate max-w-[80–260px]for trade IDs / sub-tags <table className="pro-table">already has horizontal scroll wrapper, but the innerpro-tablehas hardcodedmin-width: 980px— fine for desktop, but on narrow viewports the table scrolls within itself (correct behavior, by design)- 3 separate scroll regions (
.positions-section,.orders-section,.history-tab) each with their own min-widths - Many badges with hardcoded font/padding via inline style
Recommendation: Keep horizontal scroll behavior (it's correct for data tables). Add title={fullValue} to the 6 truncate instances that don't have it. Audit badge inline styles → lift to .position-badge class.
4.2 OverviewTab.tsx (1061 lines, dashboard landing)
Issues:
- 72 inline
style={{...}}blocks - Likely uses many
<Button>with multiple-span content → potential overlap (Pattern A) - No responsive breakpoints in inline styles
Recommendation: Highest-payoff refactor target. Move colors/spacing into Tailwind utilities or .overview-* classes. Estimated 3–4 hours for a clean pass.
4.3 HomeView.tsx (917 lines, root /)
Issues:
- 55 inline style blocks
- Hero panel uses
clamp(... vw ...)for fluid typography — looks intentional - Action grid likely uses
gridTemplateColumns: '1fr 1fr'(Pattern F)
Recommendation: Same as OverviewTab — extract into classes. Verify mobile breakpoint for action grid (grid-cols-1 md:grid-cols-2 xl:grid-cols-3).
4.4 TradeProfileManager.tsx (slide-over drawer)
Issues:
- Uses
w-[520px] max-w-[92vw]— fixed width on desktop. May feel cramped for forms with many fields. - Drawer slides in from right, portaled to body (good).
Recommendation: Consider w-[640px] on xl: breakpoint for more breathing room. Inspect the form layout for the same overlap-with-Button issue we saw in Copilot.
4.5 ConfigTab.tsx + AdminTab.tsx tables
ConfigTab:
<th className="min-w-[200px/300px/400px]">— guarantees horizontal scroll. Acceptable for a config table; user can scroll.
AdminTab:
max-h-[400px] overflow-y-auto× 2 instances. Bounded height for log/audit panels — likely intentional.max-w-[260px]truncate on token displays — good (these are secrets, full value isn't useful).
Recommendation: No urgent fix. Both pages are admin-only and the scroll behavior is appropriate for their content density.
4.6 ChatControl.tsx (Copilot, just fixed)
Quick Actions block fixed (commit 343ffb4). Remaining minor:
- 28 inline-style blocks (background gradients, animations) — keep, they're animation-specific
- Floating button portal styles — fine
- Backdrop styles — fine
No further action needed.
5. Recommendations
Immediate (1 commit, 1 hour)
- Add
title=to the 11 untitled truncate instances. Quick a11y win. - Add
minmax(0, 1fr)to the 5 inlinegridTemplateColumns: '1fr 1fr'instances in MarketplaceTab/MembershipTab/MyStrategiesTab. Prevents overflow when content gets long. - Convert
<Button>to native<button>in any Button that has 2+ block children inside (audit needed).
Short-term (1 week)
- ESLint rules (preventive):
tailwindcss/no-custom-classnameto catch inline arbitrary widths likew-[80px]- Custom rule:
truncaterequirestitle(catches Pattern E) - Custom rule: flag
gridTemplateColumnscontaining bare1frwithoutminmax - Custom rule: warn on inline
styleblocks with > 5 properties (encourage class extraction)
- CSS audit: scan
index.cssfor class names with multiple definitions; consolidate. Aim to reduce!importantcount from 122 → < 60.
Medium-term (2-3 weeks)
- Refactor OverviewTab + HomeView to extract inline styles into a
home.css/overview.csspartial. Highest user impact (these are the landing pages). - Component primitives audit: the
<Button>overlap issue suggests@bytelyst/uiButton needs a documented prop for stacked children, or a separate<CardButton>primitive. Worth a discussion with the design system team.
6. Quick verification commands
# Check current state
cd /opt/bytelyst/learning_ai_invt_trdg/web/src
# Truncate without title
grep -rn "truncate\b" --include='*.tsx' | grep -v test | grep -v "title=" | wc -l
# Inline style blocks per file (drift indicator)
for f in $(grep -rln "style={{" --include='*.tsx' | grep -v test); do
count=$(grep -c "style={{" "$f")
[ "$count" -gt 20 ] && echo "$count $f"
done | sort -rn
# !important count
grep -c "!important" index.css
# Hardcoded pixel widths in JSX
grep -rEn "(width|minWidth|maxWidth):\s*[0-9]+(px)?[,$]" --include='*.tsx' | grep -v test
7. Files changed in recent UI fix sweep
web/src/layout-fixes.css(new, 495 lines) — all global UI overrides centralizedweb/src/main.tsx— imports layout-fixes.cssweb/src/App.tsx— refactored alert banner JSXweb/src/components/ChatControl.tsx— refactored Quick Actionsweb/src/components/layout/AppShell.tsx— added /devops redirect
The single-file approach (layout-fixes.css) is intentional: every global UI fix lands there with a numbered section + comment explaining the issue. Easy to review, easy to revert one section without touching others.