learning_ai_invt_trdg/docs/ui/UI_AUDIT.md
Devin 3949062435 Add UI audit report
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>
2026-05-10 08:27:04 +00:00

239 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 5072 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 240360px, 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.
```bash
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:226` `maxWidth: 420` (toast container)
- `Header.tsx:77` `width: 300` (search) — already fixed via CSS override
- `MembershipTab.tsx:48,160` `width: 44`, `maxWidth: 1400`
- `VisualRuleBuilder.tsx:111,326` `width: 70`, `width: 260`
- `RightPanel.tsx:109` `width: 52, height: 44` (image — fine, intentional thumbnail)
- `PositionsTab.tsx` multiple `truncate 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">` × 3
- `AdminTab.tsx:372,608,843` — admin panel sections with overflow-hidden
- `PositionsTab.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:1230` `grid-template-columns: 2fr 1.2fr 1fr 1.2fr` (no minmax)
- `index.css:1895` `grid-template-columns: repeat(3, 1fr)` (no minmax)
- `index.css:2325` `grid-template-columns: 100px minmax(220px, 1fr) 90px ...` — fine
- `MarketplaceTab.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:1620` `width: min(42vw, 460px) !important;`
- `index.css:1791,1798,1822,1832``clamp(... vw ...)` for fluid typography (these are fine)
- `ChatControl.tsx:635` `maxWidth: 'calc(100vw - 32px)'` (acceptable — modal portaled to body, no sidebar offset)
- `TradeProfileManager.tsx:908` `max-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-[80260px]` for trade IDs / sub-tags
- `<table className="pro-table">` already has horizontal scroll wrapper, but the inner `pro-table` has hardcoded `min-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 34 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)
1. Add `title=` to the 11 untitled truncate instances. Quick a11y win.
2. Add `minmax(0, 1fr)` to the 5 inline `gridTemplateColumns: '1fr 1fr'` instances in MarketplaceTab/MembershipTab/MyStrategiesTab. Prevents overflow when content gets long.
3. Convert `<Button>` to native `<button>` in any Button that has 2+ block children inside (audit needed).
### Short-term (1 week)
4. **ESLint rules** (preventive):
- `tailwindcss/no-custom-classname` to catch inline arbitrary widths like `w-[80px]`
- Custom rule: `truncate` requires `title` (catches Pattern E)
- Custom rule: flag `gridTemplateColumns` containing bare `1fr` without `minmax`
- Custom rule: warn on inline `style` blocks with > 5 properties (encourage class extraction)
5. **CSS audit:** scan `index.css` for class names with multiple definitions; consolidate. Aim to reduce `!important` count from 122 → < 60.
### Medium-term (2-3 weeks)
6. **Refactor OverviewTab + HomeView** to extract inline styles into a `home.css` / `overview.css` partial. Highest user impact (these are the landing pages).
7. **Component primitives audit:** the `<Button>` overlap issue suggests `@bytelyst/ui` Button needs a documented prop for stacked children, or a separate `<CardButton>` primitive. Worth a discussion with the design system team.
---
## 6. Quick verification commands
```bash
# 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 centralized
- `web/src/main.tsx` imports layout-fixes.css
- `web/src/App.tsx` refactored alert banner JSX
- `web/src/components/ChatControl.tsx` refactored Quick Actions
- `web/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.