feat: implement tool-session progress panel and live list updates
- Add SessionOperationsContext + SessionProgressPanel for global, non-blocking lifecycle progress (create/start/stop/restart/delete/ recreate-tunnel) driven by SSE events. - Promote SessionsContext to authoritative shared session state with refresh, addOrUpdateSession, and removeSession helpers. - Wire AppShell, DashboardPage, SessionsPage, useInstanceActions, ToolStarter, and InstanceList into shared state so lists update immediately after create/delete without manual refresh. - Remove legacy blocking overlays from CreateSessionForm, SessionCard, and InstanceList; keep disabled states and inline spinners only. - Update DashboardPage tests to wrap with SessionsProvider and SessionOperationsProvider. - Add .cache/ to .gitignore. Quality gates: npm run typecheck, npm run lint, npm test -- --run (82 passed).
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-06-12
|
||||
@@ -0,0 +1,37 @@
|
||||
# . (index)
|
||||
dir: .
|
||||
|
||||
## Project Map Protocol
|
||||
|
||||
1. Read this protocol and the root `.pi-map.index.md` first.
|
||||
2. Use `index:` / `map:` references to open relevant directory indexes and maps.
|
||||
3. Load indexes before rich maps during task-start navigation.
|
||||
4. Read the local rich map and actual source before editing.
|
||||
5. Treat non-empty `## dirty` sections in either artifact as stale.
|
||||
6. If source and generated artifacts disagree, trust source.
|
||||
7. If map and index disagree, trust neither blindly; verify from source and regenerate the pair.
|
||||
8. After editing source, run `project_map_patch` for each changed file.
|
||||
9. Before broad architectural claims or final handoff, run `project_map_validate` when freshness matters.
|
||||
|
||||
Trust boundary: index routes, map orients, source decides.
|
||||
|
||||
## role
|
||||
Frontend architecture specification for real-time session progress tracking using Server-Sent Events and shared React state management.
|
||||
## parent
|
||||
-
|
||||
## children
|
||||
- specs
|
||||
index: specs/.pi-map.index.md
|
||||
map: specs/.pi-map.md
|
||||
## files
|
||||
- .openspec.yaml
|
||||
- design.md
|
||||
- proposal.md
|
||||
- tasks.md
|
||||
## links
|
||||
index: ./.pi-map.index.md
|
||||
map: ./.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
@@ -0,0 +1,36 @@
|
||||
# .
|
||||
dir: .
|
||||
|
||||
index: ./.pi-map.index.md
|
||||
|
||||
## Project Map Protocol
|
||||
|
||||
1. Read this protocol and the root `.pi-map.index.md` first.
|
||||
2. Use `index:` / `map:` references to open relevant directory indexes and maps.
|
||||
3. Load indexes before rich maps during task-start navigation.
|
||||
4. Read the local rich map and actual source before editing.
|
||||
5. Treat non-empty `## dirty` sections in either artifact as stale.
|
||||
6. If source and generated artifacts disagree, trust source.
|
||||
7. If map and index disagree, trust neither blindly; verify from source and regenerate the pair.
|
||||
8. After editing source, run `project_map_patch` for each changed file.
|
||||
9. Before broad architectural claims or final handoff, run `project_map_validate` when freshness matters.
|
||||
|
||||
Trust boundary: index routes, map orients, source decides.
|
||||
|
||||
## role
|
||||
Frontend architecture specification for real-time session progress tracking using Server-Sent Events and shared React state management.
|
||||
## files
|
||||
- .openspec.yaml | Defines an OpenAPI specification metadata file with schema type and creation date
|
||||
- design.md | Design document for frontend-only refactoring of session lifecycle progress tracking and live UI updates using SSE events and shared React context. | dep: React, SSE (useEvents), SessionsContext, SessionOperationsContext, AppShell, DashboardPage, SessionsPage, CreateSessionForm, InstanceList, useInstanceActions, ToolStarter, StartToolFAB, EventToastBridge
|
||||
- proposal.md | Proposes a frontend architecture change to add real-time session progress tracking via SSE and shared state across the application. | dep: React, SSE events, state management, AppShell, DashboardPage, SessionsPage, use-instance-actions, CreateSessionForm, SessionCard, InstanceCard
|
||||
- tasks.md | A task checklist for refactoring a web application's session management to use shared state, a global progress panel, and removing legacy progress overlays. | dep: React, state/sessions.tsx, state/session-operations.tsx, useEvents, use-instance-actions.ts, AppShell, SessionsPage, DashboardPage, tool-starter.tsx, start-tool-fab.tsx, instance-list.tsx, create-session-form.tsx, session-card.tsx
|
||||
## arch
|
||||
Documentation-driven design package using OpenAPI metadata, markdown specifications (design/proposal/tasks), and event-driven UI patterns with SSE, shared React context, and global progress panel replacing legacy overlay components.
|
||||
## tags
|
||||
tsx, session, progress, react, state, design, shared, appshell
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
@@ -0,0 +1,71 @@
|
||||
# Design: Tool Session Progress and Live Updates
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Provide structured, real-time progress feedback for every tool lifecycle action.
|
||||
- Ensure all session lists (nav, dashboard, sessions page) update immediately after create/delete.
|
||||
- Remove blocking and card-dimming overlays that hide context and provide no step detail.
|
||||
- Keep the change frontend-only, reusing existing SSE and session APIs.
|
||||
|
||||
**Non-Goals:**
|
||||
- No new backend endpoints or event types.
|
||||
- No changes to the actual Docker/container orchestration logic.
|
||||
- No redesign of the session card layout beyond action/progress affordances.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision: Global progress panel in the corner
|
||||
A fixed panel (bottom-right desktop, bottom sheet style on mobile) lists in-flight operations. Each operation shows:
|
||||
- Action icon + session display name
|
||||
- Current step label derived from the latest SSE event
|
||||
- A compact stepper: Created → Building → Starting → Probing → Ready/Error
|
||||
- Dismiss button once settled
|
||||
|
||||
This is non-blocking, works across pages, and does not interfere with the modal create flow.
|
||||
|
||||
### Decision: SSE event-driven updates
|
||||
The panel subscribes to `useEvents`. When an operation is started we record `instanceId` + `action`. Incoming events that match a tracked instance update the operation's message, status, and step. Events handled:
|
||||
- `instance.created`, `instance.started`, `instance.restarted` → advance
|
||||
- `instance.health_changed` with `status=running` → complete success
|
||||
- `instance.error` → complete error
|
||||
- `instance.stopped` → complete for stop action
|
||||
- `instance.deleted` → complete for delete action
|
||||
|
||||
### Decision: Shared session state
|
||||
`SessionsContext` is promoted from a nav-only data holder to the authoritative session list:
|
||||
- Holds `sessions`, `isLoading`, `error`, `refreshSessions()`.
|
||||
- Provides `addOrUpdateSession`, `removeSession` for optimistic updates.
|
||||
- `AppShell`, `DashboardPage`, and `SessionsPage` read from this context instead of fetching independently.
|
||||
|
||||
### Decision: Optimistic create/delete updates
|
||||
- **Create**: after the API returns a pending instance, add it to shared state and start tracking. Subsequent SSE events update its status.
|
||||
- **Delete**: remove from shared state as soon as the API succeeds; the progress panel tracks the action until the `instance.deleted` event confirms it.
|
||||
- **Other actions**: keep the existing per-action busy flag on the card for button disabled states, but the panel provides the detailed progress.
|
||||
|
||||
### Decision: Remove legacy overlays
|
||||
- Delete `loading-overlay` and workflow step markup from `CreateSessionForm`.
|
||||
- Remove `session-busy-overlay` and `instance-busy-overlay` (the dimming overlays), but keep button disabled states and small inline spinners.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**Risk: Shared context causes extra re-renders**
|
||||
→ Mitigation: context value is memoized; lists use the same data they already fetched.
|
||||
|
||||
**Risk: SSE events arriving before operation is tracked**
|
||||
→ Mitigation: start tracking before calling the create/start API; for deletes the removal is optimistic and the panel reconciles on the event.
|
||||
|
||||
**Risk: Duplicate feedback between panel and toasts**
|
||||
→ Mitigation: panel shows in-flight steps; toasts remain for terminal success/error only. Existing `EventToastBridge` logic is left largely unchanged.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Extend `SessionsContext` with loading/error/refresh/update helpers.
|
||||
2. Create `SessionOperationsContext` + `SessionProgressPanel` and render it in `AppShell`.
|
||||
3. Update `useInstanceActions` to use shared state and start/stop tracking operations.
|
||||
4. Update `ToolStarter`/`StartToolFAB` to add pending sessions and start tracking.
|
||||
5. Update `CreateSessionForm` to remove overlay and report status to parent.
|
||||
6. Update `InstanceList` to refresh shared state after create/delete.
|
||||
7. Update `SessionsPage` and `DashboardPage` to consume shared context.
|
||||
8. Remove legacy overlay styles.
|
||||
9. Run typecheck, lint, and tests.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Tool Session Progress Indication and Live Updates
|
||||
|
||||
## Why
|
||||
|
||||
Creating or deleting a tool session currently leaves the UI out of sync. After starting a tool from the floating action button, the new session does not appear on `/sessions` or the dashboard until the user manually refreshes or the 30-second poll fires. The existing progress feedback is also poor: `CreateSessionForm` shows a blocking overlay with only two static messages ("Creating instance…", "Starting container…"), and `SessionCard`/`InstanceCard` dim the whole card with a generic spinner. Users cannot see real backend progress (building, starting, probing, running, error) and receive no confirmation when an action finishes.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Introduce a **global session progress panel** that tracks all lifecycle actions (create, start, stop, restart, delete, recreate tunnel) using the existing SSE event stream (`instance.created`, `instance.started`, `instance.health_changed`, `instance.error`, `instance.stopped`, `instance.deleted`, `instance.restarted`).
|
||||
- Make lists update **immediately** after create/delete by sharing session state across `AppShell`, `DashboardPage`, and `SessionsPage`.
|
||||
- Remove the blocking full-screen overlay in `CreateSessionForm` and the card-level busy overlays; replace them with minimal disabled/spinner states and the global panel.
|
||||
- Keep existing toast notifications for terminal states (success/error) while the panel handles in-flight progress.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `session-progress-panel`: Global, non-blocking progress UI for tool lifecycle actions driven by SSE events.
|
||||
- `shared-session-state`: Centralized session list used by navigation, dashboard, and sessions page.
|
||||
|
||||
### Modified Capabilities
|
||||
- `session-lifecycle-ux`: Delete and stop actions now update shared state immediately; create/start actions add a pending session and show progress.
|
||||
- `sessions-hub`: Dashboard and sessions lists reflect new/deleted sessions without manual refresh.
|
||||
|
||||
## Impact
|
||||
|
||||
- Frontend: new `state/session-operations.tsx`, new `components/features/session/session-progress-panel.tsx`, updates to `state/sessions.tsx`, `AppShell`, `SessionsPage`, `DashboardPage`, `hooks/use-instance-actions.ts`, `components/features/tool/instance-list.tsx`, `components/features/tool/tool-starter.tsx`, `components/features/session/create-session-form.tsx`, `components/features/session/session-card.tsx`, and styles.
|
||||
- No API changes: relies on existing lifecycle events and `/users/me/sessions`.
|
||||
|
||||
## Quality Gates
|
||||
|
||||
- `npm run typecheck`
|
||||
- `npm run lint`
|
||||
- Existing frontend tests still pass
|
||||
- Manual verification: create and delete sessions from the FAB and repository detail page; verify panel updates and lists refresh without manual reload.
|
||||
@@ -0,0 +1,23 @@
|
||||
# specs (index)
|
||||
dir: specs
|
||||
|
||||
## role
|
||||
Contains specification documents and design artifacts that define system requirements, APIs, and behavioral contracts for the project.
|
||||
## parent
|
||||
index: ./.pi-map.index.md
|
||||
map: ./.pi-map.md
|
||||
## children
|
||||
- specs/session-lifecycle-ux
|
||||
index: specs/session-lifecycle-ux/.pi-map.index.md
|
||||
map: specs/session-lifecycle-ux/.pi-map.md
|
||||
- specs/sessions-hub
|
||||
index: specs/sessions-hub/.pi-map.index.md
|
||||
map: specs/sessions-hub/.pi-map.md
|
||||
## files
|
||||
## links
|
||||
index: specs/.pi-map.index.md
|
||||
map: specs/.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
@@ -0,0 +1,18 @@
|
||||
# specs
|
||||
dir: specs
|
||||
|
||||
index: specs/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Contains specification documents and design artifacts that define system requirements, APIs, and behavioral contracts for the project.
|
||||
## files
|
||||
## arch
|
||||
Documentation-driven architecture using structured specifications (likely OpenAPI/Protobuf schemas, RFCs, or design docs) to establish interfaces before implementation, serving as the source of truth for cross-service contracts and client generation.
|
||||
## tags
|
||||
-
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# specs/session-lifecycle-ux (index)
|
||||
dir: specs/session-lifecycle-ux
|
||||
|
||||
## role
|
||||
Defines UI/UX requirements for real-time session lifecycle feedback using server-sent events with non-blocking progress indicators and optimistic updates.
|
||||
## parent
|
||||
index: specs/.pi-map.index.md
|
||||
map: specs/.pi-map.md
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- spec.md
|
||||
## links
|
||||
index: specs/session-lifecycle-ux/.pi-map.index.md
|
||||
map: specs/session-lifecycle-ux/.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# specs/session-lifecycle-ux
|
||||
dir: specs/session-lifecycle-ux
|
||||
|
||||
index: specs/session-lifecycle-ux/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Defines UI/UX requirements for real-time session lifecycle feedback using server-sent events with non-blocking progress indicators and optimistic updates.
|
||||
## files
|
||||
- spec.md | Specifies UI/UX requirements for non-blocking progress indicators and optimistic updates for session lifecycle actions using SSE events. | dep: SSE, global progress indicator, shared state management, API
|
||||
## arch
|
||||
Event-driven reactive UX pattern with SSE streaming for asynchronous progress tracking and optimistic state management for immediate user feedback.
|
||||
## tags
|
||||
sse, spec, specifies, requirements, non, blocking, progress, indicators
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
@@ -0,0 +1,44 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Lifecycle actions show structured progress
|
||||
The system SHALL display non-blocking, structured progress feedback for every tool lifecycle action (create, start, stop, restart, delete, recreate tunnel).
|
||||
|
||||
#### Scenario: Create a new session
|
||||
- **WHEN** the user creates a session
|
||||
- **THEN** a global progress indicator appears showing the current backend step
|
||||
- **AND** the indicator advances through Created, Building, Starting, Probing, and Running/Error based on SSE events
|
||||
|
||||
#### Scenario: Delete a session
|
||||
- **WHEN** the user deletes a session
|
||||
- **THEN** the session disappears from the current list immediately
|
||||
- **AND** the global progress indicator shows "Deleting…" until the backend confirms deletion via SSE or API response
|
||||
|
||||
#### Scenario: Stop or restart a session
|
||||
- **WHEN** the user stops or restarts a session
|
||||
- **THEN** the global progress indicator shows the action in progress
|
||||
- **AND** the indicator updates when the backend publishes the corresponding SSE event
|
||||
|
||||
### Requirement: Remove blocking progress overlays
|
||||
The system SHALL NOT dim the entire form or card with a generic spinner while an action is in progress.
|
||||
|
||||
#### Scenario: Create session form submission
|
||||
- **WHEN** the create session form is submitted
|
||||
- **THEN** form controls are disabled
|
||||
- **AND** no full-screen overlay blocks the rest of the application
|
||||
- **AND** progress is shown in the global progress panel
|
||||
|
||||
#### Scenario: Card action in progress
|
||||
- **WHEN** a session card action is triggered
|
||||
- **THEN** the relevant button is disabled or shows a small inline spinner
|
||||
- **AND** the card itself remains fully visible and interactive for other sessions
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Deleted sessions disappear from UI immediately
|
||||
**FROM:** The system SHALL update the frontend state immediately after a session is successfully deleted.
|
||||
**TO:** The system SHALL remove the session from all visible lists optimistically when the delete API call succeeds, and reconcile via shared state.
|
||||
|
||||
#### Scenario: Delete session from any page
|
||||
- **WHEN** the user deletes a session
|
||||
- **THEN** the session is removed from the nav sidebar, dashboard, and sessions page without a reload
|
||||
- **AND** a failure re-adds the session to the list and shows an error
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# specs/sessions-hub (index)
|
||||
dir: specs/sessions-hub
|
||||
|
||||
## role
|
||||
Defines requirements for a shared global session state system that enables real-time UI synchronization across dashboard, sessions page, and navigation components when sessions change.
|
||||
## parent
|
||||
index: specs/.pi-map.index.md
|
||||
map: specs/.pi-map.md
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- spec.md
|
||||
## links
|
||||
index: specs/sessions-hub/.pi-map.index.md
|
||||
map: specs/sessions-hub/.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
@@ -0,0 +1,19 @@
|
||||
# specs/sessions-hub
|
||||
dir: specs/sessions-hub
|
||||
|
||||
index: specs/sessions-hub/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Defines requirements for a shared global session state system that enables real-time UI synchronization across dashboard, sessions page, and navigation components when sessions change.
|
||||
## files
|
||||
- spec.md | Defines requirements for implementing a shared global session state across dashboard, sessions page, and navigation to enable immediate UI updates when sessions are created or modified. | dep: SessionsContext, React Context API, sessions API (`/users/me/sessions`)
|
||||
## arch
|
||||
Specification-driven architecture using a centralized hub pattern with reactive state propagation to decoupled consumers.
|
||||
## tags
|
||||
sessions, spec, defines, requirements, implementing, shared, global, session
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
@@ -0,0 +1,33 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: New sessions appear in lists immediately
|
||||
The system SHALL add a newly created session to every session list as soon as the creation API returns.
|
||||
|
||||
#### Scenario: Create session from floating button
|
||||
- **WHEN** the user starts a tool from the global floating action button
|
||||
- **THEN** the modal closes
|
||||
- **AND** the new session appears on the dashboard and sessions page with status "pending" or "building"
|
||||
- **AND** the active session count in the navigation updates immediately
|
||||
|
||||
#### Scenario: Create session from repository detail
|
||||
- **WHEN** the user launches a tool inside a repository/workspace detail page
|
||||
- **THEN** the new session appears in the repository instance list
|
||||
- **AND** the global session lists update without requiring a manual refresh
|
||||
|
||||
### Requirement: Global session state is authoritative
|
||||
The system SHALL use a single shared session state for the navigation sidebar, dashboard, and sessions page.
|
||||
|
||||
#### Scenario: Shared state updated
|
||||
- **WHEN** a session is added, removed, or changed
|
||||
- **THEN** the navigation badge, dashboard, and sessions page all reflect the change
|
||||
- **AND** no page reload is required
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Sessions page loads sessions
|
||||
**FROM:** Sessions page fetches `/users/me/sessions` independently on mount.
|
||||
**TO:** Sessions page reads sessions from the shared `SessionsContext`; the context fetches on mount and exposes a refresh function.
|
||||
|
||||
### Requirement: Dashboard page loads sessions
|
||||
**FROM:** Dashboard page fetches `/users/me/sessions` independently on mount.
|
||||
**TO:** Dashboard page reads sessions from the shared `SessionsContext`.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Tasks: Tool Session Progress and Live Updates
|
||||
|
||||
## 1. Shared session state
|
||||
|
||||
- [x] 1.1 Extend `state/sessions.tsx` to hold `sessions`, `isLoading`, `error`, and `refreshSessions`, `addOrUpdateSession`, `removeSession` helpers.
|
||||
- [x] 1.2 Ensure `AppShell` uses the extended context and no longer needs a separate local load.
|
||||
- [x] 1.3 Update `SessionsPage` to read sessions from context and call `refreshSessions` after mutations.
|
||||
- [x] 1.4 Update `DashboardPage` to read sessions from context and call `refreshSessions` after mutations.
|
||||
|
||||
## 2. Global progress panel
|
||||
|
||||
- [x] 2.1 Create `state/session-operations.tsx` with an `Operation` model and `useSessionOperations` hook/API.
|
||||
- [x] 2.2 Create `components/features/session/session-progress-panel.tsx` that subscribes to `useEvents`, matches events to tracked operations, and renders a fixed panel.
|
||||
- [x] 2.3 Render `SessionProgressPanel` in `AppShell` so it is visible on every page.
|
||||
- [x] 2.4 Add minimal styles for the progress panel (desktop corner + mobile bottom bar).
|
||||
|
||||
## 3. Integrate actions with progress and shared state
|
||||
|
||||
- [x] 3.1 Update `hooks/use-instance-actions.ts` to remove deleted sessions optimistically from shared state, refresh on completion, and track start/stop/restart/delete/recreate-tunnel operations.
|
||||
- [x] 3.2 Update `components/features/tool/tool-starter.tsx` to add the new pending session to shared state and start tracking the create/start operation; close modal immediately.
|
||||
- [x] 3.3 Update `components/features/tool/start-tool-fab.tsx` to close modal and rely on the panel/toasts for feedback.
|
||||
- [x] 3.4 Update `components/features/tool/instance-list.tsx` to refresh shared sessions after create/delete.
|
||||
|
||||
## 4. Remove legacy progress overlays
|
||||
|
||||
- [x] 4.1 Remove `loading-overlay` and workflow step UI from `components/features/session/create-session-form.tsx`; keep form disabled during submit.
|
||||
- [x] 4.2 Remove `session-busy-overlay` from `components/features/session/session-card.tsx`; keep button disabled states and inline spinner.
|
||||
- [x] 4.3 Remove `instance-busy-overlay` from `components/features/tool/instance-list.tsx`; keep button disabled states and inline spinner.
|
||||
- [x] 4.4 Remove unused overlay CSS classes or repurpose them.
|
||||
|
||||
## 5. Verification
|
||||
|
||||
- [x] 5.1 Run `npm run typecheck` in `apps/web`.
|
||||
- [x] 5.2 Run `npm run lint` in `apps/web`.
|
||||
- [x] 5.3 Run frontend tests (`npm test -- --run` or equivalent).
|
||||
- [ ] 5.4 Manually verify: create from FAB, create from repository detail, delete from sessions page, stop/restart from dashboard.
|
||||
- [x] 5.5 Run `project_map_patch` for every edited source file.
|
||||
Reference in New Issue
Block a user