fix: guard inspector property mutations

This commit is contained in:
lucaronin
2026-05-08 17:37:04 +02:00
parent 852c153d24
commit eb731bbaad
9 changed files with 172 additions and 52 deletions

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect } from 'react'
import { useCallback, useEffect, type MutableRefObject } from 'react'
import type { VaultEntry } from '../types'
import type { FrontmatterValue } from '../components/Inspector'
import { useTabManagement } from './useTabManagement'
@@ -163,6 +163,16 @@ async function flushBeforeNoteMutation(
}
}
function activePathGuardAllowsMutation(
path: string,
activeTabPathRef: MutableRefObject<string | null>,
options?: FrontmatterOpOptions,
): boolean {
const requiredPath = options?.requireActivePath
if (!requiredPath) return true
return notePathsMatch(path, requiredPath) && notePathsMatch(activeTabPathRef.current, requiredPath)
}
async function maybeRenameAfterFrontmatterUpdate({
path,
key,
@@ -183,16 +193,18 @@ interface UpdateFrontmatterAndMaybeRenameParams {
key: string
options?: FrontmatterOpOptions
path: string
runFrontmatterOp: (
op: 'update' | 'delete',
path: string,
key: string,
value?: FrontmatterValue,
options?: FrontmatterOpOptions,
) => Promise<string | undefined>
runFrontmatterOp: RunFrontmatterOp
value: FrontmatterValue
}
type RunFrontmatterOp = (
op: 'update' | 'delete',
path: string,
key: string,
value?: FrontmatterValue,
options?: FrontmatterOpOptions,
) => Promise<string | undefined>
async function updateFrontmatterAndMaybeRename({
config,
deps,
@@ -202,8 +214,10 @@ async function updateFrontmatterAndMaybeRename({
runFrontmatterOp,
value,
}: UpdateFrontmatterAndMaybeRenameParams): Promise<void> {
if (!activePathGuardAllowsMutation(path, deps.activeTabPathRef, options)) return
const canFlush = await flushBeforeNoteMutation(path, config.flushBeforeNoteMutation)
if (!canFlush) return
if (!activePathGuardAllowsMutation(path, deps.activeTabPathRef, options)) return
const newContent = await runFrontmatterOp('update', path, key, value, options)
if (!applyFrontmatterCallbacks({ config, path, newContent })) return
@@ -288,13 +302,7 @@ function useFrontmatterActionHandlers({
handleSwitchTab: (path: string) => void
setToastMessage: (msg: string | null) => void
updateTabContent: (path: string, newContent: string) => void
runFrontmatterOp: (
op: 'update' | 'delete',
path: string,
key: string,
value?: FrontmatterValue,
options?: FrontmatterOpOptions,
) => Promise<string | undefined>
runFrontmatterOp: RunFrontmatterOp
}) {
const handleUpdateFrontmatter = useCallback(async (
path: string,
@@ -325,22 +333,26 @@ function useFrontmatterActionHandlers({
}, [activeTabPathRef, config, handleSwitchTab, renameTabsRef, runFrontmatterOp, setTabs, setToastMessage, updateTabContent])
const handleDeleteProperty = useCallback(async (path: string, key: string, options?: FrontmatterOpOptions) => {
if (!activePathGuardAllowsMutation(path, activeTabPathRef, options)) return
const canFlush = await flushBeforeNoteMutation(path, config.flushBeforeNoteMutation)
if (!canFlush) return
if (!activePathGuardAllowsMutation(path, activeTabPathRef, options)) return
const newContent = await runFrontmatterOp('delete', path, key, undefined, options)
if (!applyFrontmatterCallbacks({ config, path, newContent })) return
await notifyFrontmatterPersisted(config, key)
}, [config, runFrontmatterOp])
}, [activeTabPathRef, config, runFrontmatterOp])
const handleAddProperty = useCallback(async (path: string, key: string, value: FrontmatterValue) => {
const handleAddProperty = useCallback(async (path: string, key: string, value: FrontmatterValue, options?: FrontmatterOpOptions) => {
if (!activePathGuardAllowsMutation(path, activeTabPathRef, options)) return
const canFlush = await flushBeforeNoteMutation(path, config.flushBeforeNoteMutation)
if (!canFlush) return
if (!activePathGuardAllowsMutation(path, activeTabPathRef, options)) return
const newContent = await runFrontmatterOp('update', path, key, value)
const newContent = await runFrontmatterOp('update', path, key, value, options)
if (!applyFrontmatterCallbacks({ config, path, newContent })) return
await notifyFrontmatterPersisted(config, key)
}, [config, runFrontmatterOp])
}, [activeTabPathRef, config, runFrontmatterOp])
return {
handleUpdateFrontmatter,
@@ -349,6 +361,38 @@ function useFrontmatterActionHandlers({
}
}
function useFrontmatterRunner({
activeTabPathRef,
entries,
setToastMessage,
updateEntry,
updateTabContent,
}: {
activeTabPathRef: MutableRefObject<string | null>
entries: VaultEntry[]
setToastMessage: NoteActionsConfig['setToastMessage']
updateEntry: NoteActionsConfig['updateEntry']
updateTabContent: (path: string, newContent: string) => void
}): RunFrontmatterOp {
return useCallback(
(op, path, key, value, options) => runFrontmatterAndApply({
op,
path,
key,
value,
callbacks: {
updateTab: updateTabContent,
updateEntry,
toast: setToastMessage,
getEntry: (p) => findByNotePath(entries, p),
shouldApply: (p) => activePathGuardAllowsMutation(p, activeTabPathRef, options),
},
options,
}),
[activeTabPathRef, entries, setToastMessage, updateEntry, updateTabContent],
)
}
export function useNoteActions(config: NoteActionsConfig) {
const { entries, setToastMessage, updateEntry } = config
const tabMgmt = useTabManagement(buildTabManagementOptions(config))
@@ -379,18 +423,7 @@ export function useNoteActions(config: NoteActionsConfig) {
[entries, handleSelectNote, tabMgmt.activeTabPath, tabMgmt.tabs],
)
const runFrontmatterOp = useCallback(
(op: 'update' | 'delete', path: string, key: string, value?: FrontmatterValue, options?: FrontmatterOpOptions) =>
runFrontmatterAndApply({
op,
path,
key,
value,
callbacks: { updateTab: updateTabContent, updateEntry, toast: setToastMessage, getEntry: (p) => findByNotePath(entries, p) },
options,
}),
[updateTabContent, updateEntry, setToastMessage, entries],
)
const runFrontmatterOp = useFrontmatterRunner({ activeTabPathRef, entries, setToastMessage, updateEntry, updateTabContent })
const frontmatterActions = useFrontmatterActionHandlers({
config,
renameTabsRef: rename.tabsRef,