@tangle-network/agent-app 0.43.20 → 0.43.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{VaultPane-DsbRC1rj.d.ts → VaultPane-DrQ_tH6c.d.ts} +19 -1
- package/dist/VaultPane-HFH734K6.js +7 -0
- package/dist/{chunk-65ZRAZL3.js → chunk-FVJP2RTC.js} +186 -32
- package/dist/chunk-FVJP2RTC.js.map +1 -0
- package/dist/vault/index.d.ts +1 -1
- package/dist/vault/index.js +1 -1
- package/dist/vault/lazy.d.ts +2 -2
- package/dist/vault/lazy.js +1 -1
- package/package.json +1 -1
- package/dist/VaultPane-GIXYVVPZ.js +0 -7
- package/dist/chunk-65ZRAZL3.js.map +0 -1
- /package/dist/{VaultPane-GIXYVVPZ.js.map → VaultPane-HFH734K6.js.map} +0 -0
|
@@ -57,6 +57,21 @@ interface VaultDataPort {
|
|
|
57
57
|
/** Delete the file at `path`. */
|
|
58
58
|
deleteFile(path: string): Promise<void>;
|
|
59
59
|
}
|
|
60
|
+
/** The Vault operation that failed at the product-owned data-port seam. */
|
|
61
|
+
type VaultOperation = 'list' | 'read' | 'save' | 'create' | 'delete';
|
|
62
|
+
/** Whether the operation itself failed or a mutation succeeded but its
|
|
63
|
+
* follow-up tree refresh did not. */
|
|
64
|
+
type VaultOperationPhase = 'operation' | 'post-mutation-refresh';
|
|
65
|
+
/** Structured failure reported to an optional host observer. VaultPane always
|
|
66
|
+
* renders its own recovery UI; this payload is for telemetry or additional
|
|
67
|
+
* product presentation and never controls the pane's state machine. */
|
|
68
|
+
interface VaultOperationFailure {
|
|
69
|
+
operation: VaultOperation;
|
|
70
|
+
phase: VaultOperationPhase;
|
|
71
|
+
path?: string;
|
|
72
|
+
message: string;
|
|
73
|
+
cause: unknown;
|
|
74
|
+
}
|
|
60
75
|
/**
|
|
61
76
|
* The parsed form of a file's rich content. The pane stays agnostic about the
|
|
62
77
|
* shape — it round-trips `serialize(parse(raw))` through the codec to compute
|
|
@@ -163,6 +178,9 @@ interface VaultPaneProps {
|
|
|
163
178
|
selectedPath?: string | null;
|
|
164
179
|
/** Notified whenever the selected path changes (including clear → null). */
|
|
165
180
|
onSelectedPathChange?: (path: string | null) => void;
|
|
181
|
+
/** Optional observer for structured data-port failures. VaultPane still owns
|
|
182
|
+
* the visible error state and retry behavior when this is omitted. */
|
|
183
|
+
onOperationError?: (failure: VaultOperationFailure) => void;
|
|
166
184
|
/** Optional rich/source codec. Defaults to identity passthrough. */
|
|
167
185
|
codec?: VaultMarkdownCodec;
|
|
168
186
|
className?: string;
|
|
@@ -170,4 +188,4 @@ interface VaultPaneProps {
|
|
|
170
188
|
|
|
171
189
|
declare function VaultPane(props: VaultPaneProps): react.JSX.Element;
|
|
172
190
|
|
|
173
|
-
export { type VaultArtifactRenderProps as V, type VaultDataPort as a, type VaultDockRenderProps as b, type VaultDockToggle as c, type VaultEditorMode as d, type VaultFile as e, type VaultMarkdownCodec as f,
|
|
191
|
+
export { type VaultArtifactRenderProps as V, type VaultDataPort as a, type VaultDockRenderProps as b, type VaultDockToggle as c, type VaultEditorMode as d, type VaultFile as e, type VaultMarkdownCodec as f, type VaultOperation as g, type VaultOperationFailure as h, type VaultOperationPhase as i, VaultPane as j, type VaultPaneProps as k, type VaultRichParts as l, type VaultTreeNode as m, type VaultTreeRenderProps as n };
|
|
@@ -108,11 +108,20 @@ function ConfirmDialog({
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// src/vault/VaultPane.tsx
|
|
111
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
111
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
112
112
|
var IDENTITY_CODEC = {
|
|
113
113
|
parse: (raw) => raw,
|
|
114
114
|
serialize: (parts) => typeof parts === "string" ? parts : String(parts ?? "")
|
|
115
115
|
};
|
|
116
|
+
var LIST_CONTEXT = { operation: "list", phase: "operation" };
|
|
117
|
+
function operationMessage(error, fallback) {
|
|
118
|
+
return error instanceof Error && error.message ? error.message : fallback;
|
|
119
|
+
}
|
|
120
|
+
function treeFailureMessage(failure) {
|
|
121
|
+
if (failure.phase !== "post-mutation-refresh") return failure.message;
|
|
122
|
+
const completed = failure.operation === "create" ? "created" : "deleted";
|
|
123
|
+
return `The file was ${completed}, but the Vault couldn't refresh. ${failure.message}`;
|
|
124
|
+
}
|
|
116
125
|
function collectFilePaths(nodes, into) {
|
|
117
126
|
for (const node of nodes) {
|
|
118
127
|
if (node.type === "file") into.add(node.path);
|
|
@@ -217,6 +226,44 @@ function ReadErrorState({ message, onRetry }) {
|
|
|
217
226
|
)
|
|
218
227
|
] });
|
|
219
228
|
}
|
|
229
|
+
function TreeErrorState({ message, onRetry }) {
|
|
230
|
+
return /* @__PURE__ */ jsxs2("div", { role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [
|
|
231
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
232
|
+
/* @__PURE__ */ jsx2("h3", { className: "text-sm font-medium text-foreground", children: "Couldn't load the Vault" }),
|
|
233
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 max-w-xs text-xs text-muted-foreground", children: message })
|
|
234
|
+
] }),
|
|
235
|
+
/* @__PURE__ */ jsx2(
|
|
236
|
+
"button",
|
|
237
|
+
{
|
|
238
|
+
type: "button",
|
|
239
|
+
onClick: onRetry,
|
|
240
|
+
className: "inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60",
|
|
241
|
+
children: "Retry"
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
] });
|
|
245
|
+
}
|
|
246
|
+
function OperationErrorAlert({
|
|
247
|
+
message,
|
|
248
|
+
retryLabel,
|
|
249
|
+
onRetry,
|
|
250
|
+
onDismiss
|
|
251
|
+
}) {
|
|
252
|
+
return /* @__PURE__ */ jsxs2(
|
|
253
|
+
"div",
|
|
254
|
+
{
|
|
255
|
+
role: "alert",
|
|
256
|
+
className: "flex shrink-0 items-center justify-between gap-3 border-b border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
257
|
+
children: [
|
|
258
|
+
/* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1", children: message }),
|
|
259
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-3", children: [
|
|
260
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": retryLabel, onClick: onRetry, className: "font-medium underline-offset-2 hover:underline", children: "Retry" }),
|
|
261
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: onDismiss, className: "underline-offset-2 hover:underline", children: "Dismiss" })
|
|
262
|
+
] })
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
}
|
|
220
267
|
function VaultPane(props) {
|
|
221
268
|
const {
|
|
222
269
|
port,
|
|
@@ -226,6 +273,7 @@ function VaultPane(props) {
|
|
|
226
273
|
canWrite = true,
|
|
227
274
|
selectedPath: controlledPath,
|
|
228
275
|
onSelectedPathChange,
|
|
276
|
+
onOperationError,
|
|
229
277
|
codec,
|
|
230
278
|
className,
|
|
231
279
|
dockToggle,
|
|
@@ -241,6 +289,8 @@ function VaultPane(props) {
|
|
|
241
289
|
const dockToggleCfg = dockToggle ? dockToggle : { label: "Discuss", disabledWhenDirty: true };
|
|
242
290
|
const [tree, setTree] = useState([]);
|
|
243
291
|
const [treeLoading, setTreeLoading] = useState(true);
|
|
292
|
+
const [treeLoaded, setTreeLoaded] = useState(false);
|
|
293
|
+
const [treeError, setTreeError] = useState(null);
|
|
244
294
|
const [internalPath, setInternalPath] = useState(null);
|
|
245
295
|
const selectedPath = controlled ? controlledPath ?? null : internalPath;
|
|
246
296
|
const [selectedFile, setSelectedFile] = useState(null);
|
|
@@ -248,6 +298,7 @@ function VaultPane(props) {
|
|
|
248
298
|
const [readError, setReadError] = useState(null);
|
|
249
299
|
const [reloadNonce, setReloadNonce] = useState(0);
|
|
250
300
|
const [saving, setSaving] = useState(false);
|
|
301
|
+
const [saveError, setSaveError] = useState(null);
|
|
251
302
|
const [editorMode, setEditorMode] = useState("rich");
|
|
252
303
|
const [richDraft, setRichDraft] = useState("");
|
|
253
304
|
const [sourceDraft, setSourceDraft] = useState("");
|
|
@@ -255,13 +306,17 @@ function VaultPane(props) {
|
|
|
255
306
|
const [createOpen, setCreateOpen] = useState(false);
|
|
256
307
|
const [newPath, setNewPath] = useState("");
|
|
257
308
|
const [creating, setCreating] = useState(false);
|
|
309
|
+
const [createError, setCreateError] = useState(null);
|
|
258
310
|
const [deleteOpen, setDeleteOpen] = useState(false);
|
|
259
311
|
const [deleting, setDeleting] = useState(false);
|
|
312
|
+
const [deleteError, setDeleteError] = useState(null);
|
|
260
313
|
const [dockOpen, setDockOpen] = useState(false);
|
|
261
314
|
const [pendingNav, setPendingNav] = useState(null);
|
|
262
315
|
const [query, setQuery] = useState("");
|
|
263
316
|
const savedContentRef = useRef2("");
|
|
264
317
|
const loadedPathRef = useRef2(null);
|
|
318
|
+
const onOperationErrorRef = useRef2(onOperationError);
|
|
319
|
+
onOperationErrorRef.current = onOperationError;
|
|
265
320
|
const filePaths = useMemo(() => collectFilePaths(tree, /* @__PURE__ */ new Set()), [tree]);
|
|
266
321
|
const resolvedSelectedPath = useMemo(
|
|
267
322
|
() => selectedPath ? resolveFilePath(selectedPath, filePaths) : null,
|
|
@@ -283,17 +338,56 @@ function VaultPane(props) {
|
|
|
283
338
|
},
|
|
284
339
|
[controlled, onSelectedPathChange]
|
|
285
340
|
);
|
|
286
|
-
const
|
|
341
|
+
const reportFailure = useCallback((operation, phase, error, fallback, path) => {
|
|
342
|
+
const failure = {
|
|
343
|
+
operation,
|
|
344
|
+
phase,
|
|
345
|
+
path,
|
|
346
|
+
message: operationMessage(error, fallback),
|
|
347
|
+
cause: error
|
|
348
|
+
};
|
|
349
|
+
try {
|
|
350
|
+
onOperationErrorRef.current?.(failure);
|
|
351
|
+
} catch (callbackError) {
|
|
352
|
+
console.error("Vault onOperationError callback failed:", callbackError);
|
|
353
|
+
}
|
|
354
|
+
return failure;
|
|
355
|
+
}, []);
|
|
356
|
+
const refresh = useCallback(async (context = LIST_CONTEXT) => {
|
|
287
357
|
setTreeLoading(true);
|
|
358
|
+
setTreeError(null);
|
|
288
359
|
try {
|
|
289
360
|
setTree(await port.listTree());
|
|
361
|
+
setTreeLoaded(true);
|
|
362
|
+
return true;
|
|
363
|
+
} catch (error) {
|
|
364
|
+
const failure = reportFailure(
|
|
365
|
+
context.operation,
|
|
366
|
+
context.phase,
|
|
367
|
+
error,
|
|
368
|
+
"Failed to load the Vault",
|
|
369
|
+
context.path
|
|
370
|
+
);
|
|
371
|
+
setTreeError({ failure, context });
|
|
372
|
+
return false;
|
|
290
373
|
} finally {
|
|
291
374
|
setTreeLoading(false);
|
|
292
375
|
}
|
|
376
|
+
}, [port, reportFailure]);
|
|
377
|
+
useEffect2(() => {
|
|
378
|
+
setTree([]);
|
|
379
|
+
setTreeLoaded(false);
|
|
380
|
+
setTreeError(null);
|
|
293
381
|
}, [port]);
|
|
294
382
|
useEffect2(() => {
|
|
295
383
|
void refresh();
|
|
296
384
|
}, [refresh, refreshKey]);
|
|
385
|
+
const retryTree = useCallback(async () => {
|
|
386
|
+
if (!treeError) return;
|
|
387
|
+
const { context } = treeError;
|
|
388
|
+
const recovered = await refresh(context);
|
|
389
|
+
if (recovered && context.selectAfterRecovery) commitPath(context.selectAfterRecovery);
|
|
390
|
+
}, [treeError, refresh, commitPath]);
|
|
297
391
|
useEffect2(() => {
|
|
298
392
|
if (!selectedPath) {
|
|
299
393
|
setSelectedFile(null);
|
|
@@ -302,7 +396,7 @@ function VaultPane(props) {
|
|
|
302
396
|
loadedPathRef.current = null;
|
|
303
397
|
return;
|
|
304
398
|
}
|
|
305
|
-
if (treeLoading) return;
|
|
399
|
+
if (treeLoading || !treeLoaded) return;
|
|
306
400
|
if (!resolvedSelectedPath) {
|
|
307
401
|
commitPath(null);
|
|
308
402
|
setSelectedFile(null);
|
|
@@ -322,8 +416,9 @@ function VaultPane(props) {
|
|
|
322
416
|
if (!cancelled) setSelectedFile(file);
|
|
323
417
|
} catch (err) {
|
|
324
418
|
if (!cancelled) {
|
|
419
|
+
const failure = reportFailure("read", "operation", err, "Failed to read file", path);
|
|
325
420
|
setSelectedFile(null);
|
|
326
|
-
setReadError(
|
|
421
|
+
setReadError(failure.message);
|
|
327
422
|
}
|
|
328
423
|
} finally {
|
|
329
424
|
if (!cancelled) setFileLoading(false);
|
|
@@ -332,7 +427,7 @@ function VaultPane(props) {
|
|
|
332
427
|
return () => {
|
|
333
428
|
cancelled = true;
|
|
334
429
|
};
|
|
335
|
-
}, [port, selectedPath, resolvedSelectedPath, treeLoading, refreshKey, reloadNonce, commitPath]);
|
|
430
|
+
}, [port, selectedPath, resolvedSelectedPath, treeLoading, treeLoaded, refreshKey, reloadNonce, commitPath, reportFailure]);
|
|
336
431
|
useEffect2(() => {
|
|
337
432
|
if (!selectedFile) {
|
|
338
433
|
loadedPathRef.current = null;
|
|
@@ -341,6 +436,7 @@ function VaultPane(props) {
|
|
|
341
436
|
setSourceDraft("");
|
|
342
437
|
setEditorMode("rich");
|
|
343
438
|
setIsDirty(false);
|
|
439
|
+
setSaveError(null);
|
|
344
440
|
return;
|
|
345
441
|
}
|
|
346
442
|
const pathChanged = loadedPathRef.current !== selectedFile.path;
|
|
@@ -350,6 +446,7 @@ function VaultPane(props) {
|
|
|
350
446
|
setSourceDraft(selectedFile.content);
|
|
351
447
|
if (pathChanged) setEditorMode("rich");
|
|
352
448
|
setIsDirty(false);
|
|
449
|
+
setSaveError(null);
|
|
353
450
|
setDockOpen(false);
|
|
354
451
|
}, [selectedFile, activeCodec]);
|
|
355
452
|
const guardedOpen = useCallback(
|
|
@@ -422,6 +519,7 @@ function VaultPane(props) {
|
|
|
422
519
|
if (!selectedFile) return;
|
|
423
520
|
const content = editorMode === "source" ? sourceDraft : activeCodec.serialize(richDraft);
|
|
424
521
|
setSaving(true);
|
|
522
|
+
setSaveError(null);
|
|
425
523
|
try {
|
|
426
524
|
await port.writeFile(selectedFile.path, content);
|
|
427
525
|
savedContentRef.current = content;
|
|
@@ -429,38 +527,75 @@ function VaultPane(props) {
|
|
|
429
527
|
setSourceDraft(content);
|
|
430
528
|
setRichDraft(activeCodec.parse(content));
|
|
431
529
|
setIsDirty(false);
|
|
530
|
+
} catch (error) {
|
|
531
|
+
setSaveError(reportFailure("save", "operation", error, "Failed to save file", selectedFile.path));
|
|
432
532
|
} finally {
|
|
433
533
|
setSaving(false);
|
|
434
534
|
}
|
|
435
|
-
}, [selectedFile, editorMode, sourceDraft, richDraft, activeCodec, port]);
|
|
535
|
+
}, [selectedFile, editorMode, sourceDraft, richDraft, activeCodec, port, reportFailure]);
|
|
436
536
|
const handleCreate = useCallback(async () => {
|
|
437
537
|
const trimmed = newPath.trim();
|
|
438
538
|
if (!trimmed) return;
|
|
439
539
|
setCreating(true);
|
|
540
|
+
setCreateError(null);
|
|
440
541
|
try {
|
|
441
542
|
const created = await port.createFile(trimmed);
|
|
442
543
|
setCreateOpen(false);
|
|
443
544
|
setNewPath("");
|
|
444
|
-
await refresh(
|
|
445
|
-
|
|
545
|
+
const refreshed = await refresh({
|
|
546
|
+
operation: "create",
|
|
547
|
+
phase: "post-mutation-refresh",
|
|
548
|
+
path: created,
|
|
549
|
+
selectAfterRecovery: created
|
|
550
|
+
});
|
|
551
|
+
if (refreshed) commitPath(created);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
setCreateError(reportFailure("create", "operation", error, "Failed to create file", trimmed));
|
|
446
554
|
} finally {
|
|
447
555
|
setCreating(false);
|
|
448
556
|
}
|
|
449
|
-
}, [newPath, port, refresh, commitPath]);
|
|
557
|
+
}, [newPath, port, refresh, commitPath, reportFailure]);
|
|
450
558
|
const handleDelete = useCallback(async () => {
|
|
451
559
|
if (!selectedFile) return;
|
|
560
|
+
const path = selectedFile.path;
|
|
452
561
|
setDeleting(true);
|
|
562
|
+
setDeleteError(null);
|
|
453
563
|
try {
|
|
454
|
-
await port.deleteFile(
|
|
564
|
+
await port.deleteFile(path);
|
|
455
565
|
setDeleteOpen(false);
|
|
456
566
|
setIsDirty(false);
|
|
457
567
|
commitPath(null);
|
|
458
568
|
setSelectedFile(null);
|
|
459
|
-
await refresh();
|
|
569
|
+
await refresh({ operation: "delete", phase: "post-mutation-refresh", path });
|
|
570
|
+
} catch (error) {
|
|
571
|
+
setDeleteError(reportFailure("delete", "operation", error, "Failed to delete file", path));
|
|
460
572
|
} finally {
|
|
461
573
|
setDeleting(false);
|
|
462
574
|
}
|
|
463
|
-
}, [selectedFile, port, refresh, commitPath]);
|
|
575
|
+
}, [selectedFile, port, refresh, commitPath, reportFailure]);
|
|
576
|
+
let treeContent;
|
|
577
|
+
if (treeLoading || !treeLoaded && !treeError) {
|
|
578
|
+
treeContent = /* @__PURE__ */ jsx2(TreeSkeleton, {});
|
|
579
|
+
} else if (!treeLoaded && treeError) {
|
|
580
|
+
treeContent = /* @__PURE__ */ jsx2(TreeErrorState, { message: treeFailureMessage(treeError.failure), onRetry: () => void retryTree() });
|
|
581
|
+
} else {
|
|
582
|
+
treeContent = /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
583
|
+
treeError && /* @__PURE__ */ jsx2(
|
|
584
|
+
OperationErrorAlert,
|
|
585
|
+
{
|
|
586
|
+
message: treeFailureMessage(treeError.failure),
|
|
587
|
+
retryLabel: "Retry vault refresh",
|
|
588
|
+
onRetry: () => void retryTree(),
|
|
589
|
+
onDismiss: () => setTreeError(null)
|
|
590
|
+
}
|
|
591
|
+
),
|
|
592
|
+
renderTree({
|
|
593
|
+
root: visibleRoot,
|
|
594
|
+
selectedPath: resolvedSelectedPath ?? void 0,
|
|
595
|
+
onSelect: handleTreeSelect
|
|
596
|
+
})
|
|
597
|
+
] });
|
|
598
|
+
}
|
|
464
599
|
return /* @__PURE__ */ jsx2(EditorErrorBoundary, { onReset: () => {
|
|
465
600
|
commitPath(null);
|
|
466
601
|
setSelectedFile(null);
|
|
@@ -495,7 +630,10 @@ function VaultPane(props) {
|
|
|
495
630
|
{
|
|
496
631
|
type: "button",
|
|
497
632
|
"aria-label": "New vault file",
|
|
498
|
-
onClick: () =>
|
|
633
|
+
onClick: () => {
|
|
634
|
+
setCreateError(null);
|
|
635
|
+
setCreateOpen(true);
|
|
636
|
+
},
|
|
499
637
|
className: "inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60",
|
|
500
638
|
children: "+"
|
|
501
639
|
}
|
|
@@ -510,11 +648,7 @@ function VaultPane(props) {
|
|
|
510
648
|
const path = treeClickPath(event);
|
|
511
649
|
if (path) handleTreeSelect(path);
|
|
512
650
|
},
|
|
513
|
-
children:
|
|
514
|
-
root: visibleRoot,
|
|
515
|
-
selectedPath: resolvedSelectedPath ?? void 0,
|
|
516
|
-
onSelect: handleTreeSelect
|
|
517
|
-
})
|
|
651
|
+
children: treeContent
|
|
518
652
|
}
|
|
519
653
|
)
|
|
520
654
|
] }),
|
|
@@ -576,13 +710,25 @@ function VaultPane(props) {
|
|
|
576
710
|
type: "button",
|
|
577
711
|
"aria-label": "Delete this file",
|
|
578
712
|
title: "Delete file",
|
|
579
|
-
onClick: () =>
|
|
713
|
+
onClick: () => {
|
|
714
|
+
setDeleteError(null);
|
|
715
|
+
setDeleteOpen(true);
|
|
716
|
+
},
|
|
580
717
|
className: "inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive",
|
|
581
718
|
children: /* @__PURE__ */ jsx2(Trash2, { className: "h-4 w-4" })
|
|
582
719
|
}
|
|
583
720
|
)
|
|
584
721
|
] })
|
|
585
722
|
] }),
|
|
723
|
+
selectedFile && saveError && /* @__PURE__ */ jsx2(
|
|
724
|
+
OperationErrorAlert,
|
|
725
|
+
{
|
|
726
|
+
message: saveError.message,
|
|
727
|
+
retryLabel: "Retry save",
|
|
728
|
+
onRetry: () => void saveCurrent(),
|
|
729
|
+
onDismiss: () => setSaveError(null)
|
|
730
|
+
}
|
|
731
|
+
),
|
|
586
732
|
/* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-hidden", children: fileLoading ? /* @__PURE__ */ jsx2(EditorSkeleton, {}) : readError ? /* @__PURE__ */ jsx2(ReadErrorState, { message: readError, onRetry: () => setReloadNonce((n) => n + 1) }) : selectedFile && canWrite && isMarkdownCapable && editorMode === "source" ? /* @__PURE__ */ jsx2(
|
|
587
733
|
SourceEditor,
|
|
588
734
|
{
|
|
@@ -622,18 +768,22 @@ function VaultPane(props) {
|
|
|
622
768
|
onCancel: () => {
|
|
623
769
|
setCreateOpen(false);
|
|
624
770
|
setNewPath("");
|
|
771
|
+
setCreateError(null);
|
|
625
772
|
},
|
|
626
|
-
children: /* @__PURE__ */
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
773
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
|
|
774
|
+
/* @__PURE__ */ jsx2(
|
|
775
|
+
"input",
|
|
776
|
+
{
|
|
777
|
+
value: newPath,
|
|
778
|
+
autoFocus: true,
|
|
779
|
+
onChange: (e) => setNewPath(e.target.value),
|
|
780
|
+
placeholder: "e.g. playbooks/new-strategy.md",
|
|
781
|
+
"aria-label": "New file path",
|
|
782
|
+
className: "h-9 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-primary/60"
|
|
783
|
+
}
|
|
784
|
+
),
|
|
785
|
+
createError && /* @__PURE__ */ jsx2("p", { role: "alert", className: "text-xs text-destructive", children: createError.message })
|
|
786
|
+
] })
|
|
637
787
|
}
|
|
638
788
|
),
|
|
639
789
|
/* @__PURE__ */ jsx2(
|
|
@@ -646,7 +796,11 @@ function VaultPane(props) {
|
|
|
646
796
|
confirmDisabled: deleting,
|
|
647
797
|
destructive: true,
|
|
648
798
|
onConfirm: () => void handleDelete(),
|
|
649
|
-
onCancel: () =>
|
|
799
|
+
onCancel: () => {
|
|
800
|
+
setDeleteOpen(false);
|
|
801
|
+
setDeleteError(null);
|
|
802
|
+
},
|
|
803
|
+
children: deleteError && /* @__PURE__ */ jsx2("p", { role: "alert", className: "text-xs text-destructive", children: deleteError.message })
|
|
650
804
|
}
|
|
651
805
|
),
|
|
652
806
|
/* @__PURE__ */ jsx2(
|
|
@@ -705,4 +859,4 @@ export {
|
|
|
705
859
|
ConfirmDialog,
|
|
706
860
|
VaultPane
|
|
707
861
|
};
|
|
708
|
-
//# sourceMappingURL=chunk-
|
|
862
|
+
//# sourceMappingURL=chunk-FVJP2RTC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vault/VaultPane.tsx","../src/vault/ConfirmDialog.tsx"],"sourcesContent":["/**\n * The shared 3-pane vault: tree | artifact viewer | optional agent dock. This is\n * pure shell MECHANISM — selection, the dirty-guard + pending-nav state machine,\n * rich/source editor modes, create/delete/refresh, skeletons, an error boundary,\n * and an empty state. It renders NO file tree and NO artifact viewer of its own:\n * those arrive through the `renderTree` / `renderArtifact` / `renderDock` seams,\n * so a product wires sandbox-ui's RichFileTree + FileArtifactPane in ~10 lines.\n *\n * Data flows exclusively through `port` (a `VaultDataPort`). The pane never\n * imports a fetch client, a router, a toast system, or a markdown library — the\n * optional `codec` seam supplies rich/source parsing (identity passthrough by\n * default). Chrome uses the shared theme tokens (bg-card, border-border, …).\n */\n\nimport {\n Component,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ErrorInfo,\n type MouseEvent,\n type ReactNode,\n} from 'react'\nimport { Download, Trash2 } from 'lucide-react'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport type {\n VaultEditorMode,\n VaultFile,\n VaultMarkdownCodec,\n VaultOperation,\n VaultOperationFailure,\n VaultOperationPhase,\n VaultPaneProps,\n VaultRichParts,\n VaultTreeNode,\n} from './contracts'\n\nconst IDENTITY_CODEC: VaultMarkdownCodec = {\n parse: (raw) => raw,\n serialize: (parts) => (typeof parts === 'string' ? parts : String(parts ?? '')),\n}\n\ntype PendingNav = { type: 'open'; path: string } | { type: 'close' } | null\n\ninterface TreeRefreshContext {\n operation: Extract<VaultOperation, 'list' | 'create' | 'delete'>\n phase: VaultOperationPhase\n path?: string\n selectAfterRecovery?: string\n}\n\ninterface TreeFailureState {\n failure: VaultOperationFailure\n context: TreeRefreshContext\n}\n\nconst LIST_CONTEXT: TreeRefreshContext = { operation: 'list', phase: 'operation' }\n\nfunction operationMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback\n}\n\nfunction treeFailureMessage(failure: VaultOperationFailure): string {\n if (failure.phase !== 'post-mutation-refresh') return failure.message\n const completed = failure.operation === 'create' ? 'created' : 'deleted'\n return `The file was ${completed}, but the Vault couldn't refresh. ${failure.message}`\n}\n\nfunction collectFilePaths(nodes: VaultTreeNode[], into: Set<string>): Set<string> {\n for (const node of nodes) {\n if (node.type === 'file') into.add(node.path)\n if (node.children) collectFilePaths(node.children, into)\n }\n return into\n}\n\nfunction resolveFilePath(rawPath: string, filePaths: Set<string>): string | null {\n if (filePaths.has(rawPath)) return rawPath\n const path = rawPath.replace(/^\\/+|\\/+$/g, '')\n return filePaths.has(path) ? path : null\n}\n\nfunction treeClickPath(event: MouseEvent<HTMLElement>): string | null {\n const path = event.nativeEvent.composedPath?.() ?? []\n for (const item of path) {\n if (!(item instanceof HTMLElement)) continue\n if (item.dataset.type !== 'item') continue\n if (item.dataset.itemType !== 'file') return null\n return item.dataset.itemPath ?? null\n }\n\n const target = event.target instanceof HTMLElement\n ? event.target.closest('[data-type=\"item\"]')\n : null\n if (!(target instanceof HTMLElement)) return null\n if (target.dataset.itemType !== 'file') return null\n return target.dataset.itemPath ?? null\n}\n\n// Case-insensitive name filter over the tree: files survive when their name\n// matches; a directory survives whole (with all its children) when its own name\n// matches, otherwise only when some descendant survives.\nfunction filterNodes(nodes: VaultTreeNode[], q: string): VaultTreeNode[] {\n const out: VaultTreeNode[] = []\n for (const node of nodes) {\n if (node.type === 'file') {\n if (node.name.toLowerCase().includes(q)) out.push(node)\n } else if (node.name.toLowerCase().includes(q)) {\n out.push(node)\n } else {\n const children = filterNodes(node.children ?? [], q)\n if (children.length > 0) out.push({ ...node, children })\n }\n }\n return out\n}\n\nclass EditorErrorBoundary extends Component<{ children: ReactNode; onReset?: () => void }, { error: unknown }> {\n state: { error: unknown } = { error: null }\n static getDerivedStateFromError(error: unknown) {\n return { error }\n }\n componentDidCatch(error: unknown, info: ErrorInfo) {\n console.error('Vault crashed:', error, info)\n }\n render() {\n if (this.state.error) {\n const msg = this.state.error instanceof Error\n ? this.state.error.message\n : typeof this.state.error === 'string'\n ? this.state.error\n : 'Something went wrong loading the vault'\n return (\n <div className=\"flex h-full flex-1 flex-col items-center justify-center p-8 text-center\">\n <h3 className=\"mb-1 text-sm font-medium text-foreground\">Vault failed to load</h3>\n <p className=\"mb-4 max-w-xs text-xs text-muted-foreground\">{String(msg)}</p>\n <button\n type=\"button\"\n onClick={() => { this.setState({ error: null }); this.props.onReset?.() }}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n Try again\n </button>\n </div>\n )\n }\n return this.props.children\n }\n}\n\nfunction TreeSkeleton() {\n return (\n <div className=\"space-y-2 p-4\" aria-hidden=\"true\">\n {[32, 48, 40, 52].map((w, i) => (\n <div key={i} className=\"h-4 animate-pulse rounded bg-muted\" style={{ width: `${w * 4}px` }} />\n ))}\n </div>\n )\n}\n\nfunction EditorSkeleton() {\n return (\n <div className=\"space-y-3 p-8\" aria-hidden=\"true\">\n <div className=\"h-5 w-1/2 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-full animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-3/4 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-2/3 animate-pulse rounded bg-muted\" />\n </div>\n )\n}\n\nfunction EmptyState() {\n return (\n <div className=\"flex h-full flex-col items-center justify-center p-8 text-center\">\n <h3 className=\"text-sm font-medium text-foreground\">Open a vault document</h3>\n <p className=\"mt-1 max-w-xs text-xs text-muted-foreground\">\n Select a file from the directory, or create a new one.\n </p>\n </div>\n )\n}\n\nfunction ReadErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-8 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't open this file</h3>\n <p className=\"mt-1 max-w-md text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction TreeErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div role=\"alert\" className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't load the Vault</h3>\n <p className=\"mt-1 max-w-xs text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction OperationErrorAlert({\n message,\n retryLabel,\n onRetry,\n onDismiss,\n}: {\n message: string\n retryLabel: string\n onRetry: () => void\n onDismiss: () => void\n}) {\n return (\n <div\n role=\"alert\"\n className=\"flex shrink-0 items-center justify-between gap-3 border-b border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n <span className=\"min-w-0 flex-1\">{message}</span>\n <div className=\"flex shrink-0 items-center gap-3\">\n <button type=\"button\" aria-label={retryLabel} onClick={onRetry} className=\"font-medium underline-offset-2 hover:underline\">\n Retry\n </button>\n <button type=\"button\" onClick={onDismiss} className=\"underline-offset-2 hover:underline\">\n Dismiss\n </button>\n </div>\n </div>\n )\n}\n\nexport function VaultPane(props: VaultPaneProps) {\n const {\n port,\n renderTree,\n renderArtifact,\n renderDock,\n canWrite = true,\n selectedPath: controlledPath,\n onSelectedPathChange,\n onOperationError,\n codec,\n className,\n dockToggle,\n refreshKey,\n headerActions,\n onDownloadFile,\n pathBarClassName,\n } = props\n\n const activeCodec = codec ?? IDENTITY_CODEC\n const controlled = controlledPath !== undefined\n const isMarkdownCapable = codec !== undefined\n // `false` → a persistent dock (no toggle, always open with the selected file).\n const persistentDock = dockToggle === false\n const dockToggleCfg = dockToggle ? dockToggle : { label: 'Discuss', disabledWhenDirty: true }\n\n const [tree, setTree] = useState<VaultTreeNode[]>([])\n const [treeLoading, setTreeLoading] = useState(true)\n const [treeLoaded, setTreeLoaded] = useState(false)\n const [treeError, setTreeError] = useState<TreeFailureState | null>(null)\n const [internalPath, setInternalPath] = useState<string | null>(null)\n const selectedPath = controlled ? (controlledPath ?? null) : internalPath\n\n const [selectedFile, setSelectedFile] = useState<VaultFile | null>(null)\n const [fileLoading, setFileLoading] = useState(false)\n const [readError, setReadError] = useState<string | null>(null)\n const [reloadNonce, setReloadNonce] = useState(0)\n const [saving, setSaving] = useState(false)\n const [saveError, setSaveError] = useState<VaultOperationFailure | null>(null)\n\n const [editorMode, setEditorMode] = useState<VaultEditorMode>('rich')\n const [richDraft, setRichDraft] = useState<VaultRichParts>('')\n const [sourceDraft, setSourceDraft] = useState('')\n const [isDirty, setIsDirty] = useState(false)\n\n const [createOpen, setCreateOpen] = useState(false)\n const [newPath, setNewPath] = useState('')\n const [creating, setCreating] = useState(false)\n const [createError, setCreateError] = useState<VaultOperationFailure | null>(null)\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [deleteError, setDeleteError] = useState<VaultOperationFailure | null>(null)\n const [dockOpen, setDockOpen] = useState(false)\n const [pendingNav, setPendingNav] = useState<PendingNav>(null)\n const [query, setQuery] = useState('')\n\n const savedContentRef = useRef('')\n const loadedPathRef = useRef<string | null>(null)\n const onOperationErrorRef = useRef(onOperationError)\n onOperationErrorRef.current = onOperationError\n\n const filePaths = useMemo(() => collectFilePaths(tree, new Set<string>()), [tree])\n const resolvedSelectedPath = useMemo(\n () => selectedPath ? resolveFilePath(selectedPath, filePaths) : null,\n [selectedPath, filePaths],\n )\n const treeRoot = useMemo<VaultTreeNode>(\n () => ({ name: 'Vault', path: '', type: 'directory', children: tree }),\n [tree],\n )\n const visibleRoot = useMemo<VaultTreeNode>(() => {\n const q = query.trim().toLowerCase()\n if (!q) return treeRoot\n return { ...treeRoot, children: filterNodes(tree, q) }\n }, [treeRoot, tree, query])\n\n const commitPath = useCallback(\n (next: string | null) => {\n if (!controlled) setInternalPath(next)\n onSelectedPathChange?.(next)\n },\n [controlled, onSelectedPathChange],\n )\n\n const reportFailure = useCallback((\n operation: VaultOperation,\n phase: VaultOperationPhase,\n error: unknown,\n fallback: string,\n path?: string,\n ): VaultOperationFailure => {\n const failure: VaultOperationFailure = {\n operation,\n phase,\n path,\n message: operationMessage(error, fallback),\n cause: error,\n }\n try {\n onOperationErrorRef.current?.(failure)\n } catch (callbackError) {\n console.error('Vault onOperationError callback failed:', callbackError)\n }\n return failure\n }, [])\n\n const refresh = useCallback(async (context: TreeRefreshContext = LIST_CONTEXT): Promise<boolean> => {\n setTreeLoading(true)\n setTreeError(null)\n try {\n setTree(await port.listTree())\n setTreeLoaded(true)\n return true\n } catch (error) {\n const failure = reportFailure(\n context.operation,\n context.phase,\n error,\n 'Failed to load the Vault',\n context.path,\n )\n setTreeError({ failure, context })\n return false\n } finally {\n setTreeLoading(false)\n }\n }, [port, reportFailure])\n\n useEffect(() => {\n setTree([])\n setTreeLoaded(false)\n setTreeError(null)\n }, [port])\n\n useEffect(() => {\n void refresh()\n }, [refresh, refreshKey])\n\n const retryTree = useCallback(async () => {\n if (!treeError) return\n const { context } = treeError\n const recovered = await refresh(context)\n if (recovered && context.selectAfterRecovery) commitPath(context.selectAfterRecovery)\n }, [treeError, refresh, commitPath])\n\n useEffect(() => {\n if (!selectedPath) {\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n if (treeLoading || !treeLoaded) return\n if (!resolvedSelectedPath) {\n commitPath(null)\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n let cancelled = false\n const path = resolvedSelectedPath\n if (path !== selectedPath) commitPath(path)\n setFileLoading(true)\n setReadError(null)\n void (async () => {\n try {\n const file = await port.readFile(path)\n if (!cancelled) setSelectedFile(file)\n } catch (err) {\n // Surface read failures instead of making them indistinguishable from\n // the intentionally empty \"no file selected\" state.\n if (!cancelled) {\n const failure = reportFailure('read', 'operation', err, 'Failed to read file', path)\n setSelectedFile(null)\n setReadError(failure.message)\n }\n } finally {\n if (!cancelled) setFileLoading(false)\n }\n })()\n return () => {\n cancelled = true\n }\n }, [port, selectedPath, resolvedSelectedPath, treeLoading, treeLoaded, refreshKey, reloadNonce, commitPath, reportFailure])\n\n useEffect(() => {\n if (!selectedFile) {\n loadedPathRef.current = null\n savedContentRef.current = ''\n setRichDraft('')\n setSourceDraft('')\n setEditorMode('rich')\n setIsDirty(false)\n setSaveError(null)\n return\n }\n const pathChanged = loadedPathRef.current !== selectedFile.path\n loadedPathRef.current = selectedFile.path\n savedContentRef.current = selectedFile.content\n setRichDraft(activeCodec.parse(selectedFile.content))\n setSourceDraft(selectedFile.content)\n if (pathChanged) setEditorMode('rich')\n setIsDirty(false)\n setSaveError(null)\n setDockOpen(false)\n }, [selectedFile, activeCodec])\n\n const guardedOpen = useCallback(\n (path: string) => {\n if (path === selectedPath) return\n if (isDirty) {\n setPendingNav({ type: 'open', path })\n return\n }\n commitPath(path)\n },\n [isDirty, selectedPath, commitPath],\n )\n\n // Some tree models keep their original selection callback while resetting\n // paths internally. Keep the callable stable, but have it execute the latest\n // file-path validation and dirty-guard logic.\n const selectFileRef = useRef<(path: string) => void>(() => {})\n selectFileRef.current = (rawPath: string) => {\n const path = resolveFilePath(rawPath, filePaths)\n if (path) {\n guardedOpen(path)\n return\n }\n }\n const handleTreeSelect = useCallback((path: string) => selectFileRef.current(path), [])\n\n const guardedClose = useCallback(() => {\n if (isDirty) {\n setPendingNav({ type: 'close' })\n return\n }\n commitPath(null)\n setSelectedFile(null)\n }, [isDirty, commitPath])\n\n const confirmDiscard = useCallback(() => {\n const nav = pendingNav\n setPendingNav(null)\n setIsDirty(false)\n if (!nav) return\n if (nav.type === 'open') {\n commitPath(nav.path)\n } else {\n commitPath(null)\n setSelectedFile(null)\n }\n }, [pendingNav, commitPath])\n\n const showRichMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'rich') return mode\n setRichDraft(activeCodec.parse(sourceDraft))\n setIsDirty(sourceDraft !== savedContentRef.current)\n return 'rich'\n })\n }, [activeCodec, sourceDraft])\n\n const showSourceMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'source') return mode\n const content = isDirty ? activeCodec.serialize(richDraft) : savedContentRef.current\n setSourceDraft(content)\n setIsDirty(content !== savedContentRef.current)\n return 'source'\n })\n }, [activeCodec, isDirty, richDraft])\n\n const onSourceChange = useCallback((next: string) => {\n setSourceDraft(next)\n setIsDirty(next !== savedContentRef.current)\n }, [])\n\n const onRichChange = useCallback((next: VaultRichParts) => {\n setRichDraft(next)\n setIsDirty(activeCodec.serialize(next) !== savedContentRef.current)\n }, [activeCodec])\n\n const saveCurrent = useCallback(async () => {\n if (!selectedFile) return\n const content = editorMode === 'source' ? sourceDraft : activeCodec.serialize(richDraft)\n setSaving(true)\n setSaveError(null)\n try {\n await port.writeFile(selectedFile.path, content)\n savedContentRef.current = content\n setSelectedFile({ ...selectedFile, content })\n setSourceDraft(content)\n setRichDraft(activeCodec.parse(content))\n setIsDirty(false)\n } catch (error) {\n setSaveError(reportFailure('save', 'operation', error, 'Failed to save file', selectedFile.path))\n } finally {\n setSaving(false)\n }\n }, [selectedFile, editorMode, sourceDraft, richDraft, activeCodec, port, reportFailure])\n\n const handleCreate = useCallback(async () => {\n const trimmed = newPath.trim()\n if (!trimmed) return\n setCreating(true)\n setCreateError(null)\n try {\n const created = await port.createFile(trimmed)\n setCreateOpen(false)\n setNewPath('')\n const refreshed = await refresh({\n operation: 'create',\n phase: 'post-mutation-refresh',\n path: created,\n selectAfterRecovery: created,\n })\n if (refreshed) commitPath(created)\n } catch (error) {\n setCreateError(reportFailure('create', 'operation', error, 'Failed to create file', trimmed))\n } finally {\n setCreating(false)\n }\n }, [newPath, port, refresh, commitPath, reportFailure])\n\n const handleDelete = useCallback(async () => {\n if (!selectedFile) return\n const path = selectedFile.path\n setDeleting(true)\n setDeleteError(null)\n try {\n await port.deleteFile(path)\n setDeleteOpen(false)\n setIsDirty(false)\n commitPath(null)\n setSelectedFile(null)\n await refresh({ operation: 'delete', phase: 'post-mutation-refresh', path })\n } catch (error) {\n setDeleteError(reportFailure('delete', 'operation', error, 'Failed to delete file', path))\n } finally {\n setDeleting(false)\n }\n }, [selectedFile, port, refresh, commitPath, reportFailure])\n\n let treeContent: ReactNode\n if (treeLoading || (!treeLoaded && !treeError)) {\n treeContent = <TreeSkeleton />\n } else if (!treeLoaded && treeError) {\n treeContent = <TreeErrorState message={treeFailureMessage(treeError.failure)} onRetry={() => void retryTree()} />\n } else {\n treeContent = (\n <>\n {treeError && (\n <OperationErrorAlert\n message={treeFailureMessage(treeError.failure)}\n retryLabel=\"Retry vault refresh\"\n onRetry={() => void retryTree()}\n onDismiss={() => setTreeError(null)}\n />\n )}\n {renderTree({\n root: visibleRoot,\n selectedPath: resolvedSelectedPath ?? undefined,\n onSelect: handleTreeSelect,\n })}\n </>\n )\n }\n\n return (\n <EditorErrorBoundary onReset={() => { commitPath(null); setSelectedFile(null) }}>\n <div className={`flex min-h-0 flex-1 overflow-hidden ${className ?? ''}`}>\n <div className=\"flex w-[23rem] min-w-[23rem] flex-col border-r border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <input\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search…\"\n aria-label=\"Search vault\"\n className=\"h-8 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-primary/60\"\n />\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {headerActions}\n <button\n type=\"button\"\n aria-label=\"Refresh vault\"\n onClick={() => void refresh()}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n ↻\n </button>\n {canWrite && (\n <button\n type=\"button\"\n aria-label=\"New vault file\"\n onClick={() => { setCreateError(null); setCreateOpen(true) }}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n +\n </button>\n )}\n </div>\n </div>\n <div\n className=\"flex-1 overflow-y-auto\"\n onClickCapture={(event) => {\n const path = treeClickPath(event)\n if (path) handleTreeSelect(path)\n }}\n >\n {treeContent}\n </div>\n </div>\n\n <div className=\"flex min-w-0 flex-1 flex-col overflow-hidden\">\n {selectedFile && (\n <div className={`flex shrink-0 items-center justify-between border-b border-border px-4 py-1.5 ${pathBarClassName ?? 'bg-card'}`}>\n <span data-vault-path className=\"truncate text-xs font-medium text-foreground\">{selectedFile.path}</span>\n <div className=\"flex items-center gap-1\">\n {canWrite && isMarkdownCapable && (\n <div className=\"mr-1 flex items-center gap-1\">\n <button\n type=\"button\"\n aria-label=\"Edit as rich text\"\n aria-pressed={editorMode === 'rich'}\n onClick={showRichMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'rich'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Rich\n </button>\n <button\n type=\"button\"\n aria-label=\"Edit as source\"\n aria-pressed={editorMode === 'source'}\n onClick={showSourceMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'source'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Source\n </button>\n </div>\n )}\n {renderDock && !persistentDock && (\n <button\n type=\"button\"\n aria-label={dockToggleCfg.label}\n aria-pressed={dockOpen}\n disabled={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty}\n title={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty ? 'Save your changes first' : (dockToggleCfg.title ?? dockToggleCfg.label)}\n onClick={() => setDockOpen((v) => !v)}\n className={`inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-40 ${\n dockOpen\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n {dockToggleCfg.label}\n </button>\n )}\n {onDownloadFile && (\n <button\n type=\"button\"\n aria-label=\"Download this file\"\n title=\"Download file\"\n onClick={() => onDownloadFile(selectedFile)}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n {canWrite && (\n <button\n type=\"button\"\n aria-label=\"Delete this file\"\n title=\"Delete file\"\n onClick={() => { setDeleteError(null); setDeleteOpen(true) }}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n )}\n {selectedFile && saveError && (\n <OperationErrorAlert\n message={saveError.message}\n retryLabel=\"Retry save\"\n onRetry={() => void saveCurrent()}\n onDismiss={() => setSaveError(null)}\n />\n )}\n <div className=\"flex-1 overflow-hidden\">\n {fileLoading ? (\n <EditorSkeleton />\n ) : readError ? (\n <ReadErrorState message={readError} onRetry={() => setReloadNonce((n) => n + 1)} />\n ) : selectedFile && canWrite && isMarkdownCapable && editorMode === 'source' ? (\n <SourceEditor\n path={selectedFile.path}\n content={sourceDraft}\n saving={saving}\n dirty={isDirty}\n onChange={onSourceChange}\n onSave={() => void saveCurrent()}\n />\n ) : selectedFile ? (\n renderArtifact({\n file: selectedFile,\n loading: false,\n mode: editorMode,\n canWrite,\n richDraft,\n dirty: isDirty,\n onRichChange,\n onSave: () => void saveCurrent(),\n })\n ) : (\n <EmptyState />\n )}\n </div>\n </div>\n\n {renderDock && selectedFile && renderDock({\n file: selectedFile,\n open: persistentDock ? true : dockOpen,\n onClose: persistentDock ? () => {} : () => setDockOpen(false),\n })}\n\n <ConfirmDialog\n open={createOpen}\n title=\"Create vault file\"\n description=\"Add a new document to this vault.\"\n confirmLabel={creating ? 'Creating…' : 'Create'}\n confirmDisabled={creating || !newPath.trim()}\n onConfirm={() => void handleCreate()}\n onCancel={() => { setCreateOpen(false); setNewPath(''); setCreateError(null) }}\n >\n <div className=\"space-y-2\">\n <input\n value={newPath}\n autoFocus\n onChange={(e) => setNewPath(e.target.value)}\n placeholder=\"e.g. playbooks/new-strategy.md\"\n aria-label=\"New file path\"\n className=\"h-9 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-primary/60\"\n />\n {createError && <p role=\"alert\" className=\"text-xs text-destructive\">{createError.message}</p>}\n </div>\n </ConfirmDialog>\n\n <ConfirmDialog\n open={deleteOpen}\n title=\"Delete file?\"\n description={`This permanently removes ${selectedFile?.path ?? 'this file'} from the vault.`}\n confirmLabel={deleting ? 'Deleting…' : 'Delete file'}\n confirmDisabled={deleting}\n destructive\n onConfirm={() => void handleDelete()}\n onCancel={() => { setDeleteOpen(false); setDeleteError(null) }}\n >\n {deleteError && <p role=\"alert\" className=\"text-xs text-destructive\">{deleteError.message}</p>}\n </ConfirmDialog>\n\n <ConfirmDialog\n open={pendingNav !== null}\n title=\"Discard unsaved changes?\"\n description=\"Your edits to this document haven't been saved. Continue and lose them?\"\n confirmLabel=\"Discard changes\"\n destructive\n onConfirm={confirmDiscard}\n onCancel={() => setPendingNav(null)}\n />\n </div>\n </EditorErrorBoundary>\n )\n}\n\nfunction SourceEditor({\n path,\n content,\n saving,\n dirty,\n onChange,\n onSave,\n}: {\n path: string\n content: string\n saving: boolean\n dirty: boolean\n onChange: (content: string) => void\n onSave: () => void\n}) {\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-2\">\n <p className=\"truncate font-mono text-[11px] text-muted-foreground\">{path}</p>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"rounded-full border border-border bg-background px-2.5 py-1 text-xs text-muted-foreground\">\n {dirty ? 'Unsaved changes' : 'Saved'}\n </span>\n <button\n type=\"button\"\n onClick={onSave}\n disabled={saving || !dirty}\n className=\"inline-flex h-7 items-center rounded-md bg-primary px-2 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {saving ? 'Saving…' : 'Save'}\n </button>\n </div>\n </div>\n <textarea\n value={content}\n onChange={(event) => onChange(event.target.value)}\n spellCheck={false}\n aria-label=\"Source editor\"\n className=\"min-h-0 flex-1 resize-none border-0 bg-background p-4 font-mono text-sm leading-6 text-foreground outline-none\"\n />\n </div>\n )\n}\n","/**\n * Self-contained confirm dialog — no dialog library. A focus-trapped modal with\n * Esc-to-cancel and Enter-to-confirm, used for create / delete / discard-unsaved\n * flows so the pane carries zero UI-kit dependency.\n */\n\nimport { useEffect, useRef, type ReactNode } from 'react'\n\nexport interface ConfirmDialogProps {\n open: boolean\n title: string\n description?: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n /** Styles the confirm button as a destructive action. */\n destructive?: boolean\n /** Disables the confirm button (e.g. while the action is in flight). */\n confirmDisabled?: boolean\n onConfirm: () => void\n onCancel: () => void\n /** Optional body (e.g. an input field for the create flow). */\n children?: ReactNode\n}\n\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n destructive = false,\n confirmDisabled = false,\n onConfirm,\n onCancel,\n children,\n}: ConfirmDialogProps) {\n const panelRef = useRef<HTMLDivElement>(null)\n const confirmRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n if (!open) return\n confirmRef.current?.focus()\n }, [open])\n\n if (!open) return null\n\n function onKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && !confirmDisabled) {\n event.preventDefault()\n onConfirm()\n return\n }\n if (event.key !== 'Tab') return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement as HTMLElement | null\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onMouseDown={(e) => { if (e.target === e.currentTarget) onCancel() }}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onKeyDown={onKeyDown}\n className=\"w-full max-w-md rounded-lg border border-border bg-card p-5 shadow-lg\"\n >\n <h2 className=\"text-sm font-semibold text-foreground\">{title}</h2>\n {description && <p className=\"mt-1.5 text-xs text-muted-foreground\">{description}</p>}\n {children && <div className=\"mt-3\">{children}</div>}\n <div className=\"mt-5 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex h-8 items-center rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n {cancelLabel}\n </button>\n <button\n ref={confirmRef}\n type=\"button\"\n onClick={onConfirm}\n disabled={confirmDisabled}\n className={`inline-flex h-8 items-center rounded-md px-3 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 ${\n destructive\n ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90'\n : 'bg-primary text-primary-foreground hover:bg-primary/90'\n }`}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","jsx","jsxs","useRef","useEffect"]}
|
package/dist/vault/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { V as VaultArtifactRenderProps, a as VaultDataPort, b as VaultDockRenderProps, c as VaultDockToggle, d as VaultEditorMode, e as VaultFile, f as VaultMarkdownCodec, g as
|
|
1
|
+
export { V as VaultArtifactRenderProps, a as VaultDataPort, b as VaultDockRenderProps, c as VaultDockToggle, d as VaultEditorMode, e as VaultFile, f as VaultMarkdownCodec, g as VaultOperation, h as VaultOperationFailure, i as VaultOperationPhase, j as VaultPane, k as VaultPaneProps, l as VaultRichParts, m as VaultTreeNode, n as VaultTreeRenderProps } from '../VaultPane-DrQ_tH6c.js';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
4
|
|
package/dist/vault/index.js
CHANGED
package/dist/vault/lazy.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
2
|
+
import { j as VaultPane } from '../VaultPane-DrQ_tH6c.js';
|
|
3
|
+
export { k as VaultPaneProps } from '../VaultPane-DrQ_tH6c.js';
|
|
4
4
|
|
|
5
5
|
declare const VaultPaneLazy: react.LazyExoticComponent<typeof VaultPane>;
|
|
6
6
|
|
package/dist/vault/lazy.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/vault/lazy.tsx
|
|
2
2
|
import { lazy } from "react";
|
|
3
3
|
var VaultPaneLazy = lazy(
|
|
4
|
-
() => import("../VaultPane-
|
|
4
|
+
() => import("../VaultPane-HFH734K6.js").then((m) => ({ default: m.VaultPane }))
|
|
5
5
|
);
|
|
6
6
|
export {
|
|
7
7
|
VaultPaneLazy
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.43.
|
|
3
|
+
"version": "0.43.21",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/vault/VaultPane.tsx","../src/vault/ConfirmDialog.tsx"],"sourcesContent":["/**\n * The shared 3-pane vault: tree | artifact viewer | optional agent dock. This is\n * pure shell MECHANISM — selection, the dirty-guard + pending-nav state machine,\n * rich/source editor modes, create/delete/refresh, skeletons, an error boundary,\n * and an empty state. It renders NO file tree and NO artifact viewer of its own:\n * those arrive through the `renderTree` / `renderArtifact` / `renderDock` seams,\n * so a product wires sandbox-ui's RichFileTree + FileArtifactPane in ~10 lines.\n *\n * Data flows exclusively through `port` (a `VaultDataPort`). The pane never\n * imports a fetch client, a router, a toast system, or a markdown library — the\n * optional `codec` seam supplies rich/source parsing (identity passthrough by\n * default). Chrome uses the shared theme tokens (bg-card, border-border, …).\n */\n\nimport {\n Component,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ErrorInfo,\n type MouseEvent,\n type ReactNode,\n} from 'react'\nimport { Download, Trash2 } from 'lucide-react'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport type {\n VaultEditorMode,\n VaultFile,\n VaultMarkdownCodec,\n VaultPaneProps,\n VaultRichParts,\n VaultTreeNode,\n} from './contracts'\n\nconst IDENTITY_CODEC: VaultMarkdownCodec = {\n parse: (raw) => raw,\n serialize: (parts) => (typeof parts === 'string' ? parts : String(parts ?? '')),\n}\n\ntype PendingNav = { type: 'open'; path: string } | { type: 'close' } | null\n\nfunction collectFilePaths(nodes: VaultTreeNode[], into: Set<string>): Set<string> {\n for (const node of nodes) {\n if (node.type === 'file') into.add(node.path)\n if (node.children) collectFilePaths(node.children, into)\n }\n return into\n}\n\nfunction resolveFilePath(rawPath: string, filePaths: Set<string>): string | null {\n if (filePaths.has(rawPath)) return rawPath\n const path = rawPath.replace(/^\\/+|\\/+$/g, '')\n return filePaths.has(path) ? path : null\n}\n\nfunction treeClickPath(event: MouseEvent<HTMLElement>): string | null {\n const path = event.nativeEvent.composedPath?.() ?? []\n for (const item of path) {\n if (!(item instanceof HTMLElement)) continue\n if (item.dataset.type !== 'item') continue\n if (item.dataset.itemType !== 'file') return null\n return item.dataset.itemPath ?? null\n }\n\n const target = event.target instanceof HTMLElement\n ? event.target.closest('[data-type=\"item\"]')\n : null\n if (!(target instanceof HTMLElement)) return null\n if (target.dataset.itemType !== 'file') return null\n return target.dataset.itemPath ?? null\n}\n\n// Case-insensitive name filter over the tree: files survive when their name\n// matches; a directory survives whole (with all its children) when its own name\n// matches, otherwise only when some descendant survives.\nfunction filterNodes(nodes: VaultTreeNode[], q: string): VaultTreeNode[] {\n const out: VaultTreeNode[] = []\n for (const node of nodes) {\n if (node.type === 'file') {\n if (node.name.toLowerCase().includes(q)) out.push(node)\n } else if (node.name.toLowerCase().includes(q)) {\n out.push(node)\n } else {\n const children = filterNodes(node.children ?? [], q)\n if (children.length > 0) out.push({ ...node, children })\n }\n }\n return out\n}\n\nclass EditorErrorBoundary extends Component<{ children: ReactNode; onReset?: () => void }, { error: unknown }> {\n state: { error: unknown } = { error: null }\n static getDerivedStateFromError(error: unknown) {\n return { error }\n }\n componentDidCatch(error: unknown, info: ErrorInfo) {\n console.error('Vault crashed:', error, info)\n }\n render() {\n if (this.state.error) {\n const msg = this.state.error instanceof Error\n ? this.state.error.message\n : typeof this.state.error === 'string'\n ? this.state.error\n : 'Something went wrong loading the vault'\n return (\n <div className=\"flex h-full flex-1 flex-col items-center justify-center p-8 text-center\">\n <h3 className=\"mb-1 text-sm font-medium text-foreground\">Vault failed to load</h3>\n <p className=\"mb-4 max-w-xs text-xs text-muted-foreground\">{String(msg)}</p>\n <button\n type=\"button\"\n onClick={() => { this.setState({ error: null }); this.props.onReset?.() }}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n Try again\n </button>\n </div>\n )\n }\n return this.props.children\n }\n}\n\nfunction TreeSkeleton() {\n return (\n <div className=\"space-y-2 p-4\" aria-hidden=\"true\">\n {[32, 48, 40, 52].map((w, i) => (\n <div key={i} className=\"h-4 animate-pulse rounded bg-muted\" style={{ width: `${w * 4}px` }} />\n ))}\n </div>\n )\n}\n\nfunction EditorSkeleton() {\n return (\n <div className=\"space-y-3 p-8\" aria-hidden=\"true\">\n <div className=\"h-5 w-1/2 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-full animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-3/4 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-2/3 animate-pulse rounded bg-muted\" />\n </div>\n )\n}\n\nfunction EmptyState() {\n return (\n <div className=\"flex h-full flex-col items-center justify-center p-8 text-center\">\n <h3 className=\"text-sm font-medium text-foreground\">Open a vault document</h3>\n <p className=\"mt-1 max-w-xs text-xs text-muted-foreground\">\n Select a file from the directory, or create a new one.\n </p>\n </div>\n )\n}\n\nfunction ReadErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-8 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't open this file</h3>\n <p className=\"mt-1 max-w-md text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nexport function VaultPane(props: VaultPaneProps) {\n const {\n port,\n renderTree,\n renderArtifact,\n renderDock,\n canWrite = true,\n selectedPath: controlledPath,\n onSelectedPathChange,\n codec,\n className,\n dockToggle,\n refreshKey,\n headerActions,\n onDownloadFile,\n pathBarClassName,\n } = props\n\n const activeCodec = codec ?? IDENTITY_CODEC\n const controlled = controlledPath !== undefined\n const isMarkdownCapable = codec !== undefined\n // `false` → a persistent dock (no toggle, always open with the selected file).\n const persistentDock = dockToggle === false\n const dockToggleCfg = dockToggle ? dockToggle : { label: 'Discuss', disabledWhenDirty: true }\n\n const [tree, setTree] = useState<VaultTreeNode[]>([])\n const [treeLoading, setTreeLoading] = useState(true)\n const [internalPath, setInternalPath] = useState<string | null>(null)\n const selectedPath = controlled ? (controlledPath ?? null) : internalPath\n\n const [selectedFile, setSelectedFile] = useState<VaultFile | null>(null)\n const [fileLoading, setFileLoading] = useState(false)\n const [readError, setReadError] = useState<string | null>(null)\n const [reloadNonce, setReloadNonce] = useState(0)\n const [saving, setSaving] = useState(false)\n\n const [editorMode, setEditorMode] = useState<VaultEditorMode>('rich')\n const [richDraft, setRichDraft] = useState<VaultRichParts>('')\n const [sourceDraft, setSourceDraft] = useState('')\n const [isDirty, setIsDirty] = useState(false)\n\n const [createOpen, setCreateOpen] = useState(false)\n const [newPath, setNewPath] = useState('')\n const [creating, setCreating] = useState(false)\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [dockOpen, setDockOpen] = useState(false)\n const [pendingNav, setPendingNav] = useState<PendingNav>(null)\n const [query, setQuery] = useState('')\n\n const savedContentRef = useRef('')\n const loadedPathRef = useRef<string | null>(null)\n\n const filePaths = useMemo(() => collectFilePaths(tree, new Set<string>()), [tree])\n const resolvedSelectedPath = useMemo(\n () => selectedPath ? resolveFilePath(selectedPath, filePaths) : null,\n [selectedPath, filePaths],\n )\n const treeRoot = useMemo<VaultTreeNode>(\n () => ({ name: 'Vault', path: '', type: 'directory', children: tree }),\n [tree],\n )\n const visibleRoot = useMemo<VaultTreeNode>(() => {\n const q = query.trim().toLowerCase()\n if (!q) return treeRoot\n return { ...treeRoot, children: filterNodes(tree, q) }\n }, [treeRoot, tree, query])\n\n const commitPath = useCallback(\n (next: string | null) => {\n if (!controlled) setInternalPath(next)\n onSelectedPathChange?.(next)\n },\n [controlled, onSelectedPathChange],\n )\n\n const refresh = useCallback(async () => {\n setTreeLoading(true)\n try {\n setTree(await port.listTree())\n } finally {\n setTreeLoading(false)\n }\n }, [port])\n\n useEffect(() => {\n void refresh()\n }, [refresh, refreshKey])\n\n useEffect(() => {\n if (!selectedPath) {\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n if (treeLoading) return\n if (!resolvedSelectedPath) {\n commitPath(null)\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n let cancelled = false\n const path = resolvedSelectedPath\n if (path !== selectedPath) commitPath(path)\n setFileLoading(true)\n setReadError(null)\n void (async () => {\n try {\n const file = await port.readFile(path)\n if (!cancelled) setSelectedFile(file)\n } catch (err) {\n // Surface read failures instead of making them indistinguishable from\n // the intentionally empty \"no file selected\" state.\n if (!cancelled) {\n setSelectedFile(null)\n setReadError(err instanceof Error ? err.message : 'Failed to read file')\n }\n } finally {\n if (!cancelled) setFileLoading(false)\n }\n })()\n return () => {\n cancelled = true\n }\n }, [port, selectedPath, resolvedSelectedPath, treeLoading, refreshKey, reloadNonce, commitPath])\n\n useEffect(() => {\n if (!selectedFile) {\n loadedPathRef.current = null\n savedContentRef.current = ''\n setRichDraft('')\n setSourceDraft('')\n setEditorMode('rich')\n setIsDirty(false)\n return\n }\n const pathChanged = loadedPathRef.current !== selectedFile.path\n loadedPathRef.current = selectedFile.path\n savedContentRef.current = selectedFile.content\n setRichDraft(activeCodec.parse(selectedFile.content))\n setSourceDraft(selectedFile.content)\n if (pathChanged) setEditorMode('rich')\n setIsDirty(false)\n setDockOpen(false)\n }, [selectedFile, activeCodec])\n\n const guardedOpen = useCallback(\n (path: string) => {\n if (path === selectedPath) return\n if (isDirty) {\n setPendingNav({ type: 'open', path })\n return\n }\n commitPath(path)\n },\n [isDirty, selectedPath, commitPath],\n )\n\n // Some tree models keep their original selection callback while resetting\n // paths internally. Keep the callable stable, but have it execute the latest\n // file-path validation and dirty-guard logic.\n const selectFileRef = useRef<(path: string) => void>(() => {})\n selectFileRef.current = (rawPath: string) => {\n const path = resolveFilePath(rawPath, filePaths)\n if (path) {\n guardedOpen(path)\n return\n }\n }\n const handleTreeSelect = useCallback((path: string) => selectFileRef.current(path), [])\n\n const guardedClose = useCallback(() => {\n if (isDirty) {\n setPendingNav({ type: 'close' })\n return\n }\n commitPath(null)\n setSelectedFile(null)\n }, [isDirty, commitPath])\n\n const confirmDiscard = useCallback(() => {\n const nav = pendingNav\n setPendingNav(null)\n setIsDirty(false)\n if (!nav) return\n if (nav.type === 'open') {\n commitPath(nav.path)\n } else {\n commitPath(null)\n setSelectedFile(null)\n }\n }, [pendingNav, commitPath])\n\n const showRichMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'rich') return mode\n setRichDraft(activeCodec.parse(sourceDraft))\n setIsDirty(sourceDraft !== savedContentRef.current)\n return 'rich'\n })\n }, [activeCodec, sourceDraft])\n\n const showSourceMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'source') return mode\n const content = isDirty ? activeCodec.serialize(richDraft) : savedContentRef.current\n setSourceDraft(content)\n setIsDirty(content !== savedContentRef.current)\n return 'source'\n })\n }, [activeCodec, isDirty, richDraft])\n\n const onSourceChange = useCallback((next: string) => {\n setSourceDraft(next)\n setIsDirty(next !== savedContentRef.current)\n }, [])\n\n const onRichChange = useCallback((next: VaultRichParts) => {\n setRichDraft(next)\n setIsDirty(activeCodec.serialize(next) !== savedContentRef.current)\n }, [activeCodec])\n\n const saveCurrent = useCallback(async () => {\n if (!selectedFile) return\n const content = editorMode === 'source' ? sourceDraft : activeCodec.serialize(richDraft)\n setSaving(true)\n try {\n await port.writeFile(selectedFile.path, content)\n savedContentRef.current = content\n setSelectedFile({ ...selectedFile, content })\n setSourceDraft(content)\n setRichDraft(activeCodec.parse(content))\n setIsDirty(false)\n } finally {\n setSaving(false)\n }\n }, [selectedFile, editorMode, sourceDraft, richDraft, activeCodec, port])\n\n const handleCreate = useCallback(async () => {\n const trimmed = newPath.trim()\n if (!trimmed) return\n setCreating(true)\n try {\n const created = await port.createFile(trimmed)\n setCreateOpen(false)\n setNewPath('')\n await refresh()\n commitPath(created)\n } finally {\n setCreating(false)\n }\n }, [newPath, port, refresh, commitPath])\n\n const handleDelete = useCallback(async () => {\n if (!selectedFile) return\n setDeleting(true)\n try {\n await port.deleteFile(selectedFile.path)\n setDeleteOpen(false)\n setIsDirty(false)\n commitPath(null)\n setSelectedFile(null)\n await refresh()\n } finally {\n setDeleting(false)\n }\n }, [selectedFile, port, refresh, commitPath])\n\n return (\n <EditorErrorBoundary onReset={() => { commitPath(null); setSelectedFile(null) }}>\n <div className={`flex min-h-0 flex-1 overflow-hidden ${className ?? ''}`}>\n <div className=\"flex w-[23rem] min-w-[23rem] flex-col border-r border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <input\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search…\"\n aria-label=\"Search vault\"\n className=\"h-8 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-primary/60\"\n />\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {headerActions}\n <button\n type=\"button\"\n aria-label=\"Refresh vault\"\n onClick={() => void refresh()}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n ↻\n </button>\n {canWrite && (\n <button\n type=\"button\"\n aria-label=\"New vault file\"\n onClick={() => setCreateOpen(true)}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n +\n </button>\n )}\n </div>\n </div>\n <div\n className=\"flex-1 overflow-y-auto\"\n onClickCapture={(event) => {\n const path = treeClickPath(event)\n if (path) handleTreeSelect(path)\n }}\n >\n {treeLoading ? (\n <TreeSkeleton />\n ) : (\n renderTree({\n root: visibleRoot,\n selectedPath: resolvedSelectedPath ?? undefined,\n onSelect: handleTreeSelect,\n })\n )}\n </div>\n </div>\n\n <div className=\"flex min-w-0 flex-1 flex-col overflow-hidden\">\n {selectedFile && (\n <div className={`flex shrink-0 items-center justify-between border-b border-border px-4 py-1.5 ${pathBarClassName ?? 'bg-card'}`}>\n <span data-vault-path className=\"truncate text-xs font-medium text-foreground\">{selectedFile.path}</span>\n <div className=\"flex items-center gap-1\">\n {canWrite && isMarkdownCapable && (\n <div className=\"mr-1 flex items-center gap-1\">\n <button\n type=\"button\"\n aria-label=\"Edit as rich text\"\n aria-pressed={editorMode === 'rich'}\n onClick={showRichMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'rich'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Rich\n </button>\n <button\n type=\"button\"\n aria-label=\"Edit as source\"\n aria-pressed={editorMode === 'source'}\n onClick={showSourceMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'source'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Source\n </button>\n </div>\n )}\n {renderDock && !persistentDock && (\n <button\n type=\"button\"\n aria-label={dockToggleCfg.label}\n aria-pressed={dockOpen}\n disabled={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty}\n title={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty ? 'Save your changes first' : (dockToggleCfg.title ?? dockToggleCfg.label)}\n onClick={() => setDockOpen((v) => !v)}\n className={`inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-40 ${\n dockOpen\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n {dockToggleCfg.label}\n </button>\n )}\n {onDownloadFile && (\n <button\n type=\"button\"\n aria-label=\"Download this file\"\n title=\"Download file\"\n onClick={() => onDownloadFile(selectedFile)}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n {canWrite && (\n <button\n type=\"button\"\n aria-label=\"Delete this file\"\n title=\"Delete file\"\n onClick={() => setDeleteOpen(true)}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n )}\n <div className=\"flex-1 overflow-hidden\">\n {fileLoading ? (\n <EditorSkeleton />\n ) : readError ? (\n <ReadErrorState message={readError} onRetry={() => setReloadNonce((n) => n + 1)} />\n ) : selectedFile && canWrite && isMarkdownCapable && editorMode === 'source' ? (\n <SourceEditor\n path={selectedFile.path}\n content={sourceDraft}\n saving={saving}\n dirty={isDirty}\n onChange={onSourceChange}\n onSave={() => void saveCurrent()}\n />\n ) : selectedFile ? (\n renderArtifact({\n file: selectedFile,\n loading: false,\n mode: editorMode,\n canWrite,\n richDraft,\n dirty: isDirty,\n onRichChange,\n onSave: () => void saveCurrent(),\n })\n ) : (\n <EmptyState />\n )}\n </div>\n </div>\n\n {renderDock && selectedFile && renderDock({\n file: selectedFile,\n open: persistentDock ? true : dockOpen,\n onClose: persistentDock ? () => {} : () => setDockOpen(false),\n })}\n\n <ConfirmDialog\n open={createOpen}\n title=\"Create vault file\"\n description=\"Add a new document to this vault.\"\n confirmLabel={creating ? 'Creating…' : 'Create'}\n confirmDisabled={creating || !newPath.trim()}\n onConfirm={() => void handleCreate()}\n onCancel={() => { setCreateOpen(false); setNewPath('') }}\n >\n <input\n value={newPath}\n autoFocus\n onChange={(e) => setNewPath(e.target.value)}\n placeholder=\"e.g. playbooks/new-strategy.md\"\n aria-label=\"New file path\"\n className=\"h-9 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-primary/60\"\n />\n </ConfirmDialog>\n\n <ConfirmDialog\n open={deleteOpen}\n title=\"Delete file?\"\n description={`This permanently removes ${selectedFile?.path ?? 'this file'} from the vault.`}\n confirmLabel={deleting ? 'Deleting…' : 'Delete file'}\n confirmDisabled={deleting}\n destructive\n onConfirm={() => void handleDelete()}\n onCancel={() => setDeleteOpen(false)}\n />\n\n <ConfirmDialog\n open={pendingNav !== null}\n title=\"Discard unsaved changes?\"\n description=\"Your edits to this document haven't been saved. Continue and lose them?\"\n confirmLabel=\"Discard changes\"\n destructive\n onConfirm={confirmDiscard}\n onCancel={() => setPendingNav(null)}\n />\n </div>\n </EditorErrorBoundary>\n )\n}\n\nfunction SourceEditor({\n path,\n content,\n saving,\n dirty,\n onChange,\n onSave,\n}: {\n path: string\n content: string\n saving: boolean\n dirty: boolean\n onChange: (content: string) => void\n onSave: () => void\n}) {\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-2\">\n <p className=\"truncate font-mono text-[11px] text-muted-foreground\">{path}</p>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"rounded-full border border-border bg-background px-2.5 py-1 text-xs text-muted-foreground\">\n {dirty ? 'Unsaved changes' : 'Saved'}\n </span>\n <button\n type=\"button\"\n onClick={onSave}\n disabled={saving || !dirty}\n className=\"inline-flex h-7 items-center rounded-md bg-primary px-2 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {saving ? 'Saving…' : 'Save'}\n </button>\n </div>\n </div>\n <textarea\n value={content}\n onChange={(event) => onChange(event.target.value)}\n spellCheck={false}\n aria-label=\"Source editor\"\n className=\"min-h-0 flex-1 resize-none border-0 bg-background p-4 font-mono text-sm leading-6 text-foreground outline-none\"\n />\n </div>\n )\n}\n","/**\n * Self-contained confirm dialog — no dialog library. A focus-trapped modal with\n * Esc-to-cancel and Enter-to-confirm, used for create / delete / discard-unsaved\n * flows so the pane carries zero UI-kit dependency.\n */\n\nimport { useEffect, useRef, type ReactNode } from 'react'\n\nexport interface ConfirmDialogProps {\n open: boolean\n title: string\n description?: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n /** Styles the confirm button as a destructive action. */\n destructive?: boolean\n /** Disables the confirm button (e.g. while the action is in flight). */\n confirmDisabled?: boolean\n onConfirm: () => void\n onCancel: () => void\n /** Optional body (e.g. an input field for the create flow). */\n children?: ReactNode\n}\n\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n destructive = false,\n confirmDisabled = false,\n onConfirm,\n onCancel,\n children,\n}: ConfirmDialogProps) {\n const panelRef = useRef<HTMLDivElement>(null)\n const confirmRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n if (!open) return\n confirmRef.current?.focus()\n }, [open])\n\n if (!open) return null\n\n function onKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && !confirmDisabled) {\n event.preventDefault()\n onConfirm()\n return\n }\n if (event.key !== 'Tab') return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement as HTMLElement | null\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onMouseDown={(e) => { if (e.target === e.currentTarget) onCancel() }}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onKeyDown={onKeyDown}\n className=\"w-full max-w-md rounded-lg border border-border bg-card p-5 shadow-lg\"\n >\n <h2 className=\"text-sm font-semibold text-foreground\">{title}</h2>\n {description && <p className=\"mt-1.5 text-xs text-muted-foreground\">{description}</p>}\n {children && <div className=\"mt-3\">{children}</div>}\n <div className=\"mt-5 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex h-8 items-center rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60\"\n >\n {cancelLabel}\n </button>\n <button\n ref={confirmRef}\n type=\"button\"\n onClick={onConfirm}\n disabled={confirmDisabled}\n className={`inline-flex h-8 items-center rounded-md px-3 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 ${\n destructive\n ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90'\n : 'bg-primary text-primary-foreground hover:bg-primary/90'\n }`}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","jsx","jsxs","useRef","useEffect"]}
|
|
File without changes
|