Skip to content

FE-674: Side-chat polish + DiffPopover + saved-toast move#121

Open
kostandinang wants to merge 2 commits into
ka/fe-674-cascade-edit-and-agentfrom
ka/fe-674-card-4-polish
Open

FE-674: Side-chat polish + DiffPopover + saved-toast move#121
kostandinang wants to merge 2 commits into
ka/fe-674-cascade-edit-and-agentfrom
ka/fe-674-card-4-polish

Conversation

@kostandinang
Copy link
Copy Markdown
Contributor

@kostandinang kostandinang commented May 8, 2026

What

Figma-aligned polish across the side-chat + Pending review surfaces. New DiffPopover primitive. Saved-toast moved out of the page top bar so it doesn't cover the input.

Stacked on #120.

Visual + interaction

  • VocabularyAnnotateNote; add to chat contextAdd to context.
  • Side-chat composer+ note + Notes(N) moved into the input card's action row; Edit-mode strip below the input with a kind-accent toggle pill.
  • Staged-patches strip — per-row kind chip + ↗ view diff + impact chip + discard.
  • Pending review section — warm amber background; [Replace] N pending reviews header; per-row 2px amber left bar; from #ID was edited [↗ view source diff] sub-line; icon-only Edit + solid Resolve.

New DiffPopover primitive

Anchored, viewport-aware popover wrapping <ContentDiff>. Portals into body so it escapes the side-chat dialog's clipping ancestors. Prefers below the anchor, flips above when there's no room. Internal scroll on large diffs. ESC + click-outside close.

Saved-toast

  • Moved out of the page top bar into the structured-list view.
  • Trigger broadened so annotate batches also surface "Change saved".

Misc

  • Edit-mode toggle persists in localStorage.

Test plan

  • CI green
  • Walk through composer, staged patches, pending review on a dense spec
  • Open ↗ view diff from a few rows; popover scrolls internally on large diffs

@kostandinang kostandinang marked this pull request as ready for review May 11, 2026 09:03
@cursor
Copy link
Copy Markdown

cursor Bot commented May 11, 2026

PR Summary

Medium Risk
Moderate UI/UX refactor across side-chat, pending-review, and overlay surfaces (including new portal-based popover and toast relocation), which could affect interaction/keyboard handling and regression-test expectations but does not change backend contracts.

Overview
Introduces a reusable, portal-rendered DiffPopover (viewport-aware positioning, ESC/click-outside close) and switches both side-chat staged edit diffs and pending-review source diffs from inline expanders to anchored popovers.

Polishes the side-chat composer and staged-changes strip to match updated vocabulary and chrome ("Annotate"→"Note", edit-mode strip + placeholder changes, icon-only Apply/Undo/Discard, per-row kind chips) and persists side-chat edit mode in localStorage.

Relocates the "Change saved" toast out of SideChatPopover into PatchListOverlay, broadens toast triggering to any successful batch, and moves PendingReviewSection rendering into the structured-list view (not composed inside the overlay). Updates PendingReviewSection and structured-list inline edit toolbar styling/ARIA accordingly, with expanded test coverage for the new popover and revised UI behavior.

Reviewed by Cursor Bugbot for commit d6e8500. Bugbot is set up for automated code reviews on this repo. Configure here.

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented May 11, 2026

🤖 Augment PR Summary

Summary: This PR delivers Card 4 UI polish for side-chat and pending-review, and introduces a reusable DiffPopover primitive.

Changes:

  • Adds DiffPopover (portal-to-body, viewport-aware, ESC/click-outside close) and wires it into staged patches + pending review source-diff affordances
  • Updates SideChat vocabulary and composer chrome ("Annotate" → "Note", context wording, placeholders, icon sizing, and action layout)
  • Reworks staged-patches strip row layout (kind chips, view-diff chip, impact chip, discard) and footer actions (icon-only Apply/Undo + inline saving status)
  • Refactors PendingReviewSection layout (new header, row left bar, target-leading title, icon-only Edit, solid Resolve, and inline edit form styling)
  • Relocates saved-toast / Undo surface into PatchListOverlay within structured list view (and removes old popover-local toast behavior)
  • Persists side-chat edit-mode toggle across sessions via localStorage
  • Updates and adds tests for the new popover and revised UI flows

Technical Notes: DiffPopover uses createPortal to escape transformed/clipped ancestors and repositions on scroll/resize; toast logic now triggers on batch-id transitions (including annotate batches).

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/client/components/pending-review-section.tsx Outdated
Comment thread src/client/components/pending-review-section.tsx Outdated
Comment thread src/client/components/diff-popover.tsx Outdated
Comment thread src/client/components/side-chat-popover.tsx
@kostandinang kostandinang force-pushed the ka/fe-674-card-4-polish branch from dfd595a to d0aa725 Compare May 11, 2026 09:20
@kostandinang kostandinang force-pushed the ka/fe-674-cascade-edit-and-agent branch from 5c3a70c to 7e4d0d8 Compare May 11, 2026 09:20
@kostandinang kostandinang force-pushed the ka/fe-674-card-4-polish branch from d0aa725 to e2d1fef Compare May 11, 2026 09:34
@kostandinang kostandinang force-pushed the ka/fe-674-cascade-edit-and-agent branch from 7e4d0d8 to 98c902c Compare May 11, 2026 09:34
@kostandinang kostandinang force-pushed the ka/fe-674-card-4-polish branch from e2d1fef to 4e3e4ed Compare May 11, 2026 09:41
@kostandinang kostandinang force-pushed the ka/fe-674-cascade-edit-and-agent branch from 98c902c to 1caa9f8 Compare May 11, 2026 09:41
<PatchListProvider appliers={appliers}>
<SideChatHost specificationId={specificationState.specification.id}>
<div className="flex h-full min-h-0 flex-1 flex-col">
<PatchListOverlay />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PatchListOverlay lost on non-graph specification routes

High Severity

PatchListOverlay was removed from route.tsx (the layout wrapping all /specification/$id/* child routes) and placed only inside StructuredListView, which is rendered exclusively by the graph route. Interview-phase views (grounding, elicitation, acceptance-review, requirements-review) and the export view still have SideChatHost and can stage/apply patches, but no longer render PatchListOverlay. Since the "Change saved" toast was also removed from the side-chat popover in this same PR, users on non-graph routes receive zero post-apply feedback and lose the Undo affordance entirely.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4e3e4ed. Configure here.

@kostandinang kostandinang force-pushed the ka/fe-674-card-4-polish branch from 4e3e4ed to cd79c3f Compare May 11, 2026 09:47
@kostandinang kostandinang force-pushed the ka/fe-674-cascade-edit-and-agent branch 2 times, most recently from 81a4822 to d36f61a Compare May 11, 2026 09:49
@kostandinang kostandinang force-pushed the ka/fe-674-card-4-polish branch 2 times, most recently from 0cfc320 to 6280efb Compare May 11, 2026 10:04
@kostandinang kostandinang force-pushed the ka/fe-674-cascade-edit-and-agent branch from d36f61a to 1f26ae7 Compare May 11, 2026 10:04
…cation

Card 4 (Figma-aligned polish) + DiffPopover primitive + saved-toast surface relocation.

Polish (S1-S4):
- Vocabulary: 'Annotate' → 'Note', 'add to chat context' → 'Add to context',
  composer placeholders, 'Apply N change(s)' / 'Undo last change' aria.
- Side-chat composer: + note + Notes(N) move into the input card's left action
  row; Edit-mode strip below the input card with kind-accent toggle pill;
  top-right header buttons 24×24 → 20×20.
- Staged-patches strip: per-row layout with kind chip + '↗ view diff' chip +
  impact chip + discard; footer 28×28 icon-only Undo + Apply; Saving status
  inline next to Apply.
- Pending-review section: strip bg (255,219,168,0.18); '[Replace] N pending
  reviews' header; per-row 2px neutral-amber left bar; kind chip with
  supersedes/confirm icon; raw '#ID · {target excerpt}' title; 'from #ID was
  edited [↗ view source diff]' sub-line; icon-only Edit + solid kind-accent
  Resolve action row; inline edit form wrapped in kind-accent-tinted card.
- ItemEditTextarea: drop shadow-card + border-rule; use kindAccent-derived
  border + 2px focus ring; icon-only Cancel; Save inline kind-accent fill.

DiffPopover primitive (NEW):
- Anchored, viewport-aware popover wrapping <ContentDiff>. Read-only v1;
  props { open, onClose, anchor, before, after, title, kindChip?, kindAccent? }.
- Renders into document.body via createPortal so the popover escapes the
  side-chat dialog's transformed/clipped ancestors.
- Prefers BELOW the anchor (keeps the chip in view); flips ABOVE only when
  there isn't room. Right-aligns with anchor; reposition on scroll/resize.
- ESC + click-outside close. Slice 7's auto-edit Apply/Skip can extend
  additively via a future footer? slot.
- Wired into both side-chat-popover staged-patches and pending-review rows.

Saved-toast / Undo relocation:
- Removed inline composer 'Change saved' overlay from side-chat-popover (no
  longer covers the input row).
- Moved <PatchListOverlay /> out of the page-level top bar (route.tsx) into
  -structured-list-view.tsx, just above <PendingReviewSection /> (under the
  kind chips). Dropped sticky top-0 z-30 so the overlay sits in flow rather
  than on top of the structured-list nodes.
- Saved-toast banner gains animate-in fade-in slide-in-from-top-1 + a small
  zoom-in emerald check badge.
- Toast trigger broadened from 'applied has data' to 'new lastBatchId + not
  applying + stagedCount=0' so annotate batches (applied=undefined) also
  surface 'Change saved'.

Persistence (Card 4 follow-up):
- side-chat-host.tsx persists Edit-mode toggle in localStorage
  (brunch.side-chat.mode); a new pinned item adopts the stored mode rather
  than falling back to 'explore'.

Color system:
- pending-review-section: kind-relevant chrome (kind chip, row left bar) keeps
  amber; action affordances (Resolve, Save, edit form) use the product's
  primary blue (#3484fa). The neutral-amber row left bar remains a v1 stand-in
  until target_item_kind enrichment lands on the listing endpoint.

Tests:
- New diff-popover.test.tsx (9 tests).
- side-chat-popover.test.tsx: relabeled assertions; replaced FE-665 inline
  <details> expander tests with popover-trigger tests; deleted saved-toast
  lifecycle suite (lifecycle now lives in patch-list-overlay).
- side-chat-host.test.tsx: mounted <PatchListOverlay /> in tests that exercise
  Undo / saved-toast surfaces; cleared localStorage in afterEach so persisted
  Edit-mode doesn't leak between tests; deleted obsolete 'does not leak the
  saved confirmation to another pinned item' assertion (toast is now global).
- structured-list-view.test.tsx: mounted <PatchListOverlay /> + stubbed
  useSpecificationOpenReconciliationNeeds to fix 2 inherited failures.
- patch-list-overlay.test.tsx: removed Pending-review composition assertion
  (PendingReviewSection now renders inside structured-list view).
- pending-review-section.test.tsx: source-diff-popover tests replace inline
  ContentDiff tests; +1 Loader2 spinner test.

memory/CARDS.md: Card 4 marked done.

Verify: 1139 passed, 0 failed; oxlint + oxfmt clean; vite build clean.
Disable inline edit-target textarea/Cancel/Save while the row is also
resolving, so a click can't fire Save mid-Resolve and overlap mutations.

Stop mutating textarea.style.boxShadow imperatively in onFocus/onBlur —
React rerenders during typing restored the inline style and dropped the
intended 2px focus ring. Both PendingReview and structured-list inline
edit textareas now express the focus ring via CSS focus state, using
inline CSS variables for the kind/action accent so the ring color stays
dynamic.

Drop the fallback 'target #id' string when target_current_content is
null — the row title already prefixes #id, so the fallback produced
'#id · target #id'. Now the row shows just '#id' when no content.

Constrain DiffPopover to max-h-[min(70vh,40rem)] with an internal
overflow-y-auto body region so the header (with close button) stays
reachable on large diffs that exceeded the viewport.
@kostandinang kostandinang force-pushed the ka/fe-674-card-4-polish branch from 6280efb to d6e8500 Compare May 11, 2026 10:06
@kostandinang kostandinang force-pushed the ka/fe-674-cascade-edit-and-agent branch from 1f26ae7 to c5bb7ef Compare May 11, 2026 10:06
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d6e8500. Configure here.

// the toast renders conditionally on canUndo so hard applies show "Change
// saved" without an undo affordance.
if (hasApply && !state.isApplying && stagedCount === 0) {
if (!state.isApplying && stagedCount === 0) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saved toast re-fires when navigating between sibling views

Medium Severity

Moving PatchListOverlay from route.tsx (always mounted) into -structured-list-view.tsx (one child view) causes lastSeenBatchIdRef to reset to null whenever the user navigates to a sibling route like graph.tsx or export.tsx and back. On remount, the effect sees state.lastBatchId (persisted in PatchListProvider above Outlet) as a "new" batch and re-fires the saved toast, even though the user already saw it. The staged-changes bar also loses its expanded state on each navigation.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d6e8500. Configure here.

@kostandinang kostandinang changed the title FE-674: Card 4 — Side-chat / pending-review polish + saved-toast relocation FE-674: Side-chat polish + DiffPopover + saved-toast move May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant