Last updated: Aug 12, 2025, 01:09 PM UTC

File Actions Implementation Instructions

Overview

This document provides instructions for implementing the backend download endpoint to support the new file actions column in the FileTree component.

Frontend Changes Completed

  1. Changed "Permissions" column header to "Actions"
  2. Added Phosphor icons: Download, Copy, Lock, Edit2
  3. Replaced permissions text with action buttons:
    • Lock/Edit2 icon for read-only vs writable files
    • Download button for files
    • Copy path button for all items
  4. Added handleDownload and handleCopyPath functions
  5. Updated api.js with downloadFile method

Backend Implementation Required

Download Endpoint

Create a new endpoint in the server to handle file downloads:

File: server/routes/files.js (if doesn't exist, create it)

import express from 'express';
import path from 'path';
import fs from 'fs';
import { authenticateToken } from '../middleware/auth.js';

const router = express.Router();

// Download file endpoint
router.get('/projects/:projectName/files/download', authenticateToken, async (req, res) => {
  try {
    const { projectName } = req.params;
    const { path: filePath } = req.query;
    
    if (!filePath) {
      return res.status(400).json({ error: 'File path is required' });
    }
    
    // Construct the full file path
    const projectsDir = process.env.PROJECTS_DIR || path.join(process.cwd(), 'projects');
    const fullPath = path.join(projectsDir, projectName, filePath);
    
    // Security: Ensure the path doesn't escape the project directory
    const resolvedPath = path.resolve(fullPath);
    const projectRoot = path.resolve(path.join(projectsDir, projectName));
    
    if (!resolvedPath.startsWith(projectRoot)) {
      return res.status(403).json({ error: 'Access denied' });
    }
    
    // Check if file exists
    if (!fs.existsSync(resolvedPath)) {
      return res.status(404).json({ error: 'File not found' });
    }
    
    // Check if it's a file (not a directory)
    const stats = fs.statSync(resolvedPath);
    if (!stats.isFile()) {
      return res.status(400).json({ error: 'Path is not a file' });
    }
    
    // Get the filename for the download
    const filename = path.basename(filePath);
    
    // Set appropriate headers
    res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
    res.setHeader('Content-Type', 'application/octet-stream');
    
    // Stream the file to the response
    const fileStream = fs.createReadStream(resolvedPath);
    fileStream.pipe(res);
    
    fileStream.on('error', (error) => {
      console.error('Error streaming file:', error);
      if (!res.headersSent) {
        res.status(500).json({ error: 'Error downloading file' });
      }
    });
    
  } catch (error) {
    console.error('Download error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

export default router;

Update server/index.js

Add the files router to the main server file:

// Add to imports at the top
import filesRoutes from './routes/files.js';

// Add after other route definitions (around line 280-290)
app.use('/api', filesRoutes);

Testing the Implementation

  1. Test Download Button:

    • Click download icon on various file types
    • Verify file downloads with correct name
    • Check that directories don't show download button
  2. Test Copy Path Button:

    • Click copy icon and paste to verify path
    • Ensure full project path is included
  3. Test Read/Write Indicators:

    • Verify Lock icon shows for read-only files
    • Verify Edit2 icon shows for writable files
    • Check that indicators only show for files, not directories
  4. Security Testing:

    • Try downloading files with path traversal attempts (../)
    • Verify only files within project directory are accessible

Future Enhancements

  1. Toast Notifications: Add feedback when copying path or download completes
  2. Batch Downloads: Allow selecting multiple files for download
  3. Preview Button: Quick preview without opening full editor
  4. Upload Progress: Show progress for large file uploads
  5. File Actions Context Menu: Right-click menu with more options

Notes

  • The download endpoint uses streaming to handle large files efficiently
  • Path security is critical - always validate paths don't escape project directory
  • Consider adding rate limiting for download endpoint to prevent abuse
  • The frontend already handles errors gracefully with console logging