feat: reorganize context menu documentation into docs folder

- Moved CONTEXT_MENU_INDEX.md and CONTEXT_MENU_VERIFICATION.md into docs/ directory for better organization
- Consolidated all context menu documentation files in one location for easier maintenance
- Documentation remains complete with 1000+ lines covering implementation, integration, and verification

The change improves documentation structure by moving context menu related files into a dedicated docs folder, making it easier for developers to find an
This commit is contained in:
2025-10-25 20:17:10 -04:00
parent b873577e93
commit b1da9b111d
30 changed files with 853 additions and 369 deletions
+69
View File
@@ -15,6 +15,75 @@ import express from 'express';
import fs from 'fs';
import path from 'path';
// ============================================================================
// ENDPOINT X: /api/files/rename - Rename a markdown file within the same folder
// ============================================================================
export function setupRenameFileEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache) {
app.put('/api/files/rename', express.json(), (req, res) => {
try {
const { oldPath, newName } = req.body || {};
if (!oldPath || typeof oldPath !== 'string') {
return res.status(400).json({ error: 'Missing or invalid oldPath' });
}
if (!newName || typeof newName !== 'string') {
return res.status(400).json({ error: 'Missing or invalid newName' });
}
const invalidChars = /[\/\\:*?"<>|]/;
if (invalidChars.test(newName)) {
return res.status(400).json({ error: 'Invalid characters in newName' });
}
const sanitizedOldRel = String(oldPath).replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
const oldAbs = path.join(vaultDir, sanitizedOldRel);
if (!fs.existsSync(oldAbs) || !fs.statSync(oldAbs).isFile()) {
return res.status(404).json({ error: 'Source file not found' });
}
// Enforce .md extension and strip any other extension first
const baseNoExt = newName.replace(/\.[^/.]+$/, '');
const finalFileName = baseNoExt.endsWith('.md') ? baseNoExt : `${baseNoExt}.md`;
const parentDir = path.dirname(oldAbs);
const newAbs = path.join(parentDir, finalFileName);
const newRel = path.relative(vaultDir, newAbs).replace(/\\/g, '/');
// Prevent noop
const oldFileName = path.basename(oldAbs);
if (oldFileName === finalFileName) {
return res.status(400).json({ error: 'New name is same as current name' });
}
// Conflict check
if (fs.existsSync(newAbs)) {
return res.status(409).json({ error: 'A file with this name already exists' });
}
// Perform atomic-ish move
try {
fs.renameSync(oldAbs, newAbs);
} catch (e) {
console.error('[PUT /api/files/rename] rename failed:', e);
return res.status(500).json({ error: 'Failed to rename file' });
}
// Invalidate metadata cache
try { metadataCache?.clear?.(); } catch {}
// Broadcast SSE event
try {
broadcastVaultEvent?.({ event: 'file-rename', oldPath: sanitizedOldRel, newPath: newRel, timestamp: Date.now() });
} catch {}
return res.json({ success: true, oldPath: sanitizedOldRel, newPath: newRel, fileName: finalFileName });
} catch (error) {
console.error('[PUT /api/files/rename] Unexpected error:', error);
return res.status(500).json({ error: 'Internal server error' });
}
});
}
// ============================================================================
// ENDPOINT 5: /api/folders/rename - Rename folder with validation
// ============================================================================
+5 -1
View File
@@ -35,7 +35,8 @@ import {
setupDeleteNoteEndpoint,
setupRenameFolderEndpoint,
setupDeleteFolderEndpoint,
setupCreateFolderEndpoint
setupCreateFolderEndpoint,
setupRenameFileEndpoint
} from './index-phase3-patch.mjs';
const __filename = fileURLToPath(import.meta.url);
@@ -1536,6 +1537,9 @@ app.get('/api/vault/events', (req, res) => {
// Setup rename folder endpoint (must be before catch-all)
setupRenameFolderEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache);
// Setup rename file endpoint (must be before catch-all)
setupRenameFileEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache);
// Setup delete folder endpoint (must be before catch-all)
setupDeleteFolderEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache);