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:
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user