453 lines
11 KiB
Markdown
453 lines
11 KiB
Markdown
# 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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
createFolder(path: string): void {
|
|
// Create folder at the specified path
|
|
// Update file tree
|
|
// Emit change notification
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2. Rename Folder
|
|
|
|
**Current Implementation:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
duplicateFolder(sourcePath: string, destinationPath: string): void {
|
|
// Copy folder structure
|
|
// Copy all notes
|
|
// Update file tree
|
|
// Emit change notification
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 4. Create New Page
|
|
|
|
**Current Implementation:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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):**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:**
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
// 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:
|
|
|
|
```typescript
|
|
// 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`:
|
|
|
|
```typescript
|
|
// 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
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 documentation
|
|
- `CONTEXT_MENU_QUICK_START.md` - Quick start guide
|
|
- `src/services/vault.service.ts` - VaultService source code
|
|
- `src/components/file-explorer/file-explorer.component.ts` - Integration point
|
|
|
|
---
|
|
|
|
**Status**: ⏳ Ready for VaultService Integration
|
|
**Effort**: ~2-3 hours
|
|
**Difficulty**: Easy to Medium
|