fix: note list shows incomplete relationships when opening from sidebar
Two root causes: 1. noteListHooks used a stale selection.entry to build relationship groups — now looks up the fresh entry from the entries array so relationship updates propagate immediately. 2. frontmatterToEntryPatch didn't update entry.relationships — added RelationshipPatch support so frontmatter changes also update the relationships map in state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,12 +13,38 @@ const ENTRY_DELETE_MAP: Record<string, Partial<VaultEntry>> = {
|
||||
template: { template: null }, sort: { sort: null }, visible: { visible: null },
|
||||
}
|
||||
|
||||
/** Check if a string contains a wikilink pattern `[[...]]`. */
|
||||
function isWikilink(s: string): boolean {
|
||||
return s.startsWith('[[') && s.includes(']]')
|
||||
}
|
||||
|
||||
/** Extract wikilink strings from a FrontmatterValue. Returns empty array if none. */
|
||||
function extractWikilinks(value: FrontmatterValue): string[] {
|
||||
if (typeof value === 'string') return isWikilink(value) ? [value] : []
|
||||
if (Array.isArray(value)) return value.filter((v): v is string => typeof v === 'string' && isWikilink(v))
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship patch: a partial update to merge into `entry.relationships`.
|
||||
* Keys map to their new ref arrays. A `null` value means "remove this key".
|
||||
*/
|
||||
export type RelationshipPatch = Record<string, string[] | null>
|
||||
|
||||
export interface EntryPatchResult {
|
||||
patch: Partial<VaultEntry>
|
||||
relationshipPatch: RelationshipPatch | null
|
||||
}
|
||||
|
||||
/** Map a frontmatter key+value to the corresponding VaultEntry field(s). */
|
||||
export function frontmatterToEntryPatch(
|
||||
op: 'update' | 'delete', key: string, value?: FrontmatterValue,
|
||||
): Partial<VaultEntry> {
|
||||
): EntryPatchResult {
|
||||
const k = key.toLowerCase().replace(/\s+/g, '_')
|
||||
if (op === 'delete') return ENTRY_DELETE_MAP[k] ?? {}
|
||||
if (op === 'delete') {
|
||||
const relPatch: RelationshipPatch = { [key]: null }
|
||||
return { patch: ENTRY_DELETE_MAP[k] ?? {}, relationshipPatch: relPatch }
|
||||
}
|
||||
const str = value != null ? String(value) : null
|
||||
const arr = Array.isArray(value) ? value.map(String) : []
|
||||
const updates: Record<string, Partial<VaultEntry>> = {
|
||||
@@ -32,7 +58,11 @@ export function frontmatterToEntryPatch(
|
||||
view: { view: str },
|
||||
visible: { visible: value === false ? false : null },
|
||||
}
|
||||
return updates[k] ?? {}
|
||||
// Also update the relationships map for wikilink-containing values
|
||||
const wikilinks = value != null ? extractWikilinks(value) : []
|
||||
const relationshipPatch: RelationshipPatch | null =
|
||||
wikilinks.length > 0 ? { [key]: wikilinks } : null
|
||||
return { patch: updates[k] ?? {}, relationshipPatch }
|
||||
}
|
||||
|
||||
async function invokeFrontmatter(command: string, args: Record<string, unknown>): Promise<string> {
|
||||
@@ -65,18 +95,42 @@ export interface FrontmatterOpOptions {
|
||||
silent?: boolean
|
||||
}
|
||||
|
||||
/** Apply a relationship patch by merging into the existing relationships map. */
|
||||
export function applyRelationshipPatch(
|
||||
existing: Record<string, string[]>, relPatch: RelationshipPatch,
|
||||
): Record<string, string[]> {
|
||||
const merged = { ...existing }
|
||||
for (const [k, v] of Object.entries(relPatch)) {
|
||||
if (v === null) delete merged[k]
|
||||
else merged[k] = v
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
/** Run a frontmatter update/delete and apply the result to state.
|
||||
* Returns the new file content on success, or undefined on failure. */
|
||||
export async function runFrontmatterAndApply(
|
||||
op: 'update' | 'delete', path: string, key: string, value: FrontmatterValue | undefined,
|
||||
callbacks: { updateTab: (p: string, c: string) => void; updateEntry: (p: string, patch: Partial<VaultEntry>) => void; toast: (m: string | null) => void },
|
||||
callbacks: {
|
||||
updateTab: (p: string, c: string) => void
|
||||
updateEntry: (p: string, patch: Partial<VaultEntry>) => void
|
||||
toast: (m: string | null) => void
|
||||
getEntry?: (p: string) => VaultEntry | undefined
|
||||
},
|
||||
options?: FrontmatterOpOptions,
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const newContent = await executeFrontmatterOp(op, path, key, value)
|
||||
callbacks.updateTab(path, newContent)
|
||||
const patch = frontmatterToEntryPatch(op, key, value)
|
||||
if (Object.keys(patch).length > 0) callbacks.updateEntry(path, patch)
|
||||
const { patch, relationshipPatch } = frontmatterToEntryPatch(op, key, value)
|
||||
const fullPatch = { ...patch }
|
||||
if (relationshipPatch && callbacks.getEntry) {
|
||||
const current = callbacks.getEntry(path)
|
||||
if (current) {
|
||||
fullPatch.relationships = applyRelationshipPatch(current.relationships, relationshipPatch)
|
||||
}
|
||||
}
|
||||
if (Object.keys(fullPatch).length > 0) callbacks.updateEntry(path, fullPatch)
|
||||
if (!options?.silent) callbacks.toast(op === 'update' ? 'Property updated' : 'Property deleted')
|
||||
return newContent
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user