Feat/design system compliance - #114
Conversation
…for every run, UI polish Three production fixes plus a feature upgrade for the Playwright Dashboard and the QA Office chat panel: - **Multi-agent collaboration** in /api/qa-agent: primary → critic → primary refine → Edi M synthesis. Auto-triggered when 2+ agents are tagged or the manager is mentioned. New SSE turn_start/turn_done/turn_verdict events produce a threaded conversation in chat, with colour-coded role pills. - **Run logs persisted** alongside each archived run; clicking an old run re-hydrates the dashboard log panel. archiveRun() now logs success/failure to the server console so silent archive failures are visible. - **Edi M summary now streams to chat for every Run Tests**, not just agent-generated dynamic runs. Phase 2 streamSummary() helper shared by /api/playwright/run and /api/run-dynamic-test. - **Dashboard UI/UX polish**: KPI hero with progress ring + verdict, pill subtitle row, history-chart hover tooltip + moving-average trend line, sticky suite headers with smooth chevron rotation, copy-error button, cropped QA Office canvas (no more "blue void" above the office). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- server: drop unnecessary \- escape in runId sanitiser regex - tests/sv-login: remove unused BASE_URL import - PlaywrightDashboard: replace ternary-as-statement with explicit if/else in the multi-spec picker onChange (no-unused-expressions) - OfficePage + PlaywrightDashboard: remove orphaned `eslint-disable-next-line react-hooks/exhaustive-deps` directives — the rule isn't registered in this project's ESLint config so the directive itself was reported as an error - PlaywrightDashboard: drop two unused `// eslint-disable-line` trailing comments flagged by no-unused-disable - README: mention multi-agent collab + persistent run history features so the docs-check script sees a docs update alongside the code change Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-format 115 files with Prettier to fix the failing format:check workflow step. Also removes the temporary PR_BODY.md file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, summary snapshot, types) - CHANGELOG: remove duplicate bullets (two entries appeared under both the unreleased ### Changed block and an orphaned second block) - runCollabTurn: accept and forward history + imageAttachments into startChat/sendMessageStream so collaborative turns preserve context and vision - capturedLog: switch from oldest-first cap to a sliding window (push + shift) so archiveRun and AI summaries always see the newest 5 000 lines - streamSummary: accept runId in SummaryCreds; reads the per-run immutable archive instead of the shared RESULTS_PATH to prevent concurrent-run clobbering - Both route close-handlers now capture archiveRun return value and pass runId to streamSummary - PlaywrightDashboard: define RunRequest and SummaryEvent types; runWithSSE typed as (body: RunRequest); evt typed as SummaryEvent | Record<string,unknown>; fetchResults always calls setRunLog (clears to [] when not an archived run) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-and-ui-upgrades # Conflicts: # CHANGELOG.md # server/index.ts # ui/src/pages/PlaywrightDashboard.tsx
Satisfies the docs-validation CI check that requires README.md to be updated alongside any server/ or ui/src/ changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrote all nine documentation sections in DocsPage to reflect the current project state. Replaced every Anthropic/Claude reference with Gemini/Ollama, updated the directory tree, rewrote the env-var section with dual-provider setup instructions, corrected the tech stack table, added FAQ entries for provider switching and multi-agent collaboration, and updated the roadmap to mark completed features as done. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all off-spec color usage across PlaywrightDashboard.tsx: - Primary brand blue: #2563eb (Tailwind blue-600) → #1a3a8f (DESIGN primary) applied to all interactive elements — buttons, toggles, active file border, selected-bar outline, badges, latest/viewing chips, send button. - Success semantic: #10b981 (emerald-500) → #34C759 / #16A34A (DESIGN success) applied to StatusIcon, StatusBadge, KPI bar, chart bars, inline counts. - Warning semantic: #fbbf24 (amber-400) → #E8A728 / #D97706 (DESIGN warning) applied to StatusIcon, StatusBadge, chart bars, duration gradient, KPI bar. - Tooltip background: #1e1e2e → #2D2823 (DESIGN tooltip spec). - StatusBadge: removed `uppercase` text-transform (DESIGN: no uppercase chips). - rgba tints updated from Tailwind blue to brand primary rgba(26,58,143,…). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughPlaywrightDashboard gains structured SSE event handling for AI summary streaming, archived run log restoration, and a comprehensive design system color refresh. Documentation updated for Gemini/Ollama stack. CHANGELOG and README revised to reflect these changes. ChangesDashboard & Documentation Updates
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
… feature row Satisfies check-docs-updated.sh CI requirement — README.md must be in the diff whenever ui/src/ files change. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ui/src/pages/DocsPage.tsx (1)
35-308:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftLocalize Docs content instead of hardcoded English blocks
Most newly added user-facing strings are hardcoded in
sections(for example Line 37, Line 78, Line 230, Line 268), so they cannot be translated throughreact-i18next. This makes the Docs page effectively English-only and hard to maintain as content evolves. Please move these strings into translation resources and reference them viat(...)(or structured translation objects) for each block.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/pages/DocsPage.tsx` around lines 35 - 308, The docs content is hardcoded in the sections/blocks array (the constant named sections in DocsPage.tsx) so it must be replaced with translation keys; extract each user-facing string (paragraph text, list items, code labels, table headers/rows, FAQ q/a, roadmap entries) into your i18n resource files (e.g. under docs.sections.*) and update the sections data to reference t('docs.sections.<key>') or structured translation objects (e.g. t('docs.sections.env-vars.blocks.0.text', { returnObjects: true })) using the useTranslation hook (t) in DocsPage.tsx so every block reads content via t(...) instead of literal English strings. Ensure code block labels and table rows also use translation keys and keep existing block type shape so UI rendering (blocks map) continues to work.
🧹 Nitpick comments (1)
ui/src/pages/PlaywrightDashboard.tsx (1)
4807-4812: ⚡ Quick winKeep the SSE payload parser strictly typed.
Falling back to
Record<string, unknown>turns these API responses back into a generic bag, so any JSON object with anevtfield is accepted and skipped out of the plain-log path. A smallisSummaryEvent()guard would keep this aligned with the declaredSummaryEventcontract in both parsers.Possible fix
+ function isSummaryEvent(value: unknown): value is SummaryEvent { + if (!value || typeof value !== 'object' || !('evt' in value)) return false; + const evt = (value as { evt?: unknown }).evt; + return evt === 'summary_start' || evt === 'summary_chunk' || evt === 'summary_done'; + } + // First try to parse as a structured event object - let evt: SummaryEvent | Record<string, unknown> | null = null; + let evt: SummaryEvent | null = null; try { - const parsed = JSON.parse(raw); - if (parsed && typeof parsed === 'object' && 'evt' in parsed) { - evt = parsed as SummaryEvent | Record<string, unknown>; - } + const parsed: unknown = JSON.parse(raw); + if (isSummaryEvent(parsed)) evt = parsed; } catch { /* not JSON — fall through to plain string */ }As per coding guidelines,
**/*.{ts,tsx}: Use strict TypeScript interfaces/types for all test data, API responses, and parameters. Noanytypes. Ever.Also applies to: 4960-4965
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/pages/PlaywrightDashboard.tsx` around lines 4807 - 4812, The SSE payload parser currently falls back to a loose Record<string, unknown> (in the block that assigns evt from JSON.parse(raw)), which weakens typing; add a strict type guard function isSummaryEvent(obj: unknown): obj is SummaryEvent and use it when validating parsed so evt is only set when isSummaryEvent(parsed) is true (remove the Record<string, unknown> fallback), update both locations referenced (the current parse at the evt assignment and the similar block at the other occurrence around lines 4960-4965), and ensure downstream code expects SummaryEvent or null so the compiler enforces the contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ui/src/pages/PlaywrightDashboard.tsx`:
- Around line 4636-4637: The current call to setRunLog unconditionally replaces
the live log and trims it to 999 lines; change it so the run log is only
replaced when viewing an archived run (i.e. when runId is truthy and data.runLog
is an array) and preserved on latest-run refreshes (do nothing / keep previous
state when runId is falsy). In the archived-run branch (where you still update),
stop trimming to 999 and either remove the slice or use the server window size
(e.g., 5000) so you don't truncate server-kept history; update the logic around
setRunLog, runId and data.runLog (the fetchResults post-stream refresh path)
accordingly.
---
Outside diff comments:
In `@ui/src/pages/DocsPage.tsx`:
- Around line 35-308: The docs content is hardcoded in the sections/blocks array
(the constant named sections in DocsPage.tsx) so it must be replaced with
translation keys; extract each user-facing string (paragraph text, list items,
code labels, table headers/rows, FAQ q/a, roadmap entries) into your i18n
resource files (e.g. under docs.sections.*) and update the sections data to
reference t('docs.sections.<key>') or structured translation objects (e.g.
t('docs.sections.env-vars.blocks.0.text', { returnObjects: true })) using the
useTranslation hook (t) in DocsPage.tsx so every block reads content via t(...)
instead of literal English strings. Ensure code block labels and table rows also
use translation keys and keep existing block type shape so UI rendering (blocks
map) continues to work.
---
Nitpick comments:
In `@ui/src/pages/PlaywrightDashboard.tsx`:
- Around line 4807-4812: The SSE payload parser currently falls back to a loose
Record<string, unknown> (in the block that assigns evt from JSON.parse(raw)),
which weakens typing; add a strict type guard function isSummaryEvent(obj:
unknown): obj is SummaryEvent and use it when validating parsed so evt is only
set when isSummaryEvent(parsed) is true (remove the Record<string, unknown>
fallback), update both locations referenced (the current parse at the evt
assignment and the similar block at the other occurrence around lines
4960-4965), and ensure downstream code expects SummaryEvent or null so the
compiler enforces the contract.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 400f344f-e2e8-4953-94a6-7cd91aa10b3a
📒 Files selected for processing (5)
CHANGELOG.mdREADME.mdserver/index.tsui/src/pages/DocsPage.tsxui/src/pages/PlaywrightDashboard.tsx
| // Restore the archived stdout when viewing an old run; clear when switching to latest. | ||
| setRunLog(runId && Array.isArray(data.runLog) ? data.runLog.slice(-999) : []); |
There was a problem hiding this comment.
Don't wipe the run log during the post-run refresh.
Both SSE runners call fetchResults() as soon as streaming finishes, so this latest-run branch clears the just-streamed output and makes the Run Output panel disappear right after a successful run. It also trims archived snapshots back to 999 lines even though the server now keeps a 5000-line window. Preserve the current log on latest refreshes, and only replace it when you actually hydrate an archived run.
Possible fix
- const fetchResults = useCallback(async (runId?: string) => {
+ const fetchResults = useCallback(async (runId?: string, opts?: { preserveRunLog?: boolean }) => {
setIsLoading(true);
try {
const url = runId
? `${API_BASE}/api/playwright/results/${runId}`
: `${API_BASE}/api/playwright/results`;
const res = await fetch(url);
// ...
setExpandedSuites(Object.fromEntries(data.suites.map((s) => [s.id, true])));
- setRunLog(runId && Array.isArray(data.runLog) ? data.runLog.slice(-999) : []);
+ const hydratedLog = Array.isArray(data.runLog) ? data.runLog.slice(-5000) : [];
+ if (runId) {
+ setRunLog(hydratedLog);
+ setShowLog(hydratedLog.length > 0);
+ } else if (!opts?.preserveRunLog) {
+ setRunLog([]);
+ }
} catch {
setServerOnline(false);
setDemoMode(true);
} finally {
setIsLoading(false);
}
}, []);And keep the live log after streaming completes:
- await fetchResults();
+ await fetchResults(undefined, { preserveRunLog: true });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ui/src/pages/PlaywrightDashboard.tsx` around lines 4636 - 4637, The current
call to setRunLog unconditionally replaces the live log and trims it to 999
lines; change it so the run log is only replaced when viewing an archived run
(i.e. when runId is truthy and data.runLog is an array) and preserved on
latest-run refreshes (do nothing / keep previous state when runId is falsy). In
the archived-run branch (where you still update), stop trimming to 999 and
either remove the slice or use the server window size (e.g., 5000) so you don't
truncate server-kept history; update the logic around setRunLog, runId and
data.runLog (the fetchResults post-stream refresh path) accordingly.
…mpliance # Conflicts: # CHANGELOG.md # README.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Description
Fixes # (issue number)
Type of change
Checklist:
Summary by CodeRabbit
Release Notes
New Features
Style
Documentation