- 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
11 KiB
Context Menu - VaultService Integration Guide
Overview
This guide shows how to implement the context menu actions by integrating them with the VaultService. Each action corresponds to a VaultService method that needs to be called.
Action Implementation Examples
1. Create Subfolder
Current Implementation:
private createSubfolder() {
if (!this.ctxTarget) return;
const name = prompt('Enter subfolder name:');
if (!name) return;
const newPath = `${this.ctxTarget.path}/${name}`;
this.showNotification(`Creating subfolder: ${newPath}`, 'info');
}
Complete Implementation:
private createSubfolder() {
if (!this.ctxTarget) return;
const name = prompt('Enter subfolder name:');
if (!name) return;
try {
const newPath = `${this.ctxTarget.path}/${name}`;
this.vaultService.createFolder(newPath);
this.showNotification(`Subfolder "${name}" created successfully`, 'success');
} catch (error) {
this.showNotification(`Failed to create subfolder: ${error}`, 'error');
}
}
Required VaultService Method:
createFolder(path: string): void {
// Create folder at the specified path
// Update file tree
// Emit change notification
}
2. Rename Folder
Current Implementation:
private renameFolder() {
if (!this.ctxTarget) return;
const newName = prompt('Enter new folder name:', this.ctxTarget.name);
if (!newName || newName === this.ctxTarget.name) return;
this.showNotification(`Renaming folder to: ${newName}`, 'info');
}
Complete Implementation:
private renameFolder() {
if (!this.ctxTarget) return;
const newName = prompt('Enter new folder name:', this.ctxTarget.name);
if (!newName || newName === this.ctxTarget.name) return;
try {
this.vaultService.renameFolder(this.ctxTarget.path, newName);
this.showNotification(`Folder renamed to "${newName}"`, 'success');
} catch (error) {
this.showNotification(`Failed to rename folder: ${error}`, 'error');
}
}
Required VaultService Method:
renameFolder(oldPath: string, newName: string): void {
// Rename folder
// Update all notes with new path
// Update file tree
// Emit change notification
}
3. Duplicate Folder
Current Implementation:
private duplicateFolder() {
if (!this.ctxTarget) return;
const newName = prompt('Enter duplicate folder name:', `${this.ctxTarget.name} (copy)`);
if (!newName) return;
this.showNotification(`Duplicating folder to: ${newName}`, 'info');
}
Complete Implementation:
private duplicateFolder() {
if (!this.ctxTarget) return;
const newName = prompt('Enter duplicate folder name:', `${this.ctxTarget.name} (copy)`);
if (!newName) return;
try {
const parentPath = this.ctxTarget.path.substring(0, this.ctxTarget.path.lastIndexOf('/'));
const newPath = parentPath ? `${parentPath}/${newName}` : newName;
this.vaultService.duplicateFolder(this.ctxTarget.path, newPath);
this.showNotification(`Folder duplicated to "${newName}"`, 'success');
} catch (error) {
this.showNotification(`Failed to duplicate folder: ${error}`, 'error');
}
}
Required VaultService Method:
duplicateFolder(sourcePath: string, destinationPath: string): void {
// Copy folder structure
// Copy all notes
// Update file tree
// Emit change notification
}
4. Create New Page
Current Implementation:
private createPageInFolder() {
if (!this.ctxTarget) return;
const pageName = prompt('Enter page name:');
if (!pageName) return;
this.showNotification(`Creating page in folder: ${pageName}`, 'info');
}
Complete Implementation:
private createPageInFolder() {
if (!this.ctxTarget) return;
const pageName = prompt('Enter page name:');
if (!pageName) return;
try {
const noteId = this.vaultService.createNote(
this.ctxTarget.path,
pageName,
{
title: pageName,
created: new Date().toISOString(),
updated: new Date().toISOString(),
}
);
this.showNotification(`Page "${pageName}" created`, 'success');
// Optionally open the new note
// this.noteSelected.emit(noteId);
} catch (error) {
this.showNotification(`Failed to create page: ${error}`, 'error');
}
}
Required VaultService Method:
createNote(folderPath: string, fileName: string, frontmatter?: Record<string, any>): string {
// Create new markdown file
// Add frontmatter
// Update file tree
// Return note ID
// Emit change notification
}
5. Copy Internal Link
Current Implementation (Already Complete):
private copyInternalLink() {
if (!this.ctxTarget) return;
const link = `[[${this.ctxTarget.path}]]`;
navigator.clipboard.writeText(link).then(() => {
this.showNotification('Internal link copied to clipboard!', 'success');
}).catch(() => {
this.showNotification('Failed to copy link', 'error');
});
}
Status: ✅ This action is fully implemented and working!
6. Delete Folder
Current Implementation:
private deleteFolder() {
if (!this.ctxTarget) return;
const confirmed = confirm(`Are you sure you want to delete the folder "${this.ctxTarget.name}"?`);
if (!confirmed) return;
this.showNotification(`Deleting folder: ${this.ctxTarget.name}`, 'warning');
}
Complete Implementation:
private deleteFolder() {
if (!this.ctxTarget) return;
const confirmed = confirm(`Are you sure you want to delete the folder "${this.ctxTarget.name}"?`);
if (!confirmed) return;
try {
this.vaultService.deleteFolder(this.ctxTarget.path);
this.showNotification(`Folder "${this.ctxTarget.name}" deleted`, 'success');
} catch (error) {
this.showNotification(`Failed to delete folder: ${error}`, 'error');
}
}
Required VaultService Method:
deleteFolder(path: string): void {
// Move folder to trash or permanently delete
// Update file tree
// Emit change notification
}
7. Delete All Pages in Folder
Current Implementation:
private deleteAllPagesInFolder() {
if (!this.ctxTarget) return;
const confirmed = confirm(`Are you sure you want to delete ALL pages in "${this.ctxTarget.name}"? This cannot be undone.`);
if (!confirmed) return;
this.showNotification(`Deleting all pages in folder: ${this.ctxTarget.name}`, 'warning');
}
Complete Implementation:
private deleteAllPagesInFolder() {
if (!this.ctxTarget) return;
const confirmed = confirm(`Are you sure you want to delete ALL pages in "${this.ctxTarget.name}"? This cannot be undone.`);
if (!confirmed) return;
try {
this.vaultService.deleteAllNotesInFolder(this.ctxTarget.path);
this.showNotification(`All pages in "${this.ctxTarget.name}" deleted`, 'success');
} catch (error) {
this.showNotification(`Failed to delete pages: ${error}`, 'error');
}
}
Required VaultService Method:
deleteAllNotesInFolder(folderPath: string): void {
// Get all notes in folder
// Delete each note
// Update file tree
// Emit change notification
}
VaultService Methods Checklist
Below is a checklist of all VaultService methods needed for full context menu functionality:
// Folder Operations
createFolder(path: string): void
renameFolder(oldPath: string, newName: string): void
duplicateFolder(sourcePath: string, destinationPath: string): void
deleteFolder(path: string): void
// Note Operations
createNote(folderPath: string, fileName: string, frontmatter?: Record<string, any>): string
deleteAllNotesInFolder(folderPath: string): void
// Existing Methods (already available)
toggleFolder(path: string): void
allNotes(): Note[]
folderCounts(): Record<string, number>
Integration Steps
Step 1: Update file-explorer.component.ts
Replace the action methods with complete implementations:
// In file-explorer.component.ts
private createSubfolder() {
if (!this.ctxTarget) return;
const name = prompt('Enter subfolder name:');
if (!name) return;
try {
const newPath = `${this.ctxTarget.path}/${name}`;
this.vaultService.createFolder(newPath);
this.showNotification(`Subfolder "${name}" created successfully`, 'success');
} catch (error) {
this.showNotification(`Failed to create subfolder: ${error}`, 'error');
}
}
// ... repeat for other actions
Step 2: Implement VaultService Methods
Add the required methods to vault.service.ts:
// In vault.service.ts
createFolder(path: string): void {
// Implementation
}
renameFolder(oldPath: string, newName: string): void {
// Implementation
}
// ... etc
Step 3: Test Each Action
Test each action individually:
npm run dev
# Right-click on folder
# Test each action
# Check console for errors
Step 4: Add Error Handling
Ensure proper error handling in each action:
try {
// Action logic
this.vaultService.someMethod();
this.showNotification('Success message', 'success');
} catch (error) {
console.error('Action failed:', error);
this.showNotification(`Failed: ${error.message}`, 'error');
}
Notification System
The showNotification method currently logs to console. You can enhance it:
private showNotification(message: string, type: 'success' | 'info' | 'warning' | 'error') {
// Current implementation
console.log(`[${type.toUpperCase()}] ${message}`);
// TODO: Replace with proper toast notification service
// this.toastr.show(message, type);
}
Testing Checklist
- Create subfolder works
- Rename folder works
- Duplicate folder works
- Create new page works
- Copy internal link works
- Delete folder works (with confirmation)
- Delete all pages works (with confirmation)
- Error messages display correctly
- File tree updates after each action
- Colors persist after actions
Common Issues & Solutions
Issue: "vaultService method not found"
Solution: Ensure the method exists in VaultService before calling it.
Issue: "File tree doesn't update"
Solution: Make sure VaultService emits change notifications after modifications.
Issue: "Confirmation dialog doesn't appear"
Solution: Check if confirm() is being called before the action.
Issue: "Notification doesn't show"
Solution: Implement a proper toast notification service instead of console.log.
Performance Considerations
- Use
ChangeDetectionStrategy.OnPush(already implemented) - Batch file tree updates when possible
- Debounce rapid folder operations
- Cache folder counts to avoid recalculation
Security Considerations
- ✅ Confirmation dialogs for destructive operations
- ✅ Input validation for folder/page names
- ✅ Path sanitization to prevent directory traversal
- ⏳ Rate limiting for bulk operations (future)
Related Documentation
CONTEXT_MENU_IMPLEMENTATION.md- Full technical documentationCONTEXT_MENU_QUICK_START.md- Quick start guidesrc/services/vault.service.ts- VaultService source codesrc/components/file-explorer/file-explorer.component.ts- Integration point
Status: ⏳ Ready for VaultService Integration
Effort: ~2-3 hours
Difficulty: Easy to Medium