From f28dc0140e415058bd505a68dd08ec076177fa72 Mon Sep 17 00:00:00 2001 From: viper151 Date: Mon, 14 Jul 2025 17:27:02 +0200 Subject: [PATCH] Add delete functionality for untracked files (#65) - Add delete button for untracked files in GitPanel - Implement deleteUntrackedFile function with confirmation dialog - Add /delete-untracked API endpoint to safely delete untracked files - Update confirmation modal to handle delete actions - Maintain consistent UI patterns with existing discard functionality --- server/routes/git.js | 35 ++++++++++++++++++++++ src/components/GitPanel.jsx | 60 +++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/server/routes/git.js b/server/routes/git.js index 2f29ec9..a4a3c53 100755 --- a/server/routes/git.js +++ b/server/routes/git.js @@ -692,4 +692,39 @@ router.post('/discard', async (req, res) => { } }); +// Delete untracked file +router.post('/delete-untracked', async (req, res) => { + const { project, file } = req.body; + + if (!project || !file) { + return res.status(400).json({ error: 'Project name and file path are required' }); + } + + try { + const projectPath = await getActualProjectPath(project); + await validateGitRepository(projectPath); + + // Check if file is actually untracked + const { stdout: statusOutput } = await execAsync(`git status --porcelain "${file}"`, { cwd: projectPath }); + + if (!statusOutput.trim()) { + return res.status(400).json({ error: 'File is not untracked or does not exist' }); + } + + const status = statusOutput.substring(0, 2); + + if (status !== '??') { + return res.status(400).json({ error: 'File is not untracked. Use discard for tracked files.' }); + } + + // Delete the untracked file + await fs.unlink(path.join(projectPath, file)); + + res.json({ success: true, message: `Untracked file ${file} deleted successfully` }); + } catch (error) { + console.error('Git delete untracked error:', error); + res.status(500).json({ error: error.message }); + } +}); + export default router; \ No newline at end of file diff --git a/src/components/GitPanel.jsx b/src/components/GitPanel.jsx index 207c199..8ad2062 100755 --- a/src/components/GitPanel.jsx +++ b/src/components/GitPanel.jsx @@ -294,6 +294,34 @@ function GitPanel({ selectedProject, isMobile }) { } }; + const deleteUntrackedFile = async (filePath) => { + try { + const response = await authenticatedFetch('/api/git/delete-untracked', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + project: selectedProject.name, + file: filePath + }) + }); + + const data = await response.json(); + if (data.success) { + // Remove from selected files and refresh status + setSelectedFiles(prev => { + const newSet = new Set(prev); + newSet.delete(filePath); + return newSet; + }); + fetchGitStatus(); + } else { + console.error('Delete failed:', data.error); + } + } catch (error) { + console.error('Error deleting untracked file:', error); + } + }; + const confirmAndExecute = async () => { if (!confirmAction) return; @@ -305,6 +333,9 @@ function GitPanel({ selectedProject, isMobile }) { case 'discard': await discardChanges(file); break; + case 'delete': + await deleteUntrackedFile(file); + break; case 'commit': await handleCommit(); break; @@ -578,6 +609,23 @@ function GitPanel({ selectedProject, isMobile }) { {isMobile && Discard} )} + {status === 'U' && ( + + )}

{confirmAction.type === 'discard' ? 'Discard Changes' : + confirmAction.type === 'delete' ? 'Delete File' : confirmAction.type === 'commit' ? 'Confirm Commit' : confirmAction.type === 'pull' ? 'Confirm Pull' : 'Confirm Push'}

@@ -1147,7 +1196,7 @@ function GitPanel({ selectedProject, isMobile }) {