Merge pull request #13 from n8k99/claude/fix-nested-folder-display-015Ytt8mSX9sfytMQC85P4gA

Claude/fix nested folder display 015 ytt8m sx9sfyt mqc85 p4g a
This commit is contained in:
Nathan Eckenrode 2025-11-14 00:40:35 -05:00 committed by GitHub
commit d47e3d0bb0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 132 additions and 5 deletions

View file

@ -13,6 +13,16 @@ const ObsidianBridge = (() => {
vaultName: ""
};
// Cache for vault file list
let vaultFilesCache = {
files: null,
timestamp: null,
ttl: 5 * 60 * 1000 // 5 minutes cache
};
// Index: fmg-id → file path for fast lookups
let fmgIdIndex = {};
// Initialize from localStorage
function init() {
const stored = localStorage.getItem("obsidianConfig");
@ -24,6 +34,18 @@ const ObsidianBridge = (() => {
ERROR && console.error("Failed to load Obsidian config:", error);
}
}
// Load FMG ID index from localStorage
const storedIndex = localStorage.getItem("obsidianFmgIdIndex");
if (storedIndex) {
try {
fmgIdIndex = JSON.parse(storedIndex);
INFO && console.log(`Loaded FMG ID index with ${Object.keys(fmgIdIndex).length} entries`);
} catch (error) {
ERROR && console.error("Failed to load FMG ID index:", error);
fmgIdIndex = {};
}
}
}
// Save configuration
@ -94,19 +116,65 @@ const ObsidianBridge = (() => {
return mdFiles;
}
// Get all markdown files from vault (recursively)
async function getVaultFiles() {
// Clear the vault files cache
function clearVaultCache() {
vaultFilesCache.files = null;
vaultFilesCache.timestamp = null;
INFO && console.log("Vault file cache cleared");
}
// Save FMG ID index to localStorage
function saveFmgIdIndex() {
try {
localStorage.setItem("obsidianFmgIdIndex", JSON.stringify(fmgIdIndex));
DEBUG && console.log(`Saved FMG ID index with ${Object.keys(fmgIdIndex).length} entries`);
} catch (error) {
ERROR && console.error("Failed to save FMG ID index:", error);
}
}
// Add entry to FMG ID index
function addToFmgIdIndex(fmgId, filePath) {
if (!fmgId) return;
fmgIdIndex[fmgId] = filePath;
saveFmgIdIndex();
DEBUG && console.log(`Added to index: ${fmgId}${filePath}`);
}
// Get file path from FMG ID index
function getFromFmgIdIndex(fmgId) {
return fmgIdIndex[fmgId] || null;
}
// Get all markdown files from vault (recursively, with caching)
async function getVaultFiles(forceRefresh = false) {
if (!config.enabled) {
throw new Error("Obsidian not connected");
}
// Check cache
const now = Date.now();
const cacheValid = vaultFilesCache.files !== null &&
vaultFilesCache.timestamp !== null &&
(now - vaultFilesCache.timestamp) < vaultFilesCache.ttl;
if (cacheValid && !forceRefresh) {
INFO && console.log(`getVaultFiles: Using cached list (${vaultFilesCache.files.length} files)`);
return vaultFilesCache.files;
}
try {
TIME && console.time("getVaultFiles");
INFO && console.log("getVaultFiles: Scanning vault (cache miss or expired)...");
// Recursively scan all directories
const mdFiles = await scanDirectory("");
INFO && console.log(`getVaultFiles: Found ${mdFiles.length} markdown files (recursive scan)`);
// Update cache
vaultFilesCache.files = mdFiles;
vaultFilesCache.timestamp = now;
INFO && console.log(`getVaultFiles: Found ${mdFiles.length} markdown files (recursive scan, cached)`);
DEBUG && console.log("Sample files:", mdFiles.slice(0, 10));
TIME && console.timeEnd("getVaultFiles");
@ -344,9 +412,43 @@ const ObsidianBridge = (() => {
}
}
// Find note by FMG ID in frontmatter
// Find note by FMG ID in frontmatter (with index for fast lookup)
async function findNoteByFmgId(fmgId) {
if (!fmgId) return null;
try {
// First, check the index for instant lookup
const indexedPath = getFromFmgIdIndex(fmgId);
if (indexedPath) {
INFO && console.log(`Found note in index: ${fmgId}${indexedPath}`);
try {
const content = await getNote(indexedPath);
const {frontmatter} = parseFrontmatter(content);
// Verify the fmg-id still matches (file might have been modified)
if (frontmatter["fmg-id"] === fmgId || frontmatter.fmgId === fmgId) {
return {
path: indexedPath,
name: indexedPath.replace(/\.md$/, "").split("/").pop(),
content,
frontmatter
};
} else {
// Index is stale, remove the entry
WARN && console.warn(`Index entry stale for ${fmgId}, removing`);
delete fmgIdIndex[fmgId];
saveFmgIdIndex();
}
} catch (error) {
// File no longer exists, remove from index
WARN && console.warn(`Indexed file not found: ${indexedPath}, removing from index`);
delete fmgIdIndex[fmgId];
saveFmgIdIndex();
}
}
// Not in index or index was stale, search all files
INFO && console.log(`Searching vault for fmg-id: ${fmgId}`);
const files = await getVaultFiles();
const mdFiles = files.filter(f => f.endsWith(".md"));
@ -356,6 +458,10 @@ const ObsidianBridge = (() => {
const {frontmatter} = parseFrontmatter(content);
if (frontmatter["fmg-id"] === fmgId || frontmatter.fmgId === fmgId) {
// Found it! Add to index for next time
addToFmgIdIndex(fmgId, filePath);
INFO && console.log(`Found note and added to index: ${fmgId}${filePath}`);
return {
path: filePath,
name: filePath.replace(/\.md$/, "").split("/").pop(),
@ -520,6 +626,7 @@ Add your lore here...
saveConfig,
testConnection,
getVaultFiles,
clearVaultCache,
getNote,
updateNote,
createNote,
@ -529,7 +636,9 @@ Add your lore here...
generateNoteTemplate,
searchNotes,
listAllNotes,
listAllNotePaths
listAllNotePaths,
addToFmgIdIndex,
getFromFmgIdIndex
};
})();

View file

@ -216,6 +216,13 @@ async function promptCreateNewNote(elementId, elementType, coordinates) {
const {frontmatter} = ObsidianBridge.parseFrontmatter(template);
// Add to FMG ID index for instant future lookups
const fmgId = frontmatter["fmg-id"] || frontmatter.fmgId;
if (fmgId) {
ObsidianBridge.addToFmgIdIndex(fmgId, notePath);
INFO && console.log(`New note added to index: ${fmgId}${notePath}`);
}
resolve({
path: notePath,
name,
@ -590,6 +597,17 @@ async function saveObsidianNote() {
try {
await ObsidianBridge.updateNote(path, content);
// Update the FMG ID index if this note has an fmg-id
if (elementId) {
const {frontmatter} = ObsidianBridge.parseFrontmatter(content);
const fmgId = frontmatter["fmg-id"] || frontmatter.fmgId;
if (fmgId) {
// Add to index using internal method
ObsidianBridge.addToFmgIdIndex(fmgId, path);
}
}
showMarkdownEditor.originalContent = content;
// Update the editor to show the new frontmatter
byId("obsidianMarkdownEditor").value = content;