The decision surface — a refused open becomes a live repair, in place
Phase 3 of the decision surface, completing the card (01 ▸ Malformed input, settled 2026-07-31). An attended open's fail-fast walk transforms the loading window's content into one aggregated surface — never a sheet, never a chain: defects grouped by class, each class stated once with its files listed (Reveal in Finder + Open in Editor per row), a class-level default preselected, per-item override behind a disclosure. Only honest choices: YAML and malformed-schema get Editor + Re-check (Skip below the root); newer-than-app gets Skip alone and blocks the board at the root; the two root repairs — minted index, schema: 1 stamp — are defaults. Repair and Open applies fixes in one store-less write bracket and re-walks: clean proceeds, remainder re-aggregates into the same surface. Cancel and ⌘W retire to welcome's row; restored opens never see the surface at all (OpenOrigin rides the PendingOpen carrier). Skips are per-open consent that rides the session — the store retains the skip set and every reload passes it — and the opened board posts a warning-tone notice naming what was left out, each item's Reveal riding the banner strip's new reveal control. On Pro boards the repair bracket binds its own EchoLedger, heal-marks everything, and the store adopts it before the committer starts, so repairs land as one separate commit authored Lanework Integrity — pinned end to end. Also fixed en route: a retired loading window left its close interception installed and returned false from windowShouldClose forever, blocking quit. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import AppKit
|
||||
import SwiftUI
|
||||
|
||||
/// The banner strip: one window's standing conditions, unread failures, and work in flight, as a
|
||||
@@ -218,6 +219,26 @@ private struct BannerRowView: View {
|
||||
Button(control.label, action: cancel)
|
||||
.buttonStyle(.link)
|
||||
.font(.callout)
|
||||
case let .reveal(targets):
|
||||
// **One control, two renderings** (`BannerRowControl.reveal`): a sole skipped item gets a
|
||||
// plain button, several get a menu naming each path. The row stays one line and one Tab
|
||||
// stop either way, which is what keeps the strip's three-row budget intact on the very
|
||||
// board that just reported something wrong.
|
||||
if targets.count == 1, let only = targets.first {
|
||||
Button(control.label) { Self.reveal(only) }
|
||||
.buttonStyle(.link)
|
||||
.font(.callout)
|
||||
} else {
|
||||
Menu(control.label) {
|
||||
ForEach(targets) { target in
|
||||
Button(target.path) { Self.reveal(target) }
|
||||
}
|
||||
}
|
||||
.menuStyle(.borderlessButton)
|
||||
.fixedSize()
|
||||
.font(.callout)
|
||||
.accessibilityLabel(control.label)
|
||||
}
|
||||
case let .dismiss(id):
|
||||
Button {
|
||||
onDismiss(id)
|
||||
@@ -230,6 +251,14 @@ private struct BannerRowView: View {
|
||||
.help(control.label)
|
||||
}
|
||||
}
|
||||
|
||||
/// Finder, with the file selected — `activateFileViewerSelecting` rather than `open`, so a
|
||||
/// skipped `index.md` is shown *in its folder* rather than handed to whatever app claims `.md`.
|
||||
/// The user's next act is looking at where the file sits; opening it is the surface's other
|
||||
/// affordance, not this one.
|
||||
private static func reveal(_ target: RevealTarget) {
|
||||
NSWorkspace.shared.activateFileViewerSelecting([target.url])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Tone rendering
|
||||
|
||||
Reference in New Issue
Block a user