feat(web): frontend overhaul — rebrand, UX fixes, data upgrades, glossary#630
Conversation
…sary Step 1 – UI foundation + rebrand - Replace all "Get Rich Quick" strings with "Augr" in sidebar/header - Add @Utility scrollbar-none for mobile nav horizontal overflow - Set html { font-size: 93.75% } for tighter density at 100% zoom Step 2 – Interaction consistency + stability - Fix WatchlistTable crash: guard score ?? 0, remove unsafe cast in universe-page - Options chain: seed ticker from ?ticker= URL param on mount via commitAndLoad() - Kill switch: unify to destructive variant + Power icon + Stop All/Resume All labels - Remove stale as unknown as ScoredTicker[] cast from universe-page Step 3 – Data + content rendering - Remove all output truncation: analyst-cards, final-signal, decision-inspector - Realtime feed: newest-first sort, panel order swap (viewer above feed), scroll-to-top - Install react-markdown v10; render chat messages as GFM markdown - stock-detail-page: add Price chart, News, Social sentiment stub sections (dashed placeholder state, ready to wire when backend endpoints exist) Step 4 – Knowledge layer + tests - Add Glossary page (/glossary): 28 terms, alpha groups, live filter, anchor links - Add Glossary to nav (BookOpen icon) and App router - Fix react-markdown v10 breaking change: move className from <Markdown> to wrapper <div> - Add options-page.test.tsx (URL param autofill, API call on mount) - Add watchlist null-score test (undefined score renders 0.00) - Add glossary-page.test.tsx (render, filter, empty state, alpha order) - Fix risk-page tests: Activate→Stop All, Deactivate→Resume All - Fix chat-panel test: p.whitespace-pre-wrap → data-testid selector
There was a problem hiding this comment.
Pull request overview
Frontend-focused overhaul of the React/Vite/Tailwind SPA (rebrand + UX/interaction fixes + richer rendering/content pages), plus a backend Polygon client adjustment to respect free-tier pagination rate limits.
Changes:
- Adds new UI surfaces and content (Glossary page/route/nav entry; dashboard “Recent runs”; stock detail stub sections).
- Improves interaction/data rendering (options page URL param seeding + auto-load; watchlist null-guard; realtime feed ordering/scroll behavior; removes output truncation in pipeline components; activity feed now merges historical API events with live WebSocket events).
- Introduces Polygon pagination pacing (12s delay) and a new test to validate rate-limit behavior.
Reviewed changes
Copilot reviewed 35 out of 36 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/pages/universe-page.tsx | Removes unsafe cast when passing watchlist tickers to table. |
| web/src/pages/strategies-page.tsx | Simplifies strategies query (removes filter state and filtered query key). |
| web/src/pages/stock-detail-page.tsx | Adds placeholder cards for chart/news/social sections. |
| web/src/pages/risk-page.tsx | Updates kill switch copy + destructive styling + Power icon. |
| web/src/pages/risk-page.test.tsx | Aligns assertions with updated kill switch labels. |
| web/src/pages/realtime-page.tsx | Newest-first feed sort + auto-scroll logic adjusted to top; panel order tweaks + icon swap. |
| web/src/pages/pipeline-run-page.tsx | Tightens runtime type-guards for phase timings/config snapshot rendering. |
| web/src/pages/order-detail-page.tsx | Centralizes extraction of optional option-related fields from Order. |
| web/src/pages/options-page.tsx | Adds ?ticker= seeding and commit+load helper to avoid refetch race. |
| web/src/pages/options-page.test.tsx | Adds tests for URL param seeding and auto-fetch on mount. |
| web/src/pages/glossary-page.tsx | New glossary page with grouped terms + search + anchors. |
| web/src/pages/glossary-page.test.tsx | Adds coverage for glossary render/filter/empty/grouping behavior. |
| web/src/pages/dashboard-page.tsx | Inserts “RecentRuns” widget into dashboard layout. |
| web/src/pages/dashboard-page.test.tsx | Extends dashboard test to cover recent runs + events fetching. |
| web/src/index.css | Adds scrollbar-none utility and sets root font-size to 93.75%. |
| web/src/components/universe/watchlist-table.tsx | Adds null-guard for score rendering and badge variant selection. |
| web/src/components/universe/watchlist-table.test.tsx | Adds watchlist table tests (including undefined score case). |
| web/src/components/pipeline/final-signal.tsx | Removes truncation; preserves whitespace and shows full output text. |
| web/src/components/pipeline/decision-inspector.tsx | Removes max-height cap; adjusts structured-output null check. |
| web/src/components/pipeline/decision-inspector.test.tsx | Adds basic structured-output render test. |
| web/src/components/pipeline/analyst-cards.tsx | Removes truncation; preserves whitespace and shows full output text. |
| web/src/components/layout/app-shell.tsx | Adds Glossary nav item; updates brand strings; applies scrollbar-none to mobile nav. |
| web/src/components/layout/app-shell.test.tsx | Updates branding assertion to “Augr”. |
| web/src/components/dashboard/recent-runs.tsx | New component fetching and rendering recent pipeline runs. |
| web/src/components/dashboard/recent-runs.test.tsx | Adds tests for populated + empty states. |
| web/src/components/dashboard/activity-feed.tsx | Merges historical API events with live WebSocket events; richer item rendering. |
| web/src/components/dashboard/activity-feed.test.tsx | Updates tests to include QueryClient wrapper + historical events. |
| web/src/components/chat/chat-panel.tsx | Switches message rendering to react-markdown. |
| web/src/components/chat/chat-panel.test.tsx | Updates selectors/assertions for markdown-rendered content wrapper. |
| web/src/components/backtests/backtest-equity-chart.tsx | Hardens tooltip formatters against non-number values. |
| web/src/components/backtests/backtest-equity-chart.test.tsx | Adds basic render + empty-state tests (mocked recharts). |
| web/src/App.tsx | Registers /glossary route. |
| web/package.json | Adds react-markdown dependency. |
| web/package-lock.json | Locks markdown-related transitive deps. |
| internal/data/polygon/universe.go | Increases pagination delay to 12s to respect Polygon free-tier limits. |
| internal/data/polygon/universe_test.go | Adds test validating rate-limit spacing behavior. |
Files not reviewed (1)
- web/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func TestListActiveTickersRespectsFreeTierRateLimit(t *testing.T) { | ||
| var firstRequestAt time.Time | ||
| var serverURL string | ||
|
|
||
| server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| w.Header().Set("Content-Type", "application/json") | ||
|
|
||
| switch r.URL.Query().Get("cursor") { | ||
| case "": | ||
| firstRequestAt = time.Now() | ||
| _, _ = fmt.Fprintf(w, `{"results":[{"ticker":"AAA","name":"Alpha","primary_exchange":"XNAS","type":"CS","active":true}],"next_url":"%s/v3/reference/tickers?cursor=page-2"}`, | ||
| serverURL, | ||
| ) | ||
| case "page-2": | ||
| if time.Since(firstRequestAt) < 11*time.Second { | ||
| w.WriteHeader(http.StatusTooManyRequests) | ||
| _, _ = w.Write([]byte(`{"status":"ERROR","request_id":"req-rate","error":"rate limit exceeded"}`)) | ||
| return | ||
| } | ||
| _, _ = w.Write([]byte(`{"results":[{"ticker":"BBB","name":"Beta","primary_exchange":"XNYS","type":"CS","active":true}]}`)) |
There was a problem hiding this comment.
This test enforces the 12s pagination delay by using real wall-clock time (requires >11s between requests), which will make the test suite take at least ~12s to run and can significantly slow CI. Consider making the pagination delay configurable/injectable (e.g., client field or option) and in this test set it to a small value (and adjust the server threshold accordingly), or mock/simulate the sleep so the behavior can be verified without waiting in real time.
| // Rate limit pause: Polygon free tier allows 5 req/min, so paginated | ||
| // reference-ticker requests need roughly 12s spacing to avoid 429s. | ||
| select { | ||
| case <-ctx.Done(): | ||
| return tickers, ctx.Err() | ||
| case <-time.After(250 * time.Millisecond): | ||
| case <-time.After(12 * time.Second): | ||
| } |
There was a problem hiding this comment.
The 12s hard-coded pause on every paginated request makes ListActiveTickers potentially very slow for large universes and is not easily testable/configurable (e.g., for paid tiers or different limits). Consider using a configurable rate limiter/delay on the Client (or an injected limiter/clock) so production can still respect free-tier limits while keeping tests fast and allowing other tiers to override the pacing.
| // Seed from URL param: /options?ticker=AAPL | ||
| useEffect(() => { | ||
| const tickerParam = searchParams.get('ticker') | ||
| if (tickerParam) commitAndLoad(tickerParam, '', '') | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, []) |
There was a problem hiding this comment.
The mount effect intentionally ignores dependencies (eslint disable) and captures the initial searchParams only. If the user navigates within the SPA to a different /options?ticker=... while staying on the same route component, the input/query won’t update. Prefer including searchParams (or the derived tickerParam) and commitAndLoad in the dependency list, and guard against re-committing when the ticker hasn’t changed.
| <div className="text-sm [&_p]:mb-2 [&_p:last-child]:mb-0 [&_ul]:mb-2 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:mb-2 [&_ol]:ml-4 [&_ol]:list-decimal [&_li]:mb-0.5 [&_h1]:mb-2 [&_h1]:text-base [&_h1]:font-semibold [&_h2]:mb-1.5 [&_h2]:text-sm [&_h2]:font-semibold [&_h3]:mb-1 [&_h3]:text-sm [&_h3]:font-medium [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[11px] [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border [&_pre]:border-border [&_pre]:bg-background [&_pre]:p-3 [&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_blockquote]:border-l-2 [&_blockquote]:border-primary/40 [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_strong]:font-semibold [&_a]:text-primary [&_a:hover]:underline" data-testid="chat-message-content"> | ||
| <Markdown>{msg.content}</Markdown> | ||
| </div> |
There was a problem hiding this comment.
PR description says chat messages render as GFM, but this Markdown renderer is instantiated without any GFM plugin (e.g., remark-gfm), so tables/task lists/strikethrough won’t be supported. Either update the implementation to enable GFM or adjust the PR description to reflect the actual supported Markdown subset.
|
@copilot apply changes based on the comments in this thread |
1 similar comment
|
@copilot apply changes based on the comments in this thread |
Summary
Four-step frontend overhaul across the React/Vite/Tailwind v4 SPA.
Step 1 — UI foundation + rebrand
@utility scrollbar-nonehtml { font-size: 93.75% }for tighter density at 100% zoom (comfortable at 85%)Step 2 — Interaction consistency + stability
score ?? 0null-guard; removed unsafeas unknown as ScoredTicker[]cast inuniverse-page?ticker=AAPLon navigate seeds the input and fires the query on mount via race-condition-freecommitAndLoad()risk-status-barandrisk-pagenow usevariant='destructive', Power icon, and Stop All / Resume All labelsStep 3 — Data + content rendering
analyst-cards,final-signal,decision-inspector— no moreline-clampor.slice()capsreact-markdownv10 installed; all chat messages render as GFM with inline Tailwind prose stylesStep 4 — Knowledge layer + tests
/glossary): 28 trading terms, alphabetically grouped, live search filter, per-term anchor links, category badges — linked from nav and routerreact-markdownv10 breaking change (classNameprop removed from<Markdown>, moved to wrapper<div>)options-page.test.tsx(URL param autofill, API call on mount)undefinedscore renders0.00)glossary-page.test.tsx(6 tests: render, filter by name, filter by definition, empty state, alpha grouping)risk-page.test.tsx(Activate→Stop All, Deactivate→Resume All)chat-panel.test.tsx(p.whitespace-pre-wrap→data-testidselector)Test results
35 targeted tests pass. 27 pre-existing failures in
auth.test.ts(localStorage infrastructure issue, present before this branch).