diff options
| author | diogo464 <[email protected]> | 2025-08-13 11:08:48 +0100 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2025-08-13 11:08:48 +0100 |
| commit | 74069a896a3b831a19baefc0d9487060b34760b3 (patch) | |
| tree | 8398b24dd884d0b2e50dd1dcc7e7c758a5ba05fc | |
| parent | d3f54389f2ba0e70fef9b44a947cc0d9a8bb61e2 (diff) | |
Implement rename functionality using fctdrive CLI
- Add Drive_rename function to drive_server.ts for backend integration
- Create /api/rename endpoint with proper authentication and error handling
- Update handleRename function to call API instead of placeholder TODO
- Test rename functionality for both files and directories
- Update CLAUDE.md to note fctdrive is available in PATH
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
| -rw-r--r-- | CLAUDE.md | 1 | ||||
| -rw-r--r-- | frontend/app/api/rename/route.ts | 52 | ||||
| -rw-r--r-- | frontend/components/drive/DriveDirectoryClient.tsx | 51 | ||||
| -rw-r--r-- | frontend/lib/drive_server.ts | 11 |
4 files changed, 105 insertions, 10 deletions
| @@ -15,6 +15,7 @@ | |||
| 15 | - `just dev` - Start development servers (uses demon to run background processes) | 15 | - `just dev` - Start development servers (uses demon to run background processes) |
| 16 | - `just stop` - Stop development servers | 16 | - `just stop` - Stop development servers |
| 17 | - `just logs` - View logs | 17 | - `just logs` - View logs |
| 18 | - `fctdrive` - CLI tool is available in PATH | ||
| 18 | 19 | ||
| 19 | ## Current Implementation | 20 | ## Current Implementation |
| 20 | - Frontend directory: `frontend/` (note: frontend code is in frontend/ directory) | 21 | - Frontend directory: `frontend/` (note: frontend code is in frontend/ directory) |
diff --git a/frontend/app/api/rename/route.ts b/frontend/app/api/rename/route.ts new file mode 100644 index 0000000..1e2abb4 --- /dev/null +++ b/frontend/app/api/rename/route.ts | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | import { NextRequest, NextResponse } from 'next/server' | ||
| 2 | import { Auth_get_user } from '@/lib/auth' | ||
| 3 | import { Drive_rename } from '@/lib/drive_server' | ||
| 4 | |||
| 5 | // POST /api/rename - Rename a file or directory | ||
| 6 | export async function POST(request: NextRequest) { | ||
| 7 | try { | ||
| 8 | // Check user authentication | ||
| 9 | const user = await Auth_get_user() | ||
| 10 | if (!user.isLoggedIn) { | ||
| 11 | return NextResponse.json({ error: 'User not authenticated' }, { status: 401 }) | ||
| 12 | } | ||
| 13 | |||
| 14 | // Parse request body to get old and new paths | ||
| 15 | const body = await request.json() | ||
| 16 | const { oldPath, newPath } = body | ||
| 17 | |||
| 18 | if (!oldPath || typeof oldPath !== 'string' || oldPath.trim() === '') { | ||
| 19 | return NextResponse.json({ error: 'Invalid old path provided' }, { status: 400 }) | ||
| 20 | } | ||
| 21 | |||
| 22 | if (!newPath || typeof newPath !== 'string' || newPath.trim() === '') { | ||
| 23 | return NextResponse.json({ error: 'Invalid new path provided' }, { status: 400 }) | ||
| 24 | } | ||
| 25 | |||
| 26 | // Rename using Drive_rename | ||
| 27 | try { | ||
| 28 | await Drive_rename(oldPath.trim(), newPath.trim(), user.email) | ||
| 29 | |||
| 30 | return NextResponse.json({ | ||
| 31 | success: true, | ||
| 32 | message: `Successfully renamed "${oldPath}" to "${newPath}"` | ||
| 33 | }) | ||
| 34 | |||
| 35 | } catch (error) { | ||
| 36 | console.error(`Failed to rename ${oldPath} to ${newPath}:`, error) | ||
| 37 | return NextResponse.json( | ||
| 38 | { | ||
| 39 | error: error instanceof Error ? error.message : 'Failed to rename item' | ||
| 40 | }, | ||
| 41 | { status: 500 } | ||
| 42 | ) | ||
| 43 | } | ||
| 44 | |||
| 45 | } catch (error) { | ||
| 46 | console.error('Rename API error:', error) | ||
| 47 | return NextResponse.json( | ||
| 48 | { error: error instanceof Error ? error.message : 'Internal server error' }, | ||
| 49 | { status: 500 } | ||
| 50 | ) | ||
| 51 | } | ||
| 52 | } \ No newline at end of file | ||
diff --git a/frontend/components/drive/DriveDirectoryClient.tsx b/frontend/components/drive/DriveDirectoryClient.tsx index 8a53123..6089ec2 100644 --- a/frontend/components/drive/DriveDirectoryClient.tsx +++ b/frontend/components/drive/DriveDirectoryClient.tsx | |||
| @@ -134,18 +134,49 @@ export function DriveDirectoryClient({ path, files, breadcrumbs }: DriveDirector | |||
| 134 | }) | 134 | }) |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | const handleRename = () => { | 137 | const handleRename = async () => { |
| 138 | if (currentItem && newName.trim()) { | 138 | if (!currentItem || !newName.trim()) return |
| 139 | // TODO: Implement actual rename API call | 139 | |
| 140 | setRenameDialogOpen(false) | 140 | try { |
| 141 | setCurrentItem(null) | 141 | // Calculate the new full path by replacing the filename |
| 142 | setNewName("") | 142 | const pathParts = currentItem.path.split('/') |
| 143 | pathParts[pathParts.length - 1] = newName.trim() | ||
| 144 | const newPath = pathParts.join('/') | ||
| 145 | |||
| 146 | const response = await fetch('/api/rename', { | ||
| 147 | method: 'POST', | ||
| 148 | headers: { | ||
| 149 | 'Content-Type': 'application/json', | ||
| 150 | }, | ||
| 151 | body: JSON.stringify({ | ||
| 152 | oldPath: currentItem.path, | ||
| 153 | newPath: newPath | ||
| 154 | }) | ||
| 155 | }) | ||
| 156 | |||
| 157 | const result = await response.json() | ||
| 158 | |||
| 159 | if (response.ok) { | ||
| 160 | setRenameDialogOpen(false) | ||
| 161 | setCurrentItem(null) | ||
| 162 | setNewName("") | ||
| 163 | toast({ | ||
| 164 | title: "Renamed successfully", | ||
| 165 | description: result.message, | ||
| 166 | }) | ||
| 167 | |||
| 168 | // Refresh page to show changes | ||
| 169 | window.location.reload() | ||
| 170 | } else { | ||
| 171 | throw new Error(result.error || `Rename failed with status ${response.status}`) | ||
| 172 | } | ||
| 173 | } catch (error) { | ||
| 174 | console.error('Rename error:', error) | ||
| 143 | toast({ | 175 | toast({ |
| 144 | title: "Renamed successfully", | 176 | title: "Rename failed", |
| 145 | description: `Item renamed to "${newName.trim()}"`, | 177 | description: error instanceof Error ? error.message : 'Unknown error occurred', |
| 178 | variant: "destructive" | ||
| 146 | }) | 179 | }) |
| 147 | // Refresh page to show changes | ||
| 148 | window.location.reload() | ||
| 149 | } | 180 | } |
| 150 | } | 181 | } |
| 151 | 182 | ||
diff --git a/frontend/lib/drive_server.ts b/frontend/lib/drive_server.ts index 992a287..2a94fe9 100644 --- a/frontend/lib/drive_server.ts +++ b/frontend/lib/drive_server.ts | |||
| @@ -97,6 +97,17 @@ export async function Drive_mkdir(path: string, email: string) { | |||
| 97 | } | 97 | } |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /// renames a file or directory from old path to new path | ||
| 101 | export async function Drive_rename(oldPath: string, newPath: string, email: string) { | ||
| 102 | const result = spawnSync('fctdrive', ['rename', '--email', email, '--old', oldPath, '--new', newPath], { encoding: 'utf-8' }); | ||
| 103 | if (result.error) { | ||
| 104 | throw new Error(`Failed to execute fctdrive: ${result.error.message}`); | ||
| 105 | } | ||
| 106 | if (result.status !== 0) { | ||
| 107 | throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 100 | /// builds a filesystem tree from Drive_ls entries | 111 | /// builds a filesystem tree from Drive_ls entries |
| 101 | export async function Drive_tree(): Promise<DriveTreeResponse> { | 112 | export async function Drive_tree(): Promise<DriveTreeResponse> { |
| 102 | const entries = await Drive_ls('/', true); | 113 | const entries = await Drive_ls('/', true); |
