How to embed download buttons in Tabulator

import panel as pn
import pandas as pd
from pathlib import Path

# Enable Panel extensions
pn.extension('tabulator')

class FileDownloadManager:
    def __init__(self):
        # Sample data
        self.data = pd.DataFrame({
            'id': [1, 2],
            'filename': ['report1.py', 'data.py'],  # Display names
            'size': ['2.3 MB', '1.1 MB'],
            'modified': ['2024-01-15', '2024-01-14'],
            'file_path': ['test.py', 'test_process_fix.py'],  # replace these
            'download': ['🔽 Download', '🔽 Download']  # Simple text buttons
        })
        
        self.setup_tabulator()
        
    def setup_tabulator(self):
        """Setup the Tabulator widget with click handling"""
        
        self.tabulator = pn.widgets.Tabulator(
            self.data,
            formatters={
                'download': {'type': 'html'}  # Allow HTML rendering
            },
            titles={
                'filename': 'File Name',
                'size': 'Size', 
                'modified': 'Last Modified',
                'download': 'Action'
            },
            widths={
                'filename': 200,
                'size': 100,
                'modified': 120,
                'download': 120
            },
            text_align={
                'download': 'center',
                'size': 'right'
            },
            pagination='remote',
            page_size=10,
            height=200,
            disabled=True,  # Prevent edits while allowing clicks
            hidden_columns=['id', 'file_path']  # Hide utility columns
        )
        
        # Handle clicks on the download column
        self.tabulator.on_click(self.handle_download_click)
    
    def handle_download_click(self, event):
        """Handle clicks on the download column"""
        if event.column == 'download':
            row_data = self.tabulator.value.iloc[event.row]
            file_id = row_data['id']
            filename = row_data['filename']
            file_path = row_data['file_path']
            
            print(f"Downloading file: {filename} (ID: {file_id})")
            
            # Get file content
            content = self.get_file_content(file_path, filename)
            
            # Create download using JavaScript
            self.trigger_download(filename, content)
    
    def get_file_content(self, file_path, filename):
        """Get file content, with fallback to dummy content"""
        try:
            # Try to read the actual file
            if Path(file_path).exists():
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                print(f"Successfully read file: {file_path}")
                return content
            else:
                print(f"File not found: {file_path}, using dummy content")
        except Exception as e:
            print(f"Error reading file {file_path}: {e}")
        
        # Fallback to dummy content
        return f"""# Content of {filename}
# This is a demo file

def main():
    print("Hello from {filename}")
    return "Demo content"

if __name__ == "__main__":
    main()
"""
    
    def trigger_download(self, filename, content):
        """Trigger file download using JavaScript"""
        # Escape content for JavaScript
        escaped_content = content.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
        
        js_code = f"""
        <script>
        (function() {{
            const content = "{escaped_content}";
            const blob = new Blob([content], {{type: 'text/plain'}});
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '{filename}';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url);
            console.log('Downloaded: {filename}');
        }})();
        </script>
        """
        
        # Update the status and trigger download
        self.status_pane.object = f"<div style='color: green; padding: 10px; background: #f0f8f0; border-radius: 4px;'>📁 Downloaded: <strong>{filename}</strong></div>" + js_code
    
    def create_layout(self):
        """Create the main layout"""
        
        # Status pane for download feedback
        self.status_pane = pn.pane.HTML("Click a download button to download a file.", width=800)
        
        return pn.Column(
            pn.pane.Markdown("## File Manager with Download Buttons"),
            pn.pane.Markdown("Click the **🔽 Download** button in any row to download the file."),
            self.tabulator,
            pn.pane.Markdown("### Status:"),
            self.status_pane,
            pn.pane.Markdown("""
            ### Features:
            - Table editing disabled (`disabled=True`)
            - Click-based download functionality  
            - Works with multiple clicks
            - Real file reading with fallback content
            """),
            width=800
        )

# Usage
file_manager = FileDownloadManager()
layout = file_manager.create_layout()
layout.show()