Add lightweight toast notification infrastructure that surfaces
repeated errors to users while avoiding alert fatigue.
Components:
- ToastContainer: Renders toast notifications with auto-dismiss
- showToast(): Singleton function to display messages from anywhere
- trackError(): Counts errors by key, surfaces toast after threshold
Error tracking strategy:
- Errors logged immediately (console.error)
- Toast shown only after 3+ occurrences within 30-second window
- Prevents spam from transient network issues
- Reset counter on success (clearErrorCount)
Toast styling:
- Fixed position bottom-right with z-index 100
- Type-aware colors (error=red, success=green, info=yellow)
- Manual dismiss button with auto-dismiss after 5 seconds
- Backdrop blur and slide-up animation
This prepares the dashboard to gracefully handle API failures
without overwhelming users with error popups for transient issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Performance and polish improvements across dashboard components:
Transition optimizations (reduces reflow/repaint overhead):
- OptionButton: transition-all → transition-[transform,border-color,
background-color,box-shadow]
- QuestionBlock: Add transition-colors to textarea, transition-all →
transition-[transform,filter] on send button
- SimpleInput: Same pattern as QuestionBlock
- Sidebar: transition-all → transition-colors for project buttons
Animation additions:
- App: Add animate-fade-in-up to loading and error state containers
- MessageBubble: Make fade-in-up animation conditional on non-compact
mode to avoid animation spam in card preview
Using specific transition properties instead of transition-all tells
the browser exactly which properties to watch, avoiding unnecessary
style recalculation on unrelated property changes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removes unnecessary complexity from ChatMessages while adding proper
scroll management to SessionCard:
ChatMessages.js:
- Remove scroll position tracking refs and effects (wasAtBottomRef,
prevMessagesLenRef, containerRef)
- Remove spinner display logic (moved to parent components)
- Simplify to pure message filtering and rendering
- Add display limit (last 20 messages) with offset tracking for keys
SessionCard.js:
- Add chatPaneRef for scroll container
- Add useEffect to scroll to bottom when conversation updates
- Provides natural "follow" behavior for new messages
The refactor moves scroll responsibility to the component that owns
the scroll container, reducing prop drilling and effect complexity.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements animated modal open/close with accessibility support:
- Add closing state with 200ms exit animation before unmount
- Refactor to React hooks-compliant structure (guards after hooks)
- Add CSS keyframes for backdrop fade and panel scale+translate
- Include prefers-reduced-motion media query to disable animations
for users with vestibular sensitivities
- Use handleClose callback wrapper for consistent animation behavior
across Escape key, backdrop click, and close button
The animations provide visual continuity without being distracting,
and gracefully degrade to instant transitions when reduced motion
is preferred.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes for tool call display in the dashboard:
1. **filterDisplayMessages includes tool_calls** (MessageBubble.js)
Previously filtered out messages with only tool_calls (no content/thinking).
Now correctly keeps messages that have tool_calls.
2. **Type-safe getToolSummary** (markdown.js)
The heuristic tool summary extractor was calling .slice() without
type checks. If a tool input had a non-string value (e.g., number),
it would throw TypeError. Now uses a helper function to safely
check types before calling string methods.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Visual feedback when an agent is actively processing:
1. **Spinner on status dots** (SessionCard.js, Modal.js)
- Status dot gets a spinning ring animation when session is active/starting
- Uses CSS border trick with transparent borders except top
2. **Working indicator in chat** (ChatMessages.js, Modal.js)
- Shows at bottom of conversation when agent is working
- Bouncing dots animation ("...") next to "Agent is working" text
- Only visible for active/starting statuses
3. **CSS animations** (styles.css)
- spin-ring: 0.8s rotation for the status dot border
- bounce-dot: staggered vertical bounce for the working dots
4. **Status metadata** (status.js)
- Added `spinning: true` flag for active and starting statuses
- Used by components to conditionally render spinner elements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the monolithic single-file dashboards (dashboard.html,
dashboard-preact.html) with a proper modular directory structure:
dashboard/
index.html - Entry point, loads main.js
main.js - App bootstrap, mounts <App> to #root
styles.css - Global styles (dark theme, typography)
components/
App.js - Root component, state management, polling
Header.js - Top bar with refresh/timing info
Sidebar.js - Project tree navigation
SessionCard.js - Individual session card with status/actions
SessionGroup.js - Group sessions by project path
Modal.js - Full conversation viewer overlay
ChatMessages.js - Message list with role styling
MessageBubble.js - Individual message with markdown
QuestionBlock.js - User question input with quick options
EmptyState.js - "No sessions" placeholder
OptionButton.js - Quick response button component
SimpleInput.js - Text input with send button
lib/
preact.js - Preact + htm ESM bundle (CDN shim)
markdown.js - Lightweight markdown-to-HTML renderer
utils/
api.js - fetch wrappers for /api/* endpoints
formatting.js - Time formatting, truncation helpers
status.js - Session status logic, action availability
This structure enables:
- Browser-native ES modules (no build step required)
- Component reuse and isolation
- Easier styling and theming
- IDE support for component navigation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>