From fe37bb4b27db23cd54be9005b8dfcafe69d7a41f Mon Sep 17 00:00:00 2001 From: lucaronin Date: Wed, 11 Mar 2026 21:24:57 +0100 Subject: [PATCH] feat: wire create-open relationship note to all panel contexts --- src/App.tsx | 1 + src/components/Editor.tsx | 4 +++- src/components/EditorRightPanel.tsx | 4 +++- src/components/Inspector.tsx | 4 +++- src/hooks/useNoteActions.ts | 20 ++++++++++++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 9d7e909e..8e810aee 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -621,6 +621,7 @@ function App() { onUpdateFrontmatter={notes.handleUpdateFrontmatter} onDeleteProperty={notes.handleDeleteProperty} onAddProperty={notes.handleAddProperty} + onCreateAndOpenNote={notes.handleCreateNoteForRelationship} showAIChat={dialogs.showAIChat} onToggleAIChat={dialogs.toggleAIChat} vaultPath={resolvedPath} diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 81b78e31..f8c9c025 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -45,6 +45,7 @@ interface EditorProps { onUpdateFrontmatter?: (path: string, key: string, value: FrontmatterValue) => Promise onDeleteProperty?: (path: string, key: string) => Promise onAddProperty?: (path: string, key: string, value: FrontmatterValue) => Promise + onCreateAndOpenNote?: (title: string) => Promise showAIChat?: boolean onToggleAIChat?: () => void vaultPath?: string @@ -120,7 +121,7 @@ export const Editor = memo(function Editor({ onLoadDiff, onLoadDiffAtCommit, getNoteStatus, onCreateNote, inspectorCollapsed, onToggleInspector, inspectorWidth, onInspectorResize, inspectorEntry, inspectorContent, gitHistory, - onUpdateFrontmatter, onDeleteProperty, onAddProperty, + onUpdateFrontmatter, onDeleteProperty, onAddProperty, onCreateAndOpenNote, showAIChat, onToggleAIChat, vaultPath, noteList, noteListFilter, onTrashNote, onRestoreNote, onDeleteNote, onArchiveNote, onUnarchiveNote, @@ -245,6 +246,7 @@ export const Editor = memo(function Editor({ onUpdateFrontmatter={onUpdateFrontmatter} onDeleteProperty={onDeleteProperty} onAddProperty={onAddProperty} + onCreateAndOpenNote={onCreateAndOpenNote} onOpenNote={onNavigateWikilink} onFileCreated={onFileCreated} onFileModified={onFileModified} diff --git a/src/components/EditorRightPanel.tsx b/src/components/EditorRightPanel.tsx index 5a57c800..33936454 100644 --- a/src/components/EditorRightPanel.tsx +++ b/src/components/EditorRightPanel.tsx @@ -22,6 +22,7 @@ interface EditorRightPanelProps { onUpdateFrontmatter?: (path: string, key: string, value: FrontmatterValue) => Promise onDeleteProperty?: (path: string, key: string) => Promise onAddProperty?: (path: string, key: string, value: FrontmatterValue) => Promise + onCreateAndOpenNote?: (title: string) => Promise onOpenNote?: (path: string) => void onFileCreated?: (relativePath: string) => void onFileModified?: (relativePath: string) => void @@ -33,7 +34,7 @@ export function EditorRightPanel({ inspectorEntry, inspectorContent, entries, gitHistory, vaultPath, openTabs, noteList, noteListFilter, onToggleInspector, onToggleAIChat, onNavigateWikilink, onViewCommitDiff, - onUpdateFrontmatter, onDeleteProperty, onAddProperty, onOpenNote, + onUpdateFrontmatter, onDeleteProperty, onAddProperty, onCreateAndOpenNote, onOpenNote, onFileCreated, onFileModified, onVaultChanged, }: EditorRightPanelProps) { if (showAIChat) { @@ -79,6 +80,7 @@ export function EditorRightPanel({ onUpdateFrontmatter={onUpdateFrontmatter} onDeleteProperty={onDeleteProperty} onAddProperty={onAddProperty} + onCreateAndOpenNote={onCreateAndOpenNote} /> ) diff --git a/src/components/Inspector.tsx b/src/components/Inspector.tsx index 731086c9..2b397fcb 100644 --- a/src/components/Inspector.tsx +++ b/src/components/Inspector.tsx @@ -23,6 +23,7 @@ interface InspectorProps { onUpdateFrontmatter?: (path: string, key: string, value: FrontmatterValue) => Promise onDeleteProperty?: (path: string, key: string) => Promise onAddProperty?: (path: string, key: string, value: FrontmatterValue) => Promise + onCreateAndOpenNote?: (title: string) => Promise } function useBacklinks( @@ -114,7 +115,7 @@ function EmptyInspector() { export function Inspector({ collapsed, onToggle, entry, content, entries, gitHistory, onNavigate, - onViewCommitDiff, onUpdateFrontmatter, onDeleteProperty, onAddProperty, + onViewCommitDiff, onUpdateFrontmatter, onDeleteProperty, onAddProperty, onCreateAndOpenNote, }: InspectorProps) { const referencedBy = useReferencedBy(entry, entries) const backlinks = useBacklinks(entry, entries, referencedBy) @@ -157,6 +158,7 @@ export function Inspector({ onAddProperty={onAddProperty ? handleAddProperty : undefined} onUpdateProperty={onUpdateFrontmatter ? handleUpdateProperty : undefined} onDeleteProperty={onDeleteProperty ? handleDeleteProperty : undefined} + onCreateAndOpenNote={onCreateAndOpenNote} /> diff --git a/src/hooks/useNoteActions.ts b/src/hooks/useNoteActions.ts index ee9f33e8..c89e8c1f 100644 --- a/src/hooks/useNoteActions.ts +++ b/src/hooks/useNoteActions.ts @@ -415,6 +415,25 @@ export function useNoteActions(config: NoteActionsConfig) { } }, [entries, openTabWithContent, addEntry, config.vaultPath, config.trackUnsaved, config.markContentPending]) // eslint-disable-line react-hooks/exhaustive-deps -- config callbacks are stable + /** Create a note with the given title, open it in a tab, and persist to disk. + * Returns true on success, false on failure (shows toast on error). */ + const handleCreateNoteForRelationship = useCallback(async (title: string): Promise => { + const template = resolveTemplate(entries, 'Note') + const resolved = resolveNewNote(title, 'Note', config.vaultPath, template) + openTabWithContent(resolved.entry, resolved.content) + addEntryWithMock(resolved.entry, resolved.content, addEntry) + try { + await persistNewNote(resolved.entry.path, resolved.content) + config.onNewNotePersisted?.() + return true + } catch { + handleCloseTab(resolved.entry.path) + removeEntry(resolved.entry.path) + setToastMessage('Failed to create note — disk write error') + return false + } + }, [entries, openTabWithContent, addEntry, handleCloseTab, removeEntry, setToastMessage, config.vaultPath, config.onNewNotePersisted]) // eslint-disable-line react-hooks/exhaustive-deps -- config callbacks are stable + /** Close tab and discard entry+unsaved state if the note was never persisted. */ const handleCloseTabWithCleanup = useCallback((path: string) => { if (unsavedPathsRef.current?.has(path)) { removeEntry(path); config.clearUnsaved?.(path) } @@ -471,6 +490,7 @@ export function useNoteActions(config: NoteActionsConfig) { handleNavigateWikilink, handleCreateNote, handleCreateNoteImmediate, + handleCreateNoteForRelationship, handleOpenDailyNote, handleCreateType, createTypeEntrySilent,