Commit Graph
7 Commits
Author SHA1 Message Date
amosblomqvist 5601a98335 dialogs: delete dialogs drop the serif display title for the abort-turn look
Titles become text-sm font-semibold in destructive red — JetBrains Mono
via the UI default, matching the abort-turn/dismiss-question dialogs the
owner named as the ideal look. Node and session names below the title
drop the sized-up text-lg for normal text-sm, still white mono, no
code-block chrome. Settings and Setup keep their serif titles by owner
ruling; abort-turn already renders this way. 1610/1610 both configs;
verified live on the running dev server.
2026-10-13 09:54:43 +03:00
amosblomqvist e523bea670 keyboard: the one-Esc law — a surfaced layer claims at the document level (keyboard 4 of 4)
Owner ruling (keyboard round 2026-10-06): Esc (or any key) does ONE
action, on the topmost active layer. The plan-open-while-dictating
double-act was the symptom: the plan popup listened at WINDOW level
with no claim, and same-node window listeners all fire — the global
chain (registered first) cancelled the dictation while the plan's own
listener closed the plan. One Esc, two actions.

The law (now the house pattern, documented at the chain):
- field-level handlers claim at their element (focus in a field: the
  field's action) — unchanged, already correct
- every SURFACED layer claims at the DOCUMENT level with preventDefault
  + stopPropagation — document fires before the window chain, so the
  chain stays silent under any surface
- the window chain is the bottom-up fallback: dictation (a live capture,
  NOT a surface — it survives the Esc that closes a plan or overlay),
  then abort (escAbortTarget layers its own targets)

Converted to the claim: plan popup, session overlay, chain table,
settings dialog, setup dialog, the delete/abort dialogs (window-level
stopPropagation was never enough — same-node listeners all fire), and
the stats popover. Popovers (popover-dismiss), menus, model picker, and
the sidebar context menu already claimed correctly.

1427 tests, tsc, lint, build green.
2026-10-07 00:08:49 +03:00
amosblomqvist e7f4923159 deletion screen minimal + 'node' as THE UI word (owner ruling)
Owner 2026-09-30: the confirm dialog's pre-flight impact read had to
go — what full death takes is obvious, the per-open fetch flickered,
and richer facts would only confuse as deletion semantics evolve
(rewiring is on the table). The screen is now: Delete node? / Delete
N nodes?, the names in the mono block, one permanence line, Cancel /
Delete. No loading state, no gone state (a 404 mid-run lands in the
honest failure line), no sessions join — the joins prop died too.

The dead path is deleted end to end: GET /api/graph/nodes/[id],
graphNodeImpact (server), nodeDeletionImpact (core) and their tests.

WORDING: node/node(s) is THE UI word for graph objects, standardized
across every surface's copy (owner, same ruling): the dialog titles,
the chain table's counts/search/summary/delete aria-labels, the
practice dialog's cluster counts, selection line, and empty-cluster
hint. Internal identifiers (selection.propositions) unchanged.

Rewritten dialog pins (tests/delete-node-dialog.test.tsx): minimal
contract — no facts/loading/fetch copy, singular/plural titles, the
cap, 409 dock phrasing, busy states, no 'proposition' left in the
dialog.
2026-09-30 01:19:03 +03:00
amosblomqvist 40dc1b7f85 chain table: the fenced Delete action + multi-node delete dialog (owner ruling)
"This is really the view deletion should be done in" — the chain table
becomes the graph's MANAGEMENT surface. The floating selection bar
gains Delete FENCED at its right end (owner-approved placement): a
divider quarantines the destructive action from Clear and Generate,
red destructive pair + trash icon, opening the SAME full-death confirm
dialog the canvas uses.

DeleteNodeDialog extended from one node to an array:
- one node renders exactly as always; many pluralize the title
  (Delete N propositions?) and list the names in the mono block,
  capped at 8 + 'and K more'
- the pre-flight impact read aggregates: summed edge counts, unioned
  referencing sessions (deduped, first-seen order); all-404 = gone
- confirm runs the per-node DELETEs SEQUENTIALLY — a failure stops
  the run (extraction_running is never plowed through); onDeleted
  now carries every id that actually died
- the chain table prunes its selection on delete and announces
  lh:graph-revision so the snapshot refetches

Drift fix found en route (surfaced as NaN in the aggregated facts):
the server's NodeDeletionImpact has been {edges, sessions} only since
the quiz-events ledger died in the practice-arc schema slim — the
dialog kept rendering quizEvents/observations as undefined. The dead
fact lines are removed; the dialog now shows exactly what the server
can honestly report.
2026-09-30 01:03:59 +03:00
amosblomqvist 6896c23cc2 Session deletion dialog matches the node deletion dialog: red title, mono name below, checkbox flow
Owner polish round (2026-09-24): the two destructive-confirmation
surfaces must read as ONE design. The node dialog was the good one —
the session dialog now wears its exact look and flow.

components/delete-session-dialog.tsx (full rework):
- Red serif "Delete session?" (was neutral "Delete "title"?") — the
  node dialog's destructive title, text-destructive on font-title 2xl.
- The session name below the title in JetBrains Mono at text-lg,
  NO code-block chrome — the font already says code. (The node
  dialog's name got the same treatment: text-xs bg-muted code block
  dies, mono text-lg line lives. Owner chose below-the-title over
  parens-in-the-title: long titles wrap safely below, never inside
  the 25px headline.)
- TWO OPTION BUTTONS -> CHECKBOX FLOW: the locked two-button design
  (preserve-graph / delete-nodes) collapses to ONE unchecked-by-default
  checkbox "Also remove its graph traces" (accent-primary, the settings
  panel's native-checkbox idiom) carrying the graph-touching option's
  consequence copy verbatim. Unchecked = preserve-graph; checked =
  delete-nodes. The unchecked promise ("everything it added to the
  graph stays unless you check below") lives in the intro line now.
- Bottom row = the node dialog's exact pair: quiet Cancel + destructive
  red Delete (border + text, fill on hover), "Deleting…" on the Delete
  button while busy. Try-again re-derives the mode from the checkbox
  (retry IS Delete pressed again; the checkbox is disabled while busy).
- DeleteSessionBody exported pure (the settings/node dialog body
  pattern) for SSR pins; TRACES_COPY exported for the copy pin.
  DELETE_OPTIONS dies with the two-button design.

Tests: session-context.test.tsx's two-option pins rewritten for the
node-dialog shape (red title, mono name no-chrome, unchecked checkbox
default, red Delete pair, old testids absent); delete-node-dialog
pins the chrome-less text-lg name. 905/905. Live-verified on :3001:
both dialogs render 25px red serif titles, 16px mono names, matching
red Delete buttons; Esc closes both, nothing deleted in verification.
2026-09-24 20:06:22 +03:00
amosblomqvist 976be50a81 Polish round: node-delete chrome + rename alignment
Owner polish dispatch (2026-09-23):

- Right-click no longer pins a node or opens the detail card: the
  canvas pointerdown/up handlers now gate on the primary button, so
  the context menu arrives alone.
- Node context menu: label is just "Delete" and the shell hugs its
  content (w-44 -> w-fit); the menu body keeps focus for arrow
  cycling but never shows the browser's default focus ring
  (outline-none on the MenuShell body - applies to every menu).
- Delete confirm: "Delete node?" title in CMU Serif, red
  (text-destructive); the node name sits below in JetBrains Mono
  inline-code; the Delete button carries the destructive treatment
  (border + tint, fill deepens on hover). Rest of the dialog stays
  neutral.
- Sidebar rename row: text and metadata stay at the idle row's x -
  the status spacer and the input's border/padding are gone; the
  underline is the only editing cue.
2026-09-23 18:53:51 +03:00
amosblomqvist 92943864c4 Node deletion affordance (node interlude): right-click menu + full-death confirm
Platform's 50bfcba engine, surfaced. Three pieces:

1. THE RIGHT-CLICK (graph-canvas.ts): a contextmenu listener — always
   preventDefault (the native menu on a full-bleed custom canvas is
   never useful) — picks the node under the pointer and hands the
   canvas-relative position to a new onContext callback (null on empty
   stage). pickAt already respected the visibility filters: a hidden
   node cannot be right-clicked, same as it cannot be clicked. The
   view opens a MenuShell anchored at a zero-size point-div positioned
   at the pointer — MenuShell's placement machine measures it like any
   element, so the menu gets the full discipline: placement, focus on
   open, arrow cycling, honest-fit flip. Delete… is its one action;
   the dismissal contract is the sidebar's (wave 6): outside-click /
   Esc (claimed) close, and a camera move closes it too — a menu
   floating over a moved graph is anchored to nothing.

2. THE CONFIRM (delete-node-dialog.tsx, portaled z-50 like the
   session-delete dialog whose tone it follows): the pre-flight impact
   read (GET /api/graph/nodes/[id]) renders the plain facts — link
   count, quiz-answer count, session-note count (zeros stay visible —
   hiding a zero fact would understate the blast), and the referencing
   sessions with display names joined CLIENT-SIDE from the snapshot
   (chat titles; imported-notes file paths; unknown ids honestly
   themselves). "This cannot be undone" says the permanence. The 409
   extraction_running renders the dock phrasing (EXTRACTION_RETRY_LINE —
   the server names the extraction, the ACTIVITY DOCK is the surface
   the user actually watches drain) with a Try-again; every other
   failure shows the server's line verbatim. The honest 404 (deleted
   elsewhere meanwhile) states it plainly and its Close rides the same
   refresh. The pure body is exported separately (the settings-dialog
   pattern) — SSR pins everything the live dialog shows.

3. SUCCESS: onDeleted dispatches lh:graph-revision with the returned
   graphRevision — the wave-6 chain refetches snapshot + costs. The
   detail card closes if it pointed at the dying node (the refetch
   would close it anyway; the same frame should not show a card for a
   node the user just killed). Clusters shrink / unrender below the
   minimum on the server's read — the client just renders the
   refreshed snapshot.

Tests: 867/867 (+8 — the join helper, honest plurals, the 409 phrasing
pin, the dialog body at loading/gone/impact/failure states).
Live-verified on :3001 against the real engine, scratch data: impact
facts match the API, the intercepted 409 shows the dock line and
Try-again recovers into a real delete, the three-member cluster died
below MIN_CLUSTER_SIZE server-side, the labeled seedplan cluster +
its canvas label died with it (cold load draws nothing stale; the
in-session refresh refetches and the dying node's label stops
drawing), other nodes survived, and the full menu contract holds
(empty stage → no menu; Esc, outside-click, camera move all close).
2026-09-23 16:37:07 +03:00