Implementation Plan

Add Sample Widget to Dashboard

todo
2026-05-30 agentics feature

Ship a reusable SampleWidget component that renders on the main dashboard, supports collapsed/expanded toggle, and persists its state across page refreshes via localStorage.

File add-sample-widget.html
Path docs/plans/add-sample-widget.html
Acceptance criteria 0 / 5 done

Context

The dashboard currently has no reusable widget pattern. Each panel is hand-rolled, making it hard to add, remove, or reorder sections. A SampleWidget establishes the canonical widget shape — toggle state, localStorage persistence, typed props — that all future dashboard panels will follow.

This plan is also a smoke-test artifact for the plan-agent v0.8.0 optimization: it verifies the skill writes a valid verb-target.html file directly without entering harness plan mode.

Steps

1
todo Create SampleWidget in src/components/widgets/SampleWidget.tsx
A standalone file isolates the widget's state and markup from the dashboard layout, making it independently testable and reusable.
Verify
ls src/components/widgets/SampleWidget.tsx exits 0; npm run build passes with no new type errors.
2
todo Wire SampleWidget into DashboardPage and pass required props
The dashboard is the entry point — wiring here ensures the widget renders inside the correct column layout and receives its data contract.
Verify
Run npm start, navigate to /dashboard, confirm the widget renders in the expected column with correct default state and no console errors.
3
todo Persist collapsed/expanded state to localStorage via a useLocalStorage hook
Without persistence, a page refresh resets the widget — a friction point that erodes trust in dashboard customisation.
Verify
Expand/collapse the widget, then refresh the page — state survives. Confirm in DevTools: localStorage.getItem('widget-sample-expanded') returns the expected boolean string.
4
todo Write unit tests for SampleWidget covering default state, toggle behaviour, and persistence
The localStorage side effect is easy to miss in a refactor; tests catch regressions before they reach production.
Verify
npm test -- --testPathPattern=SampleWidget passes; coverage report shows ≥80% for the component file.

Acceptance Criteria

Verification

Open a browser at http://localhost:3000/dashboard. Confirm the widget renders. Toggle it twice. Open DevTools → Application → Local Storage and confirm the key widget-sample-expanded exists with the correct value. Refresh — confirm state restores. Run npm run build && npm test in the terminal; both must exit 0 with no new failures.

Next Steps

Add configurable title and body content via props

Paste this prompt into Claude to execute this follow-up:

In src/components/widgets/SampleWidget.tsx, add optional props `title: string` (default: "Sample Widget") and `children: React.ReactNode` so the widget title and body content are configurable at the call site. Update DashboardPage to pass a real title. Add a test for the custom title prop. Bump the component's JSDoc version comment.
Wish List
Support drag-to-reorder widgets on the dashboard Wish List

Speculative / blue-sky idea — not on the critical path. Paste into Claude when ready to explore:

Investigate adding drag-to-reorder support for dashboard widgets using the HTML5 Drag and Drop API or a library like @dnd-kit/core. The widget order should persist to localStorage keyed by user ID (or a session key if unauthenticated). Produce a spike plan covering: library choice, state shape for widget order, integration points with the existing SampleWidget pattern, and estimated effort. Do not implement yet — deliver a written recommendation only.
Unresolved Questions
  • Should widget state use localStorage or be synced to the user profile via API?
    We are adding collapsed/expanded widget state to localStorage in the SampleWidget component. Evaluate whether this should instead be persisted to the user profile via the existing /api/user/preferences endpoint. Consider: (1) behaviour when the user logs in on a new device, (2) complexity of the API route vs. a localStorage hook, (3) whether other dashboard settings already use the API. Recommend one approach with a one-paragraph rationale and identify any migration work if the API route is chosen.