<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hypha Workspace Management</title>
    <!-- External Scripts -->
    <script src="../assets/hypha-rpc-websocket.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.24.7/babel.min.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" />
    <script src="https://cdn.auth0.com/js/auth0-spa-js/2.0/auth0-spa-js.production.js"></script>
    <script src="https://rawcdn.githack.com/nextapps-de/winbox/0.2.82/dist/winbox.bundle.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.7.7/axios.min.js"></script>
    <!-- Favicon and Icons -->
    <link rel="apple-touch-icon" sizes="180x180" href="./static/img/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="./static/img/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="./static/img/favicon-16x16.png">
    <!-- Stylesheets -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.3.0/github-markdown-light.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;800&display=swap">
    <!-- Meta Tags -->
    <meta name="msapplication-TileColor" content="#da532c">
    <meta name="theme-color" content="#ffffff">
    <style>
        /* Styles for the sidebar and main content */
        .sidebar {
            width: 250px;
            position: fixed;
            top: 0;
            left: 0;
            height: 100%;
            background-color: #1f2937;
            padding-top: 20px;
            transition: all 0.3s;
        }

        .sidebar.collapsed {
            width: 60px;
        }

        .sidebar .logo {
            padding-left: 10px;
            text-align: center;
            margin-bottom: 1rem;
        }

        .sidebar .menu-item {
            padding: 1rem;
            color: white;
            cursor: pointer;
            display: flex;
            align-items: center;
            transition: background-color 0.3s;
        }

        .sidebar .menu-item:hover {
            background-color: #374151;
        }

        .sidebar.collapsed .menu-item span {
            display: none;
        }

        .main-content {
            padding: 20px;
            transition: all 0.3s;
        }

        .main-content.collapsed {
            margin-left: 60px;
        }

        .file-item {
            position: relative;
        }
        .file-item-buttons {
            opacity: 0;
            transition: opacity 0.2s ease;
        }
        .file-item:hover .file-item-buttons {
            opacity: 1;
        }
        
        /* Enhanced file card hover effects */
        .file-card {
            transition: all 0.2s ease;
        }
        
        .file-card:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        }
        
        .file-card.drag-over {
            background-color: #4a5568;
            border-color: #4299e1;
        }
        .border-blue-500 {
            border-color: #4299e1 !important;
            border-width: 2px !important;
        }
        .file-card.drag-over,
        .bg-gray-600.border-blue-500 {
            background-color: #4a5568 !important;
            border-color: #4299e1 !important;
            transform: scale(1.02);
        }

        /* Enhanced artifact dialog styles */
        .bg-gray-750 {
            background-color: #2a2f3a;
        }

        .group-open\:rotate-180 {
            transform: rotate(180deg);
        }

        /* Improved modal backdrop blur */
        .backdrop-blur-sm {
            backdrop-filter: blur(4px);
        }

        /* Smooth transitions for better UX */
        .transition-all {
            transition: all 0.3s ease;
        }

        /* Enhanced border radius for modern look */
        .rounded-xl {
            border-radius: 0.75rem;
        }

        /* Professional shadows */
        .shadow-2xl {
            box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
        }

        @media (max-width: 768px) {
            .sidebar {
                width: 60px;
            }

            .main-content {
                margin-left: 60px;
            }

            .sidebar .menu-item span {
                display: none;
            }
        }

        .service-card {
            background-color: #2d3748;
            border-radius: 0.5rem;
            padding: 1.5rem;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }

        .service-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.15);
        }

        .modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .modal-content {
            background-color: #1f2937;
            border-radius: 0.5rem;
            padding: 2rem;
            width: 90%;
            max-width: 600px;
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.3);
        }

        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 1rem;
        }

        .modal-body {
            max-height: 400px;
            overflow-y: auto;
        }
    </style>
</head>

<body class="bg-black text-white font-poppins">
    <div id="app"></div>
    <script type="module">
        import { HyphaCore } from "https://cdn.jsdelivr.net/npm/hypha-core@0.20.60/dist/hypha-core.mjs";

        const defaultService = {
            getServerConfig(context){
                let token;
                try{
                    token = document.cookie.split('; ').find(row => row.startsWith('access_token')).split('=')[1]
                }
                catch(e){
                    token = null;
                }
                // extract workspace from url
                // for example: http://127.0.0.1:9527/ws-user-github%7C478667#services => ws-user-github|478667
                const workspace = decodeURIComponent(window.location.href.split(window.location.origin)[1].split('/')[1].split("#")[0].split('?')[0]);
                return {
                    server_url: window.location.origin,
                    workspace,
                    token,
                    method_timeout: 120,
                }
            }
        }
        window.defaultService = defaultService;
        const hyphaCore = new HyphaCore({base_url: "/hypha-core-app/", default_service: defaultService});
        hyphaCore.on("add_window", (config) => {
            const root = document.getElementById("hypha-window-container");
            // get the left and top position of the root element
            // then set it to the WinBox
            const rect = root.getBoundingClientRect();

            const wb = new WinBox(config.name || config.src.slice(0, 128), {
                root: root,
                y: rect.top + 10,
                x: rect.left + 10,
                background: "#448aff",
            });
            wb.body.innerHTML = `<iframe src="${config.src}" id="${config.window_id}" style="width: 100%; height: 100%; border: none;"></iframe>`;
        });
        const api = await hyphaCore.start();

        console.log("Hypha core started:", hyphaCore.url);
        async function loadPluginFromUrl(url) {
            const plugin = await api.loadPlugin({ src: url});
            await plugin.run({ config: {}, data: {} });
            console.log("Loaded and ran plugin from URL:", url);
        }
        window.loadPlugin = loadPluginFromUrl;

                 window.loadCodeEditor = async function (ws, refreshApps) {
             if (!ws || !ws.getService) {
                 alert('WebSocket connection not ready. Please wait for the connection to be established.');
                 return;
             }
             
             const response = await fetch("/ws/code_template.hypha.html");
             const pythonPluginCode = await response.text();
             await api.createWindow({ 
                 name: "Code Editor",
                 src: "https://if.imjoy.io",
                config: {
                    fold: [1],
                    templates: [
                        {
                            name: "Basic JavaScript App",
                            url: window.location.origin + "/ws/code_template.hypha.html",
                            lang: 'javascript',
                        },
                        {
                            name: "JavaScript Test App", 
                            url: window.location.origin + "/ws/javascript_app_template.hypha.html",
                            lang: 'javascript',
                        },
                        {
                            name: "Python Test App",
                            url: window.location.origin + "/ws/python_app_template.hypha.html", 
                            lang: 'python',
                        },
                        {
                            name: "FastAPI Web App",
                            url: window.location.origin + "/ws/fastapi_app_template.hypha.html",
                            lang: 'python',
                        },
                        {
                            name: "MCP Server",
                            url: window.location.origin + "/ws/mcp_server_template.hypha.html",
                            lang: 'json',
                        },
                        {
                            name: "A2A Agent",
                            url: window.location.origin + "/ws/a2a_agent_template.hypha.html",
                            lang: 'json',
                        },
                        {
                            name: "ImageJ.JS Web App",
                            url: window.location.origin + "/ws/web_app_template.hypha.html",
                            lang: 'json',
                        },
                    ],
                    ui_elements: {
                         install: {
                             _rintf: true,
                             type: "button",
                             label: "Install Application",
                             visible: true,
                             icon: "file-download-outline",
                             callback: async (source, config) => {
                                 try {
                                     // Show progress spinner with logs
                                     window.showProgressSpinner('Installing Application...', { 
                                         showLogs: true,
                                         title: "Installing Application"
                                     });
                                     window.addProgressLog('Starting application installation...', 'info');
                                     
                                     if (!ws || !ws.getService) {
                                         throw new Error('WebSocket connection not ready');
                                     }
                                     
                                     window.addProgressLog('Connecting to server...', 'info');
                                     const controller = await ws.getService("public/server-apps");
                                     
                                     // Create progress callback
                                     const progressCallback = window.createProgressCallback();
                                     
                                     window.addProgressLog('Installing application...', 'info');
                                     const appInfo = await controller.install(source, {
                                         config: config,
                                         overwrite: true,
                                         progress_callback: progressCallback,
                                         _rkwargs: true
                                     });
                                     
                                     window.addProgressLog('Application installed successfully!', 'success');
                                     console.log("App installed successfully:", appInfo);
                                     
                                     window.updateProgressSpinner('Refreshing application list...');
                                     await refreshApps(ws);
                                     window.addProgressLog('Application list refreshed', 'info');
                                     
                                     // Allow user to close the dialog
                                     setTimeout(() => {
                                         window.enableProgressClose();
                                         window.updateProgressSpinner('Installation completed successfully!');
                                     }, 1000);
                                     
                                     return appInfo;
                                 } catch (error) {
                                     console.error("Failed to install app:", error);
                                     window.addProgressLog(`Installation failed: ${error.message}`, 'error');
                                     
                                     // Allow user to close after error
                                     window.enableProgressClose();
                                     window.updateProgressSpinner('Installation failed');
                                     
                                     throw error;
                                 }
                             }
                         }
                     }
                },  
                data: {
                    code: pythonPluginCode,
                }
            });
            console.log("Loaded and ran code editor plugin");
        };
    </script>

    <!-- Render the App component -->
    <script type="text/babel" data-presets="env,react" data-env-targets="defaults, safari >= 12">
        // Utility function to check if a file should be included based on hidden file settings
        const shouldIncludeFile = (fileName, includeHidden = false) => {
            if (includeHidden) return true;
            
            // Extract just the filename from path
            const name = fileName.split('/').pop();
            return !name.startsWith('.');
        };

        // Utility function to filter file list based on hidden file settings
        const filterFiles = (files, includeHidden = false) => {
            if (includeHidden) return files;
            
            return files.filter(file => {
                // For File objects from file input
                if (file instanceof File) {
                    // Check both the file name and any path components
                    const fileName = file.name;
                    const relativePath = file.webkitRelativePath || fileName;
                    
                    // Split path and check each component
                    const pathComponents = relativePath.split('/');
                    return pathComponents.every(component => !component.startsWith('.'));
                }
                
                // For other file objects, check the name property
                if (file.name) {
                    return shouldIncludeFile(file.name, includeHidden);
                }
                
                return true;
            });
        };

        const Sidebar = ({ isCollapsed, onToggle, setActivePanel, enabledPanels }) => {
            return (
                <div className={`sidebar ${isCollapsed ? 'collapsed' : ''}`}>
                    <div className="logo">
                        <a href="/"><img src="/static/img/hypha-logo-black.svg" className={`h-10 invert ${isCollapsed ? 'hidden' : 'block'}`} alt="Hypha Logo" /></a>
                    </div>
                    <div className="menu-item" onClick={() => onToggle()}>
                        <i className="fas fa-bars"></i>
                        <span className="ml-2">Menu</span>
                    </div>
                    <hr className="border-gray-700"></hr>
                    {enabledPanels.includes('dashboard') && (
                    <div className="menu-item" onClick={() => setActivePanel('dashboard')}>
                        <i className="fas fa-cogs"></i>
                        <span className="ml-2">Dashboard</span>
                    </div>
                    )}
                    {enabledPanels.includes('applications') && (
                    <div className="menu-item" onClick={() => setActivePanel('applications')}>
                        <i className="fas fa-th-large"></i>
                        <span className="ml-2">Applications</span>
                    </div>
                    )}
                    {enabledPanels.includes('files') && (
                    <div className="menu-item" onClick={() => setActivePanel('files')}>
                        <i className="fas fa-file-alt"></i>
                        <span className="ml-2">Files</span>
                    </div>
                    )}
                    {enabledPanels.includes('artifacts') && (
                    <div className="menu-item" onClick={() => setActivePanel('artifacts')}>
                        <i className="fas fa-file-alt"></i>
                        <span className="ml-2">Artifacts</span>
                    </div>
                    )}
                    {enabledPanels.includes('development') && (
                    <div className="menu-item" onClick={() => setActivePanel('development')}>
                        <i className="fas fa-code"></i>
                        <span className="ml-2">Development</span>
                    </div>
                    )}
                </div>
            );
        };

        const ClientCard = ({ client }) => {
            return (
                <div className="flex flex-col items-start p-6 bg-gray-800 rounded-lg shadow-lg mb-6 w-full">
                    <div className="flex items-center mb-4">
                        <i className="fas fa-users fa-3x text-white mr-4"></i>
                    </div>
                    <div className="text-gray-400 whitespace-pre-wrap break-words w-full">
                        <p className="mb-4">
                            <strong>Client ID:</strong> {client.id.split('/')[1]}
                        </p>
                        <p className="mb-4">
                            {client.user && (<strong>User:</strong>)} {client.user && client.user.id}
                        </p>
                        <p className="mb-4">
                            {client.user && (<strong>Email:</strong>)} {client.user && client.user.email}
                        </p>
                    </div>
                </div>
            );
        };        

        const ServiceCard = ({ service, onShowDetails, onBookmarkService }) => {
            return (
              <div className="relative flex flex-col items-start p-6 bg-gray-800 rounded-lg shadow-lg mb-6 w-full">
                {/* Bookmark icon in the upper right corner */}
                <button
                  class="absolute top-2 right-2 text-white"
                  onClick={() => onBookmarkService(service.id)}
                >
                  <i className="fas fa-bookmark"></i>
                </button>
          
                {/* Service information */}
                <div className="flex items-center mb-4">
                  <i className="fas fa-cog fa-3x text-white mr-4"></i>
                  <div>
                    <h3 className="text-xl font-bold whitespace-pre-wrap break-words">
                      {service.id.split(":")[1]}
                    </h3>
                    <p className="text-gray-400">Type: {service.type}</p>
                  </div>
                </div>
          
                <div className="text-gray-400 whitespace-pre-wrap break-words w-full">
                  <p className="mb-4">
                    <strong>ID:</strong> {service.id}
                  </p>
                  <p className="mb-4">
                    <strong>Visibility:</strong>
                    {service.config.visibility === 'public' ? (
                      <i className="fas fa-globe m-1 text-blue-500"></i>
                    ) : (
                      <i className="fas fa-lock m-1 text-red-500"></i>
                    )}
                    {service.config.visibility}
                  </p>
                  <p className="mb-4">{service.description}</p>
                </div>
          
                <button
                  className="mt-auto bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                  onClick={() => onShowDetails(service)}
                >
                  <i className="fas fa-info-circle mr-2"></i> View Details
                </button>
              </div>
            );
          };          
        

        const AppCard = ({ app, onUninstall, onShowDetails, onStart }) => {
            const [showServices, setShowServices] = React.useState(false);
            const [copiedServiceId, setCopiedServiceId] = React.useState('');
            const [isDisabled, setIsDisabled] = React.useState(app.disabled || false);
            const [isToggling, setIsToggling] = React.useState(false);
            
            const services = app.services || [];
            const serverUrl = window.location.origin;
            // For installed apps, we need to get the workspace from the current config
            const workspace = window.defaultService.getServerConfig().workspace;
            
            const copyServiceId = async (serviceId) => {
                try {
                    await navigator.clipboard.writeText(serviceId);
                    setCopiedServiceId(serviceId);
                    setTimeout(() => setCopiedServiceId(''), 2000);
                } catch (error) {
                    console.error('Failed to copy service ID:', error);
                    // Fallback for older browsers
                    const textArea = document.createElement('textarea');
                    textArea.value = serviceId;
                    document.body.appendChild(textArea);
                    textArea.select();
                    document.execCommand('copy');
                    document.body.removeChild(textArea);
                    setCopiedServiceId(serviceId);
                    setTimeout(() => setCopiedServiceId(''), 2000);
                }
            };

            const handleToggleDisabled = async () => {
                if (isToggling) return;
                
                setIsToggling(true);
                try {
                    window.showLoadingSpinner(isDisabled ? 'Enabling app...' : 'Disabling app...');
                    
                    if (!window.remoteServer) {
                        throw new Error('Server connection not ready');
                    }
                    
                    const controller = await window.remoteServer.getService('public/server-apps');
                    await controller.edit_app(app.id, { disabled: !isDisabled });
                    
                    // Update local state
                    setIsDisabled(!isDisabled);
                    
                    // Update the app object for future renders
                    app.disabled = !isDisabled;
                    
                } catch (error) {
                    console.error('Failed to toggle app status:', error);
                    alert(`Failed to ${isDisabled ? 'enable' : 'disable'} app: ${error.message}`);
                } finally {
                    setIsToggling(false);
                    window.hideLoadingSpinner();
                }
            };
            
            const getServiceUrl = (service) => {
                // For installed apps: [workspace]/apps/[service_id]@[app_id]/
 
                return `${serverUrl}/${workspace}/services/${service.id.split(":")[1]}@${app.id}`;
                
            };
            
            const getAppUrl = (service) => {
                // For ASGI apps, same URL as service URL
                return `${serverUrl}/${workspace}/apps/${service.id.split(":")[1]}@${app.id}/`;
            };
            
            return (
                <div className={`flex flex-col items-start p-6 rounded-lg shadow-lg mb-6 w-full transition-all duration-300 ${
                    isDisabled ? 'bg-gray-900 border-2 border-red-600 opacity-75' : 'bg-gray-800'
                }`}>
                    <div className="flex items-center mb-4 w-full">
                        <i className={`fas fa-th-large fa-3x text-white mr-4`}></i>
                        <div className="flex-1">
                            <div className="flex items-center justify-between mb-2">
                                <h3 className={`text-xl font-bold ${isDisabled ? 'text-gray-500' : 'text-white'}`}>
                                    {app.name || 'Untitled App'}
                                </h3>
                                <div className="flex items-center space-x-2">
                                    <span className={`text-sm ${isDisabled ? 'text-red-400' : 'text-green-400'}`}>
                                        {isDisabled ? 'Disabled' : 'Enabled'}
                                    </span>
                                    <label className="flex items-center cursor-pointer">
                                        <div className="relative">
                                            <input
                                                type="checkbox"
                                                className="sr-only"
                                                checked={!isDisabled}
                                                onChange={handleToggleDisabled}
                                                disabled={isToggling}
                                            />
                                            <div className={`block w-10 h-6 rounded-full transition-colors ${
                                                isDisabled ? 'bg-red-600' : 'bg-green-600'
                                            } ${isToggling ? 'opacity-50' : ''}`}></div>
                                            <div className={`dot absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform ${
                                                isDisabled ? 'transform translate-x-0' : 'transform translate-x-4'
                                            }`}></div>
                                        </div>
                                    </label>
                                </div>
                            </div>
                            <p className="text-gray-400 text-sm">App ID: <code className="bg-gray-700 px-1 rounded">{app.id}</code></p>
                            <p className={`mt-2 ${isDisabled ? 'text-gray-500' : 'text-gray-400'}`}>
                                {app.description || 'No description available'}
                            </p>
                            <div className="flex flex-wrap gap-2 mt-2">
                                <span className="bg-blue-600 text-white px-2 py-1 rounded text-xs">
                                    {app.type || 'Unknown'}
                                </span>
                                <span className="bg-gray-600 text-white px-2 py-1 rounded text-xs">
                                    v{app.version || '1.0.0'}
                                </span>
                                {app.daemon && (
                                    <span className="bg-green-600 text-white px-2 py-1 rounded text-xs">
                                        Daemon
                                    </span>
                                )}
                                {app.singleton && (
                                    <span className="bg-purple-600 text-white px-2 py-1 rounded text-xs">
                                        Singleton
                                    </span>
                                )}
                                {services.length > 0 && (
                                    <span className="bg-orange-600 text-white px-2 py-1 rounded text-xs">
                                        {services.length} Service{services.length > 1 ? 's' : ''}
                                    </span>
                                )}
                                {isDisabled && (
                                    <span className="bg-red-600 text-white px-2 py-1 rounded text-xs">
                                        <i className="fas fa-ban mr-1"></i> Disabled
                                    </span>
                                )}
                            </div>
                        </div>
                    </div>
                    
                    {/* Services Section */}
                    {services.length > 0 && (
                        <div className="w-full mb-4">
                            <button
                                className="flex items-center justify-between w-full bg-gray-700 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded transition duration-300"
                                onClick={() => setShowServices(!showServices)}
                            >
                                <span className="flex items-center">
                                    <i className="fas fa-cogs mr-2"></i> 
                                    Services ({services.length})
                                </span>
                                <i className={`fas fa-chevron-${showServices ? 'up' : 'down'}`}></i>
                            </button>
                            
                            {showServices && (
                                <div className="mt-2 space-y-2 max-h-64 overflow-y-auto">
                                    {services.map((service, index) => (
                                        <div key={index} className="bg-gray-700 p-3 rounded">
                                            <div className="flex items-center justify-between mb-2">
                                                <div className="flex items-center">
                                                    <i className="fas fa-cog mr-2 text-blue-400"></i>
                                                    <span className="font-medium text-white">{service.id.split('@')[0]}</span>
                                                </div>
                                                <div className="flex items-center space-x-2">
                                                    <span className={`px-2 py-1 rounded text-xs ${
                                                        service.config?.visibility === 'public' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
                                                    }`}>
                                                        {service.config?.visibility || 'protected'}
                                                    </span>
                                                    {service.type && (
                                                        <span className="bg-gray-600 text-white px-2 py-1 rounded text-xs">
                                                            {service.type}
                                                        </span>
                                                    )}
                                                </div>
                                            </div>
                                            
                                            <div className="text-sm text-gray-300 mb-2">
                                                <code className="bg-gray-800 px-1 rounded text-xs break-all">{service.id}</code>
                                            </div>
                                            
                                            <div className="flex flex-wrap gap-2">
                                                {/* Copy Service ID Button */}
                                                <button
                                                    onClick={() => copyServiceId(service.id)}
                                                    className={`text-xs px-2 py-1 rounded transition duration-300 ${
                                                        copiedServiceId === service.id
                                                            ? 'bg-green-600 hover:bg-green-500 text-white'
                                                            : 'bg-gray-600 hover:bg-gray-500 text-white'
                                                    }`}
                                                    title="Copy service ID"
                                                >
                                                    <i className={`fas ${copiedServiceId === service.id ? 'fa-check' : 'fa-copy'} mr-1`}></i>
                                                    {copiedServiceId === service.id ? 'Copied!' : 'Copy ID'}
                                                </button>
                                                
                                                {/* Service URL Link */}
                                                <a
                                                    href={getServiceUrl(service)}
                                                    target="_blank"
                                                    rel="noopener noreferrer"
                                                    className="text-xs bg-blue-600 hover:bg-blue-500 text-white px-2 py-1 rounded transition duration-300 flex items-center"
                                                    title="Open service URL"
                                                >
                                                    <i className="fas fa-external-link-alt mr-1"></i>
                                                    Service URL
                                                </a>
                                                
                                                {/* App URL Link for ASGI services */}
                                                {service.type === 'asgi' && (
                                                    <a
                                                        href={getAppUrl(service)}
                                                        target="_blank"
                                                        rel="noopener noreferrer"
                                                        className="text-xs bg-purple-600 hover:bg-purple-500 text-white px-2 py-1 rounded transition duration-300 flex items-center"
                                                        title="Open ASGI app"
                                                    >
                                                        <i className="fas fa-globe mr-1"></i>
                                                        Visit App
                                                    </a>
                                                )}
                                            </div>
                                        </div>
                                    ))}
                                </div>
                            )}
                        </div>
                    )}
                    
                    <div className="flex gap-2 w-full justify-end">
                        <button
                            className={`font-bold py-2 px-4 rounded transition duration-300 flex items-center ${
                                isDisabled 
                                    ? 'bg-gray-600 cursor-not-allowed text-gray-400' 
                                    : 'bg-green-600 hover:bg-green-500 text-white'
                            }`}
                            onClick={() => !isDisabled && onStart(app.id)}
                            disabled={isDisabled}
                            title={isDisabled ? 'App is disabled' : 'Start app'}
                        >
                            <i className={`fas ${isDisabled ? 'fa-ban' : 'fa-play'} mr-2`}></i> 
                            {isDisabled ? 'Disabled' : 'Start'}
                        </button>
                        <button
                            className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                            onClick={() => onShowDetails(app)}
                        >
                            <i className="fas fa-info-circle mr-2"></i> More
                        </button>
                        <button
                            className="bg-red-600 hover:bg-red-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                            onClick={() => onUninstall(app.id)}
                        >
                            <i className="fas fa-trash mr-2"></i> Uninstall
                        </button>
                    </div>
                </div>
            );
        };

        const RunningAppCard = ({ app, onStop, onShowDetails, onTakeScreenshot }) => {
            const [showServices, setShowServices] = React.useState(false);
            const [copiedServiceId, setCopiedServiceId] = React.useState('');
            
            const services = app.services || [];
            const serverUrl = window.location.origin;
            const workspace = app.workspace;
            
            const copyServiceId = async (serviceId) => {
                try {
                    await navigator.clipboard.writeText(serviceId);
                    setCopiedServiceId(serviceId);
                    setTimeout(() => setCopiedServiceId(''), 2000);
                } catch (error) {
                    console.error('Failed to copy service ID:', error);
                    // Fallback for older browsers
                    const textArea = document.createElement('textarea');
                    textArea.value = serviceId;
                    document.body.appendChild(textArea);
                    textArea.select();
                    document.execCommand('copy');
                    document.body.removeChild(textArea);
                    setCopiedServiceId(serviceId);
                    setTimeout(() => setCopiedServiceId(''), 2000);
                }
            };
            
            const getServiceUrl = (service) => {
                // For running apps: [workspace]/apps/[client_id]:[service_id]/
                const serviceName = service.id.split('@')[0];
                
                return `${serverUrl}/${workspace}/services/${serviceName.split("/")[1]}`;
                
            };
            
            const getAppUrl = (service) => {
                return `${serverUrl}/${workspace}/apps/${service.id.split("/")[1]}/`;
            };
            
            return (
                <div className="flex flex-col items-start p-6 bg-gray-800 rounded-lg shadow-lg mb-6 w-full">
                    <div className="flex items-center mb-4 w-full">
                        <i className={`fas fa-play-circle fa-3x text-green-400 mr-4`}></i>
                        <div className="flex-1">
                            <h3 className="text-xl font-bold">{app.name || 'Untitled App'}</h3>
                            <p className="text-gray-400 text-sm">Session ID: <code className="bg-gray-700 px-1 rounded">{app.id}</code></p>
                            <p className="text-gray-400 text-sm">App ID: <code className="bg-gray-700 px-1 rounded">{app.app_id}</code></p>
                            <p className="text-gray-400 mt-2">{app.description || 'No description available'}</p>
                            <div className="flex flex-wrap gap-2 mt-2">
                                <span className="bg-green-600 text-white px-2 py-1 rounded text-xs">
                                    <i className="fas fa-play mr-1"></i> Running
                                </span>
                                <span className="bg-blue-600 text-white px-2 py-1 rounded text-xs">
                                    Workspace: {app.workspace}
                                </span>
                                {app.service_id && (
                                    <span className="bg-purple-600 text-white px-2 py-1 rounded text-xs">
                                        Service: {app.service_id.split('@')[0]}
                                    </span>
                                )}
                                {services.length > 0 && (
                                    <span className="bg-orange-600 text-white px-2 py-1 rounded text-xs">
                                        {services.length} Service{services.length > 1 ? 's' : ''}
                                    </span>
                                )}
                            </div>
                        </div>
                    </div>
                    
                    {/* Services Section */}
                    {services.length > 0 && (
                        <div className="w-full mb-4">
                            <button
                                className="flex items-center justify-between w-full bg-gray-700 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded transition duration-300"
                                onClick={() => setShowServices(!showServices)}
                            >
                                <span className="flex items-center">
                                    <i className="fas fa-cogs mr-2"></i> 
                                    Services ({services.length})
                                </span>
                                <i className={`fas fa-chevron-${showServices ? 'up' : 'down'}`}></i>
                            </button>
                            
                            {showServices && (
                                <div className="mt-2 space-y-2 max-h-64 overflow-y-auto">
                                    {services.map((service, index) => (
                                        <div key={index} className="bg-gray-700 p-3 rounded">
                                            <div className="flex items-center justify-between mb-2">
                                                <div className="flex items-center">
                                                    <i className="fas fa-cog mr-2 text-blue-400"></i>
                                                    <span className="font-medium text-white">{service.id.split('@')[0]}</span>
                                                </div>
                                                <div className="flex items-center space-x-2">
                                                    <span className={`px-2 py-1 rounded text-xs ${
                                                        service.config?.visibility === 'public' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'
                                                    }`}>
                                                        {service.config?.visibility || 'protected'}
                                                    </span>
                                                    {service.type && (
                                                        <span className="bg-gray-600 text-white px-2 py-1 rounded text-xs">
                                                            {service.type}
                                                        </span>
                                                    )}
                                                </div>
                                            </div>
                                            
                                            <div className="text-sm text-gray-300 mb-2">
                                                <code className="bg-gray-800 px-1 rounded text-xs break-all">{service.id}</code>
                                            </div>
                                            
                                            <div className="flex flex-wrap gap-2">
                                                {/* Copy Service ID Button */}
                                                <button
                                                    onClick={() => copyServiceId(service.id)}
                                                    className={`text-xs px-2 py-1 rounded transition duration-300 ${
                                                        copiedServiceId === service.id
                                                            ? 'bg-green-600 hover:bg-green-500 text-white'
                                                            : 'bg-gray-600 hover:bg-gray-500 text-white'
                                                    }`}
                                                    title="Copy service ID"
                                                >
                                                    <i className={`fas ${copiedServiceId === service.id ? 'fa-check' : 'fa-copy'} mr-1`}></i>
                                                    {copiedServiceId === service.id ? 'Copied!' : 'Copy ID'}
                                                </button>
                                                
                                                {/* Service URL Link */}
                                                <a
                                                    href={getServiceUrl(service)}
                                                    target="_blank"
                                                    rel="noopener noreferrer"
                                                    className="text-xs bg-blue-600 hover:bg-blue-500 text-white px-2 py-1 rounded transition duration-300 flex items-center"
                                                    title="Open service URL"
                                                >
                                                    <i className="fas fa-external-link-alt mr-1"></i>
                                                    Service URL
                                                </a>
                                                
                                                {/* App URL Link for ASGI services */}
                                                {service.type === 'asgi' && (
                                                    <a
                                                        href={getAppUrl(service)}
                                                        target="_blank"
                                                        rel="noopener noreferrer"
                                                        className="text-xs bg-purple-600 hover:bg-purple-500 text-white px-2 py-1 rounded transition duration-300 flex items-center"
                                                        title="Open ASGI app"
                                                    >
                                                        <i className="fas fa-globe mr-1"></i>
                                                        Visit App
                                                    </a>
                                                )}
                                            </div>
                                        </div>
                                    ))}
                                </div>
                            )}
                        </div>
                    )}
                    
                    <div className="flex gap-2 w-full justify-end">
                        {(app.app_type === 'window' || app.app_type === 'iframe' || app.app_type === 'web-app') && (
                            <button
                                className="bg-yellow-600 hover:bg-yellow-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                                onClick={() => onTakeScreenshot(app.id, app.name || 'Untitled App')}
                                title="Take screenshot of the running app"
                            >
                                <i className="fas fa-camera mr-2"></i> Screen
                            </button>
                        )}
                        <button
                            className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                            onClick={() => onShowDetails(app)}
                        >
                            <i className="fas fa-info-circle mr-2"></i> More
                        </button>
                        <button
                            className="bg-red-600 hover:bg-red-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                            onClick={() => onStop(app.id)}
                        >
                            <i className="fas fa-stop mr-2"></i> Stop
                        </button>
                    </div>
                </div>
            );
        };

        const FileCard = ({
            file,
            onDownload,
            onDelete,
            onToggle,
            isExpanded,
            isLoading,
            children,
            fullPath,
            onUploadToFolder,
            onCreateFolder,
            onDragOver,
            onDragEnter,
            onDragLeave,
            onDrop,
            onUploadFolderToPath,
        }) => {
            const isDirectory = file.type === 'directory';
            const [isHovered, setIsHovered] = React.useState(false);
            
            return (
                <div 
                    className="file-card flex flex-col justify-between items-start p-3 bg-gray-700 shadow-md transition-colors duration-200"
                    onDragOver={isDirectory ? onDragOver : undefined}
                    onDragEnter={isDirectory ? onDragEnter : undefined}
                    onDragLeave={isDirectory ? onDragLeave : undefined}
                    onDrop={isDirectory ? (e) => onDrop(e, fullPath) : undefined}
                    onMouseEnter={() => setIsHovered(true)}
                    onMouseLeave={() => setIsHovered(false)}
                >
                    <div className="file-item flex items-center w-full justify-between relative">
                        <div className="flex items-center">
                            {isDirectory && (
                                <button 
                                    className="mr-2 min-w-[20px] text-center" 
                                    onClick={() => onToggle(fullPath)} 
                                    disabled={isLoading}
                                    style={{ opacity: isLoading ? 0.7 : 1 }}
                                >
                                    {isLoading ? (
                                        <i className="fas fa-spinner fa-spin text-blue-400"></i>
                                    ) : (
                                        isExpanded ? '-' : '+'
                                    )}
                                </button>
                            )}
                            <i className={`fas ${isDirectory ? 'fa-folder' : 'fa-file-alt'} mr-2`}></i>
                            <span className="flex-1">
                                {file.name}
                                {isDirectory && isHovered && (
                                    <span className="text-xs text-gray-400 ml-2">(drop files/folders here)</span>
                                )}
                            </span>
                        </div>
                        <div className="file-item-buttons">
                            {isDirectory ? (
                                <>
                                <button
                                    className="bg-green-600 hover:bg-green-500 text-white font-bold py-1 px-2 rounded-full transition duration-300 mr-1"
                                    onClick={() => onUploadToFolder(fullPath)}
                                    title="Upload files to this folder"
                                >
                                    <i className="fas fa-upload"></i>
                                </button>
                                <button
                                    className="bg-purple-600 hover:bg-purple-500 text-white font-bold py-1 px-2 rounded-full transition duration-300 mr-1"
                                    onClick={() => onUploadFolderToPath(fullPath)}
                                    title="Upload folder to this folder"
                                >
                                    <i className="fas fa-folder-open"></i>
                                </button>
                                <button
                                    className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-1 px-2 rounded-full transition duration-300 mr-1"
                                    onClick={() => onCreateFolder(fullPath)}
                                    title="Create subfolder"
                                >
                                    <i className="fas fa-folder-plus"></i>
                                </button>
                                <button
                                    className="bg-red-600 hover:bg-red-500 text-white font-bold py-1 px-2 rounded-full transition duration-300"
                                    onClick={() => onDelete(fullPath, file.type)}
                                    title="Delete folder"
                                >
                                    <i className="fas fa-trash"></i>
                                </button>
                                </>
                            ) : (
                                <>
                                <button
                                    className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-full transition duration-300"
                                    onClick={() => onDownload(fullPath)}
                                    title="Download file"
                                >
                                    <i className="fas fa-download"></i>
                                </button>
                                <button
                                    className="bg-red-600 hover:bg-red-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 ml-2"
                                    onClick={() => onDelete(fullPath, file.type)}
                                    title="Delete file"
                                >
                                    <i className="fas fa-trash"></i>
                                </button>
                                </>
                            )}
                            
                        </div>
                    </div>
                    {isExpanded && <div className="w-full mt-3 ml-3">{children}</div>}
                </div>
            );
        };        
        
        const FileTree = ({
            files,
            onDownload,
            onDelete,
            listFiles,
            expandedDirs,
            setExpandedDirs,
            parentPath = "",
            onUploadToFolder,
            onCreateFolder,
            onDragOver,
            onDragEnter,
            onDragLeave,
            onDrop,
            onUploadFolderToPath,
        }) => {
            const [loadingDirs, setLoadingDirs] = React.useState({});
            
            const handleToggle = async (fullPath) => {
                const isExpanded = !!expandedDirs[fullPath];
                if (isExpanded) {
                    setExpandedDirs({ ...expandedDirs, [fullPath]: null });
                } else {
                    // Set loading state immediately
                    setLoadingDirs({ ...loadingDirs, [fullPath]: true });
                    
                    try {
                        const children = await listFiles(fullPath);
                        setExpandedDirs({ ...expandedDirs, [fullPath]: children });
                    } catch (error) {
                        console.error("Error loading directory:", error);
                    } finally {
                        // Clear loading state
                        setLoadingDirs({ ...loadingDirs, [fullPath]: false });
                    }
                }
            };
        
            return (
                <div>
                    {files.map((file) => {
                        const fullPath = parentPath ? `${parentPath}/${file.name}` : file.name;
                        return (
                            <FileCard
                                key={`${fullPath}-${file.type}`} // Ensure key is unique
                                file={file}
                                onDownload={onDownload}
                                onDelete={onDelete}
                                isExpanded={!!expandedDirs[fullPath]}
                                isLoading={!!loadingDirs[fullPath]}
                                onToggle={handleToggle}
                                fullPath={fullPath}
                                onUploadToFolder={onUploadToFolder}
                                onCreateFolder={onCreateFolder}
                                onDragOver={onDragOver}
                                onDragEnter={onDragEnter}
                                onDragLeave={onDragLeave}
                                onDrop={onDrop}
                                onUploadFolderToPath={onUploadFolderToPath}
                            >
                                {expandedDirs[fullPath] && (
                                    <FileTree
                                        files={expandedDirs[fullPath]}
                                        onDownload={onDownload}
                                        onDelete={onDelete}
                                        listFiles={listFiles}
                                        expandedDirs={expandedDirs}
                                        setExpandedDirs={setExpandedDirs}
                                        parentPath={fullPath}
                                        onUploadToFolder={onUploadToFolder}
                                        onCreateFolder={onCreateFolder}
                                        onDragOver={onDragOver}
                                        onDragEnter={onDragEnter}
                                        onDragLeave={onDragLeave}
                                        onDrop={onDrop}
                                        onUploadFolderToPath={onUploadFolderToPath}
                                    />
                                )}
                            </FileCard>
                        );
                    })}
                </div>
            );
        };                    

        const Modal = ({ serviceInfo, onClose }) => {
            return (
                <div className="modal">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">Service Details</h2>
                            <button onClick={onClose} className="text-white text-2xl">&times;</button>
                        </div>
                        <div className="modal-body">
                            <pre className="whitespace-pre-wrap text-gray-200">
                                {JSON.stringify(serviceInfo, null, 2)}
                            </pre>
                        </div>
                    </div>
                </div>
            );
        };

        const SpinnerOverlay = ({ isVisible, message = "Loading...", showLogs = false, logs = [], onClose = null, closeEnabled = false, title = "Operation Progress", retryAction = null, includeHiddenFiles = false, onIncludeHiddenFilesChange = null }) => {
            const [isExpanded, setIsExpanded] = React.useState(false);
            
            if (!isVisible) return null;
            
            return (
                <div className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 min-w-[300px]">
                    <div className={`bg-gray-800 rounded-lg p-6 flex flex-col relative min-w-[300px] ${showLogs ? 'max-w-4xl' : 'items-center'}`}>
                        {/* Close X button in upper right corner - always visible */}
                        {onClose && (
                            <button 
                                onClick={onClose}
                                className="absolute top-4 right-4 text-gray-400 hover:text-white text-2xl leading-none z-10"
                                title="Close"
                            >
                                ×
                            </button>
                        )}
                        
                        {/* Header */}
                        {showLogs && (
                            <div className="mb-6 pr-8">
                                <h2 className="text-xl font-bold text-white">{title}</h2>
                            </div>
                        )}
                        
                        {/* Loading section - centered */}
                        <div className="flex flex-col items-center mb-6">
                            {!closeEnabled && (
                                <div className="animate-spin rounded-full h-16 w-16 border-b-2 border-white mb-4"></div>
                            )}
                            {closeEnabled && (
                                <div className="flex items-center justify-center h-16 w-16 mb-4">
                                    <i className={`fas fa-2x ${message.includes('failed') || message.includes('Error') ? 'fa-times-circle text-red-400' : 'fa-check-circle text-green-400'}`}></i>
                                </div>
                            )}
                            <p className="text-white text-lg font-medium text-center">{message}</p>
                            {!closeEnabled && (
                                <p className="text-gray-400 text-sm mt-2">Please wait...</p>
                            )}
                        </div>
                        
                        {/* File Upload Settings - only shown during file uploads */}
                        {showLogs && onIncludeHiddenFilesChange && (
                            <div className="w-full mb-4 p-3 bg-gray-700 rounded-lg border border-gray-600">
                                <div className="flex items-center">
                                    <input
                                        type="checkbox"
                                        id="includeHiddenFiles"
                                        checked={includeHiddenFiles}
                                        onChange={(e) => onIncludeHiddenFilesChange(e.target.checked)}
                                        className="mr-3 w-4 h-4 text-blue-600 bg-gray-800 border-gray-600 rounded focus:ring-blue-500 focus:ring-2"
                                    />
                                    <label htmlFor="includeHiddenFiles" className="text-white text-sm font-medium cursor-pointer">
                                        Include hidden files (.DS_Store, .gitignore, etc.)
                                    </label>
                                </div>
                                <p className="text-gray-400 text-xs mt-1 ml-7">
                                    Uncheck to ignore files and folders starting with "." during upload
                                </p>
                            </div>
                        )}
                        
                        {/* Log window section - below spinner */}
                        {showLogs && (
                            <div className="w-full mb-6">
                                <div className="flex items-center justify-between mb-2">
                                    <h3 className="text-white font-medium">Progress Log</h3>
                                    <button
                                        onClick={() => setIsExpanded(!isExpanded)}
                                        className="text-gray-400 hover:text-white text-sm"
                                    >
                                        {isExpanded ? 'Collapse' : 'Expand'}
                                    </button>
                                </div>
                                <div className={`bg-gray-900 rounded border border-gray-700 p-3 font-mono text-sm overflow-y-auto ${
                                    isExpanded ? 'h-96' : 'h-32'
                                }`}>
                                    {logs.length === 0 ? (
                                        <div className="text-gray-500 italic">Waiting for progress updates...</div>
                                    ) : (
                                        logs.map((log, index) => (
                                            <div key={index} className="mb-1 text-gray-300">
                                                <span className="text-gray-500 mr-2">
                                                    {new Date(log.timestamp).toLocaleTimeString()}
                                                </span>
                                                <span className={`whitespace-pre-wrap ${
                                                    log.type === 'error' ? 'text-red-400' : 
                                                      log.type === 'warning' ? 'text-yellow-400' :
                                                      log.type === 'success' ? 'text-green-400' : 'text-gray-300'
                                                }`}>
                                                    {log.message}
                                                </span>
                                            </div>
                                        ))
                                    )}
                                    {/* Auto-scroll to bottom */}
                                    {logs.length > 0 && (
                                        <div ref={el => el?.scrollIntoView({ behavior: 'smooth' })} />
                                    )}
                                </div>
                            </div>
                        )}
                        
                        {/* Action buttons at bottom */}
                        {(onClose && showLogs) && (
                            <div className="flex justify-center gap-3">
                                {retryAction && (
                                    <button
                                        onClick={retryAction}
                                        className="px-6 py-2 rounded-lg font-medium bg-orange-600 hover:bg-orange-500 text-white cursor-pointer transition-all duration-300"
                                        title="Retry failed uploads"
                                    >
                                        <i className="fas fa-redo mr-2"></i>
                                        Retry Failed
                                    </button>
                                )}
                                <button
                                    onClick={closeEnabled ? onClose : undefined}
                                    disabled={!closeEnabled}
                                    className={`px-6 py-2 rounded-lg font-medium transition-all duration-300 ${
                                        closeEnabled 
                                            ? 'bg-blue-600 hover:bg-blue-500 text-white cursor-pointer' 
                                            : 'bg-gray-600 text-gray-400 cursor-not-allowed opacity-50'
                                    }`}
                                    title={closeEnabled ? "Close dialog" : "Please wait for operation to complete"}
                                >
                                    {closeEnabled ? 'OK' : 'Please wait...'}
                                </button>
                            </div>
                        )}
                    </div>
                </div>
            );
        };

        const AppDetailsModal = ({ app, onClose }) => {
            return (
                <div className="modal">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">App Details</h2>
                            <button onClick={onClose} className="text-white text-2xl">&times;</button>
                        </div>
                        <div className="modal-body">
                            <pre className="whitespace-pre-wrap text-gray-200 max-h-96 overflow-y-auto">
                                {JSON.stringify(app, null, 2)}
                            </pre>
                        </div>
                    </div>
                </div>
            );
        };

        const ScreenshotDialog = ({ screenshotData, sessionId, appName, onClose, onRefresh, onAutoScreenshot }) => {
            const [copied, setCopied] = React.useState(false);
            const [autoScreenshot, setAutoScreenshot] = React.useState(false);
            const [autoScreenshotInterval, setAutoScreenshotInterval] = React.useState(null);

            // Handle auto screenshot toggle
            const handleAutoScreenshotToggle = (enabled) => {
                setAutoScreenshot(enabled);
                if (enabled) {
                    // Start auto screenshot every 0.5 seconds
                    const interval = setInterval(() => {
                        if (onRefresh) {
                            onRefresh();
                        }
                    }, 500);
                    setAutoScreenshotInterval(interval);
                } else {
                    // Stop auto screenshot
                    if (autoScreenshotInterval) {
                        clearInterval(autoScreenshotInterval);
                        setAutoScreenshotInterval(null);
                    }
                }
            };

            // Cleanup interval on unmount
            React.useEffect(() => {
                return () => {
                    if (autoScreenshotInterval) {
                        clearInterval(autoScreenshotInterval);
                    }
                };
            }, [autoScreenshotInterval]);

            const copyScreenshotUrl = async () => {
                try {
                    const dataUrl = `data:image/png;base64,${screenshotData}`;
                    await navigator.clipboard.writeText(dataUrl);
                    setCopied(true);
                    setTimeout(() => setCopied(false), 2000);
                } catch (error) {
                    console.error('Failed to copy screenshot URL:', error);
                    // Fallback for older browsers
                    const textArea = document.createElement('textarea');
                    textArea.value = `data:image/png;base64,${screenshotData}`;
                    document.body.appendChild(textArea);
                    textArea.select();
                    document.execCommand('copy');
                    document.body.removeChild(textArea);
                    setCopied(true);
                    setTimeout(() => setCopied(false), 2000);
                }
            };

            const downloadScreenshot = () => {
                const link = document.createElement('a');
                link.href = `data:image/png;base64,${screenshotData}`;
                link.download = `screenshot-${appName || sessionId}-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.png`;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            };

            const handleRefresh = () => {
                if (onRefresh) {
                    onRefresh();
                }
            };

            return (
                <div className="modal">
                    <div className="modal-content" style={{ maxWidth: '95vw', maxHeight: '95vh', width: '90vw' }}>
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">{appName || 'Screenshot'}</h2>
                            <button onClick={onClose} className="text-white text-2xl">&times;</button>
                        </div>
                        <div className="modal-body" style={{ maxHeight: '80vh', overflow: 'auto' }}>
                            <div className="flex flex-col items-center space-y-4">
                                {/* Screenshot image - much larger */}
                                <img 
                                    src={`data:image/png;base64,${screenshotData}`} 
                                    alt={`Screenshot of ${appName || sessionId}`}
                                    className="max-w-full max-h-[70vh] object-contain border border-gray-600 rounded-lg shadow-lg"
                                    style={{ minHeight: '400px' }}
                                />
                                
                                {/* Action buttons */}
                                <div className="flex gap-2 items-center">
                                    <button
                                        onClick={downloadScreenshot}
                                        className="bg-green-600 hover:bg-green-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                                    >
                                        <i className="fas fa-download mr-2"></i> Download
                                    </button>
                                    <button
                                        onClick={copyScreenshotUrl}
                                        className={`font-bold py-2 px-4 rounded transition duration-300 flex items-center ${
                                            copied 
                                                ? 'bg-green-600 hover:bg-green-500 text-white' 
                                                : 'bg-blue-600 hover:bg-blue-500 text-white'
                                        }`}
                                    >
                                        <i className={`fas ${copied ? 'fa-check' : 'fa-copy'} mr-2`}></i>
                                        {copied ? 'Copied!' : 'Copy URL'}
                                    </button>
                                    <button
                                        onClick={handleRefresh}
                                        className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                                        disabled={autoScreenshot}
                                    >
                                        <i className="fas fa-sync-alt mr-2"></i> Refresh
                                    </button>
                                    <div className="flex items-center gap-2 bg-gray-800 px-4 py-2 rounded-full border border-gray-600">
                                        <input
                                            type="checkbox"
                                            id="autoScreenshot"
                                            checked={autoScreenshot}
                                            onChange={(e) => handleAutoScreenshotToggle(e.target.checked)}
                                            className="w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2"
                                        />
                                        <label htmlFor="autoScreenshot" className="text-sm text-gray-300 cursor-pointer">
                                            Auto Screenshot (0.5s)
                                        </label>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            );
        };

        const EnvManagementPanel = ({ ws }) => {
            const [envVars, setEnvVars] = React.useState({});
            const [showEnvVars, setShowEnvVars] = React.useState(false);
            const [newEnvKey, setNewEnvKey] = React.useState('');
            const [newEnvValue, setNewEnvValue] = React.useState('');
            const [loading, setLoading] = React.useState(false);
            const [visibleValues, setVisibleValues] = React.useState({});
            const [copiedKeys, setCopiedKeys] = React.useState({});

            const fetchEnvVars = async () => {
                if (!ws) return;
                try {
                    setLoading(true);
                    const allEnvs = await ws.getEnv();
                    setEnvVars(allEnvs || {});
                } catch (error) {
                    console.error('Failed to fetch environment variables:', error);
                    alert(`Failed to fetch environment variables: ${error}`);
                } finally {
                    setLoading(false);
                }
            };

            React.useEffect(() => {
                if (showEnvVars) {
                    fetchEnvVars();
                }
            }, [showEnvVars, ws]);

            const handleAddEnvVar = async () => {
                if (!newEnvKey.trim()) {
                    alert('Please enter a valid environment variable name');
                    return;
                }
                
                try {
                    window.showLoadingSpinner('Adding Environment Variable...');
                    setLoading(true);
                    await ws.setEnv(newEnvKey.trim(), newEnvValue);
                    setNewEnvKey('');
                    setNewEnvValue('');
                    await fetchEnvVars();
                } catch (error) {
                    console.error('Failed to set environment variable:', error);
                    alert(`Failed to set environment variable: ${error}`);
                } finally {
                    setLoading(false);
                    window.hideLoadingSpinner();
                }
            };

            const handleRemoveEnvVar = async (key) => {
                if (!confirm(`Are you sure you want to remove the environment variable "${key}"?`)) {
                    return;
                }
                
                try {
                    window.showLoadingSpinner('Removing Environment Variable...');
                    setLoading(true);
                    await ws.setEnv({key, value: null, _rkwargs: true});
                    await fetchEnvVars();
                } catch (error) {
                    console.error('Failed to remove environment variable:', error);
                    alert(`Failed to remove environment variable: ${error}`);
                } finally {
                    setLoading(false);
                    window.hideLoadingSpinner();
                }
            };

            const toggleValueVisibility = (key) => {
                setVisibleValues(prev => ({
                    ...prev,
                    [key]: !prev[key]
                }));
            };

            const copyEnvVar = async (key, value) => {
                const envString = `${key}="${value}"`;
                try {
                    await navigator.clipboard.writeText(envString);
                    // Show copied feedback
                    setCopiedKeys(prev => ({ ...prev, [key]: true }));
                    setTimeout(() => {
                        setCopiedKeys(prev => ({ ...prev, [key]: false }));
                    }, 2000);
                } catch (error) {
                    console.error('Failed to copy to clipboard:', error);
                    // Fallback for older browsers
                    const textArea = document.createElement('textarea');
                    textArea.value = envString;
                    document.body.appendChild(textArea);
                    textArea.select();
                    document.execCommand('copy');
                    document.body.removeChild(textArea);
                    // Show copied feedback for fallback too
                    setCopiedKeys(prev => ({ ...prev, [key]: true }));
                    setTimeout(() => {
                        setCopiedKeys(prev => ({ ...prev, [key]: false }));
                    }, 2000);
                }
            };

            return (
                <div className="main-content">
                    <p className="text-xl text-gray-400 mt-4">
                        Manage environment variables shared across all clients in this workspace
                    </p>
                    
                    <button
                        className={`mt-4 font-bold py-2 px-4 rounded-full transition duration-300 flex items-center ${
                            showEnvVars 
                                ? 'bg-red-600 hover:bg-red-500 text-white' 
                                : 'bg-blue-600 hover:bg-blue-500 text-white'
                        }`}
                        onClick={() => setShowEnvVars(!showEnvVars)}
                        disabled={loading}
                    >
                        <i className={`fas ${showEnvVars ? 'fa-eye-slash' : 'fa-eye'} mr-2`}></i>
                        {showEnvVars ? 'Hide' : 'Show'} Environment Variables
                    </button>

                    {showEnvVars && (
                        <div className="mt-6 p-6 bg-gray-800 rounded-lg shadow-lg">
                            {/* Add new environment variable */}
                            <div className="mb-4 p-3 bg-gray-700 rounded-lg">
                                <h3 className="text-lg font-bold mb-3 text-white">Add New Environment Variable</h3>
                                <div className="flex flex-col md:flex-row gap-3">
                                    <div className="flex-1">
                                        <label className="block text-sm font-medium text-gray-300 mb-1">
                                            Variable Name
                                        </label>
                                        <input
                                            type="text"
                                            value={newEnvKey}
                                            onChange={(e) => setNewEnvKey(e.target.value)}
                                            placeholder="e.g., API_KEY"
                                            className="w-full px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white"
                                            disabled={loading}
                                        />
                                    </div>
                                    <div className="flex-1">
                                        <label className="block text-sm font-medium text-gray-300 mb-1">
                                            Value
                                        </label>
                                        <input
                                            type="text"
                                            value={newEnvValue}
                                            onChange={(e) => setNewEnvValue(e.target.value)}
                                            placeholder="Variable value"
                                            className="w-full px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white"
                                            disabled={loading}
                                        />
                                    </div>
                                    <div className="flex items-end">
                                        <button
                                            onClick={handleAddEnvVar}
                                            disabled={loading || !newEnvKey.trim()}
                                            className="w-full md:w-auto bg-green-600 hover:bg-green-500 disabled:bg-gray-600 text-white font-bold py-2 px-4 rounded transition duration-300"
                                        >
                                            {loading ? 'Adding...' : 'Add Variable'}
                                        </button>
                                    </div>
                                </div>
                            </div>

                            {/* Current environment variables */}
                            <div>
                                <h3 className="text-lg font-bold mb-4 text-white">Current Environment Variables</h3>
                                {loading ? (
                                    <div className="text-center py-4">
                                        <i className="fas fa-spinner fa-spin text-2xl text-gray-400"></i>
                                        <p className="text-gray-400 mt-2">Loading environment variables...</p>
                                    </div>
                                ) : Object.keys(envVars).length === 0 ? (
                                    <div className="text-center py-8 text-gray-400">
                                        <i className="fas fa-inbox text-4xl mb-4"></i>
                                        <p>No environment variables set</p>
                                    </div>
                                ) : (
                                                                         <div className="space-y-3">
                                        {Object.entries(envVars).map(([key, value]) => (
                                            <div
                                                key={key}
                                                className="flex items-center justify-between p-3 bg-gray-700 rounded-lg hover:bg-gray-600 transition duration-300"
                                            >
                                                <div className="flex-1 min-w-0">
                                                    <div className="flex items-center space-x-3">
                                                        <span className="font-mono text-sm bg-gray-800 px-2 py-1 rounded text-green-400">
                                                            {key}
                                                        </span>
                                                        <span className="text-gray-300">=</span>
                                                        <span className="font-mono text-sm text-gray-300 truncate">
                                                            {visibleValues[key] 
                                                                ? (typeof value === 'string' && value.length > 50 
                                                                    ? `${value.substring(0, 50)}...` 
                                                                    : String(value))
                                                                : '****'
                                                            }
                                                        </span>
                                                    </div>
                                                </div>
                                                <div className="flex items-center space-x-2">
                                                    <button
                                                        onClick={() => toggleValueVisibility(key)}
                                                        className="bg-gray-600 hover:bg-gray-500 text-white font-bold py-1 px-3 rounded transition duration-300 flex items-center"
                                                        title={visibleValues[key] ? 'Hide value' : 'Show value'}
                                                    >
                                                        <i className={`fas ${visibleValues[key] ? 'fa-eye-slash' : 'fa-eye'}`}></i>
                                                    </button>
                                                    <button
                                                        onClick={() => copyEnvVar(key, value)}
                                                        className={`font-bold py-1 px-3 rounded transition duration-300 flex items-center ${
                                                            copiedKeys[key] 
                                                                ? 'bg-green-600 hover:bg-green-500 text-white' 
                                                                : 'bg-blue-600 hover:bg-blue-500 text-white'
                                                        }`}
                                                        title={copiedKeys[key] ? 'Copied!' : `Copy ${key}="${value}"`}
                                                    >
                                                        <i className={`fas ${copiedKeys[key] ? 'fa-check' : 'fa-copy'}`}></i>
                                                    </button>
                                                    <button
                                                        onClick={() => handleRemoveEnvVar(key)}
                                                        disabled={loading}
                                                        className="bg-red-600 hover:bg-red-500 disabled:bg-gray-600 text-white font-bold py-1 px-3 rounded transition duration-300 flex items-center"
                                                        title={`Remove ${key}`}
                                                    >
                                                        <i className="fas fa-times"></i>
                                                    </button>
                                                </div>
                                            </div>
                                        ))}
                                    </div>
                                )}
                            </div>

                            {/* Info box */}
                            <div className="mt-6 p-4 bg-blue-900 bg-opacity-30 border border-blue-700 rounded-lg">
                                <div className="flex items-start">
                                    <i className="fas fa-info-circle text-blue-400 mr-3 mt-1"></i>
                                    <div className="text-sm text-blue-200">
                                        <p className="font-medium mb-1">About Environment Variables:</p>
                                        <ul className="list-disc list-inside space-y-1 text-blue-300">
                                            <li>Environment variables are shared across all clients in this workspace</li>
                                            <li>They are stored securely and persist between sessions</li>
                                            <li>Use them to store API keys, configuration values, or other shared data</li>
                                            <li>Removing a variable sets its value to null</li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </div>
                    )}
                </div>
            );
        };

        const TokenPanel = ({ workspaceId, onGenerateToken }) => {
            const [workspace, setWorkspace] = React.useState(workspaceId);
            const [expiryTime, setExpiryTime] = React.useState(3600);
            const [clientId, setClientId] = React.useState(null);
            const [permission, setPermission] = React.useState('read_write');
            const [extraScopes, setExtraScopes] = React.useState([]);
            const [newScope, setNewScope] = React.useState('');
            const [generatedToken, setGeneratedToken] = React.useState('');
            const [showSnackBar, setShowSnackBar] = React.useState(false);

            const handleGenerateToken = async () => {
                try {
                    const token = await onGenerateToken(workspace, expiryTime, clientId, permission, extraScopes);
                    setGeneratedToken(token);
                } catch (error) {
                    console.error("Failed to generate token:", error);
                    alert("Failed to generate token. Please try again later.");
                }
            };

            const addExtraScope = () => {
                if (newScope.trim() && !extraScopes.includes(newScope.trim())) {
                    setExtraScopes([...extraScopes, newScope.trim()]);
                    setNewScope('');
                }
            };

            const removeExtraScope = (index) => {
                setExtraScopes(extraScopes.filter((_, i) => i !== index));
            };

            const handleNewScopeKeyPress = (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    addExtraScope();
                }
            };
        
            const handleCopyToken = () => {
                navigator.clipboard.writeText(generatedToken);
                setShowSnackBar(true);
                setTimeout(() => setShowSnackBar(false), 2000); // Snack bar disappears after 2 seconds
            };
        
            return (
                <div className="main-content">
                    <div className="mt-4">
                        <label htmlFor="workspace" className="block text-sm font-medium text-gray-300">
                            Workspace Name
                        </label>
                        <input
                            type="text"
                            id="workspace"
                            name="workspace"
                            className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                            value={workspace}
                            onChange={(e) => setWorkspace(e.target.value)}
                        />
                    </div>
                    <div className="mt-4">
                        <label htmlFor="permission" className="block text-sm font-medium text-gray-300">
                            Permission Level
                            <p className="text-gray-500 text-xs mt-1">
                                Permission level for the workspace: read, read_write, or admin.
                            </p>
                        </label>
                        <select
                            id="permission"
                            name="permission"
                            className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                            value={permission}
                            onChange={(e) => setPermission(e.target.value)}
                        >
                            <option value="read">Read Only</option>
                            <option value="read_write">Read & Write</option>
                            <option value="admin">Admin</option>
                        </select>
                    </div>
                    <div className="mt-4">
                        <label htmlFor="expiry-time" className="block text-sm font-medium text-gray-300">
                            Expiry Time (seconds)
                        </label>
                        <input
                            type="number"
                            id="expiry-time"
                            name="expiry-time"
                            className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                            placeholder="3600"
                            value={expiryTime}
                            onChange={(e) => setExpiryTime(e.target.value)}
                        />
                    </div>
                    <div className="mt-4">
                        <label htmlFor="client-id" className="block text-sm font-medium text-gray-300">
                            Client ID (Optional)
                            <p className="text-gray-500 text-xs mt-1">
                                If specified, this token can only be used by the client with this ID. Leave empty for unrestricted access.
                            </p>
                        </label>
                        <input
                            type="text"
                            id="client-id"
                            name="client-id"
                            className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                            placeholder="e.g., my-app-client"
                            value={clientId || ''}
                            onChange={(e) => setClientId(e.target.value.trim() === '' ? null : e.target.value)}
                        />
                    </div>
                    <div className="mt-4">
                        <label className="block text-sm font-medium text-gray-300">
                            Extra Scopes (Optional)
                            <p className="text-gray-500 text-xs mt-1">
                                Additional scopes for specialized access, e.g., "dataset:read", "model:write".
                            </p>
                        </label>
                        <div className="mt-2 flex gap-2">
                            <input
                                type="text"
                                className="text-black flex-1 px-3 py-2 border border-gray-300 rounded-md"
                                placeholder="e.g., dataset:read"
                                value={newScope}
                                onChange={(e) => setNewScope(e.target.value)}
                                onKeyPress={handleNewScopeKeyPress}
                            />
                            <button
                                type="button"
                                className="bg-green-500 hover:bg-green-600 text-white px-3 py-2 rounded-md transition duration-200"
                                onClick={addExtraScope}
                                disabled={!newScope.trim()}
                            >
                                +
                            </button>
                        </div>
                        {extraScopes.length > 0 && (
                            <div className="mt-2 flex flex-wrap gap-2">
                                {extraScopes.map((scope, index) => (
                                    <span
                                        key={index}
                                        className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800"
                                    >
                                        {scope}
                                        <button
                                            type="button"
                                            className="ml-1 text-blue-600 hover:text-blue-800"
                                            onClick={() => removeExtraScope(index)}
                                        >
                                            <i className="fas fa-times"></i>
                                        </button>
                                    </span>
                                ))}
                            </div>
                        )}
                    </div>
                    <div className="mt-4">
                        <button
                            className="bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded transition duration-200"
                            onClick={handleGenerateToken}
                        >
                            Generate Token
                        </button>
                    </div>
                    {generatedToken && (
                        <div className="mt-4">
                            <h3 className="text-lg font-bold">Generated Token:</h3>
                            <pre className="text-black bg-gray-200 p-4 rounded break-words whitespace-pre-wrap max-h-48 overflow-y-auto">
                                {generatedToken}
                            </pre>
                            <button 
                                className="bg-gray-500 text-white py-1 px-4 rounded mt-2" 
                                onClick={handleCopyToken}
                            >
                                Copy Token
                            </button>
                        </div>
                    )}
                    {showSnackBar && (
                        <div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 bg-green-500 text-white py-2 px-4 rounded shadow-md">
                            Token copied to clipboard!
                        </div>
                    )}
                </div>
            );
        };
        // Enhanced Artifact Card with better file management UI
        const ArtifactCard = ({
            artifact,
            onToggle,
            isExpanded,
            children,
            fullPath,
            onMoreInfo,
            onDelete,
            onUploadFile,
            onCreateFolder,
            onCreateChildArtifact,
            onDragOver,
            onDragEnter, 
            onDragLeave,
            onDrop,
            isLoading
        }) => {
            const isCollection = artifact.type === "collection";
            const [isHovered, setIsHovered] = React.useState(false);
        
            return (
                <div 
                    className="artifact-card flex flex-col justify-between items-start p-3 bg-gray-700 shadow-md transition-colors duration-200"
                    onDragOver={isCollection ? onDragOver : undefined}
                    onDragEnter={isCollection ? onDragEnter : undefined}
                    onDragLeave={isCollection ? onDragLeave : undefined}
                    onDrop={isCollection ? (e) => onDrop(e, fullPath) : undefined}
                    onMouseEnter={() => setIsHovered(true)}
                    onMouseLeave={() => setIsHovered(false)}
                >
                    <div className="artifact-item flex items-center w-full justify-between relative">
                        <div className="flex items-center p-6 bg-gray-800 rounded-lg shadow-lg mb-6 w-full">
                            {isCollection && (
                                <button 
                                    className="mr-2 min-w-[20px] text-center" 
                                    onClick={() => onToggle(fullPath)}
                                    disabled={isLoading}
                                    style={{ opacity: isLoading ? 0.7 : 1 }}
                                >
                                    {isLoading ? (
                                        <i className="fas fa-spinner fa-spin text-blue-400"></i>
                                    ) : (
                                        isExpanded ? "-" : "+"
                                    )}
                                </button>
                            )}
                            <i
                                className={`fas ${
                                    isCollection ? "fa-folder" : "fa-file-alt"
                                } mr-2`}
                            ></i>
                            <div className="w-full overflow-hidden">
                                <h4 className="text-xl font-bold truncate">{artifact.manifest?.name || artifact.id}</h4>
                                <p className="text-gray-400 truncate">{artifact.manifest?.description || "No description"}</p>
                                <p className="text-gray-400">Type: {artifact.type}</p>
                                <code className="text-gray-400 text-xs break-all">
                                    ID: {artifact.id}
                                </code>
                                {/* Action buttons */}
                                <div className="flex justify-between items-center w-full mt-3">
                                    <div className="flex gap-2">
                                        <button
                                            className="bg-blue-500 hover:bg-blue-400 text-white font-bold py-1 px-3 rounded text-sm transition duration-300"
                                            onClick={() => onMoreInfo(artifact)}
                                        >
                                            <i className="fas fa-info-circle mr-1"></i> More Info
                                        </button>
                                        {isCollection && (
                                            <button
                                                className="bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-1 px-3 rounded text-sm transition duration-300"
                                                onClick={() => onCreateChildArtifact(artifact.id)}
                                                title="Create child artifact in this collection"
                                            >
                                                <i className="fas fa-plus"></i>
                                            </button>
                                        )}
                                    </div>
                                        <button
                                        className="bg-red-500 hover:bg-red-400 text-white font-bold py-1 px-3 rounded text-sm transition duration-300"
                                            onClick={() => onDelete(artifact.id)}
                                        >
                                        <i className="fas fa-trash mr-1"></i> Delete
                                        </button>
                                    </div>
                                </div>                                
                            </div>
                    </div>
                    {isExpanded && <div className="w-full mt-3 ml-3">{children}</div>}
                </div>
            );
        };
        
        // Enhanced Artifact Tree with drag & drop and loading states
        const ArtifactTree = ({
            artifacts,
            onToggle,
            expandedArtifacts,
            setExpandedArtifacts,
            parentPath = "",
            listArtifacts,
            onMoreInfo,
            onDelete,
            onUploadFile,
            onCreateFolder,
            onCreateChildArtifact,
            onDragOver,
            onDragEnter,
            onDragLeave,
            onDrop
        }) => {
            const [loadingArtifacts, setLoadingArtifacts] = React.useState({});
            
            const handleToggle = async (fullPath) => {
                const isExpanded = !!expandedArtifacts[fullPath];
                if (isExpanded) {
                    setExpandedArtifacts({ ...expandedArtifacts, [fullPath]: null });
                } else {
                    // Set loading state immediately
                    setLoadingArtifacts({ ...loadingArtifacts, [fullPath]: true });
                    
                    try {
                    const children = await listArtifacts(fullPath);
                    setExpandedArtifacts({ ...expandedArtifacts, [fullPath]: children });
                    } catch (error) {
                        console.error("Error loading artifact children:", error);
                    } finally {
                        // Clear loading state
                        setLoadingArtifacts({ ...loadingArtifacts, [fullPath]: false });
                    }
                }
            };
        
            return (
                <div>
                    {artifacts.map((artifact) => {
                        const fullPath = parentPath
                            ? `${parentPath}/${artifact.id}`
                            : artifact.id;
                        return (
                            <ArtifactCard
                                key={`${fullPath}-${artifact.type}`}
                                artifact={artifact}
                                onToggle={handleToggle}
                                isExpanded={!!expandedArtifacts[fullPath]}
                                isLoading={!!loadingArtifacts[fullPath]}
                                fullPath={fullPath}
                                onMoreInfo={onMoreInfo}
                                onDelete={(id) => onDelete(id, parentPath || null)} // Pass parent ID to onDelete
                                onUploadFile={onUploadFile}
                                onCreateFolder={onCreateFolder}
                                onCreateChildArtifact={onCreateChildArtifact}
                                onDragOver={onDragOver}
                                onDragEnter={onDragEnter}
                                onDragLeave={onDragLeave}
                                onDrop={onDrop}
                            >
                                {expandedArtifacts[fullPath] && (
                                    <ArtifactTree
                                        artifacts={expandedArtifacts[fullPath]}
                                        onToggle={onToggle}
                                        expandedArtifacts={expandedArtifacts}
                                        setExpandedArtifacts={setExpandedArtifacts}
                                        parentPath={fullPath}
                                        listArtifacts={listArtifacts}
                                        onMoreInfo={onMoreInfo}
                                        onDelete={onDelete}
                                        onUploadFile={onUploadFile}
                                        onCreateFolder={onCreateFolder}
                                        onCreateChildArtifact={onCreateChildArtifact}
                                        onDragOver={onDragOver}
                                        onDragEnter={onDragEnter}
                                        onDragLeave={onDragLeave}
                                        onDrop={onDrop}
                                    />
                                )}
                            </ArtifactCard>
                        );
                    })}
                </div>
            );
        };
        
        // Enhanced Artifact File Card component for file tree
        const ArtifactFileCard = ({
            file,
            onDownload,
            onDelete,
            onToggle,
            isExpanded,
            isLoading,
            children,
            fullPath,
            onUploadToFolder,
            onCreateFolder,
            onDragOver,
            onDragEnter,
            onDragLeave,
            onDrop,
            onUploadFolderToPath,
            canUpload = true
        }) => {
            const isDirectory = file.type === 'directory';
            const [isHovered, setIsHovered] = React.useState(false);
            
            return (
                <div 
                    className={`border border-gray-600 rounded-lg bg-gray-750 hover:bg-gray-700 transition-all duration-200 ${
                        isDirectory ? 'border-blue-400 bg-blue-900 bg-opacity-20' : ''
                    }`}
                    onDragOver={isDirectory ? onDragOver : undefined}
                    onDragEnter={isDirectory ? onDragEnter : undefined}
                    onDragLeave={isDirectory ? onDragLeave : undefined}
                    onDrop={isDirectory ? (e) => onDrop(e, fullPath) : undefined}
                    onMouseEnter={() => setIsHovered(true)}
                    onMouseLeave={() => setIsHovered(false)}
                >
                    <div className="file-item flex items-center justify-between p-3">
                        <div className="flex items-center flex-1 min-w-0">
                            {isDirectory && (
                                <button 
                                    className="mr-3 w-6 h-6 flex items-center justify-center bg-gray-600 hover:bg-gray-500 rounded transition duration-200" 
                                    onClick={() => onToggle(fullPath)} 
                                    disabled={isLoading}
                                >
                                    {isLoading ? (
                                        <i className="fas fa-spinner fa-spin text-blue-400 text-xs"></i>
                                    ) : (
                                        <i className={`fas ${isExpanded ? 'fa-chevron-down' : 'fa-chevron-right'} text-xs text-gray-300`}></i>
                                    )}
                                </button>
                            )}
                            <div className={`p-1 rounded mr-3 ${isDirectory ? 'bg-blue-900 bg-opacity-50' : 'bg-gray-600'}`}>
                                <i className={`fas ${isDirectory ? 'fa-folder' : 'fa-file-alt'} text-sm ${
                                    isDirectory ? 'text-blue-400' : 'text-gray-300'
                                }`}></i>
                            </div>
                            <div className="flex-1 min-w-0">
                                <p className="text-white font-medium truncate">{file.name}</p>
                                {isDirectory && isHovered && canUpload && (
                                    <p className="text-xs text-blue-300 mt-1">Drop files here to upload</p>
                                )}
                                {file.size && (
                                    <p className="text-xs text-gray-400 mt-1">
                                        {(file.size / 1024).toFixed(1)} KB
                                    </p>
                                )}
                            </div>
                        </div>
                        
                        {isHovered && (
                            <div className="file-item-buttons flex items-center gap-1 ml-3">
                                {isDirectory && canUpload ? (
                                    <>
                                        <button
                                            className="bg-green-600 hover:bg-green-500 text-white p-1.5 rounded transition duration-200"
                                            onClick={() => onUploadToFolder(fullPath)}
                                            title="Upload files to this folder"
                                        >
                                            <i className="fas fa-upload text-xs"></i>
                                        </button>
                                        <button
                                            className="bg-purple-600 hover:bg-purple-500 text-white p-1.5 rounded transition duration-200"
                                            onClick={() => onUploadFolderToPath(fullPath)}
                                            title="Upload folder to this folder"
                                        >
                                            <i className="fas fa-folder-open text-xs"></i>
                                        </button>
                                        <button
                                            className="bg-blue-600 hover:bg-blue-500 text-white p-1.5 rounded transition duration-200"
                                            onClick={() => onCreateFolder(fullPath)}
                                            title="Create subfolder"
                                        >
                                            <i className="fas fa-folder-plus text-xs"></i>
                                        </button>
                                        {onDelete && (
                                            <button
                                                className="bg-red-600 hover:bg-red-500 text-white p-1.5 rounded transition duration-200"
                                                onClick={() => onDelete(fullPath, file.type)}
                                                title="Delete folder"
                                            >
                                                <i className="fas fa-trash text-xs"></i>
                                            </button>
                                        )}
                                    </>
                                ) : (
                                    <>
                                        <button
                                            className="bg-blue-600 hover:bg-blue-500 text-white p-1.5 rounded transition duration-200"
                                            onClick={() => onDownload(fullPath)}
                                            title="Download file"
                                        >
                                            <i className="fas fa-download text-xs"></i>
                                        </button>
                                        {onDelete && (
                                            <button
                                                className="bg-red-600 hover:bg-red-500 text-white p-1.5 rounded transition duration-200"
                                                onClick={() => onDelete(fullPath, file.type)}
                                                title="Delete file"
                                            >
                                                <i className="fas fa-trash text-xs"></i>
                                            </button>
                                        )}
                                    </>
                                )}
                            </div>
                        )}
                    </div>
                    {isExpanded && (
                        <div className="border-t border-gray-600 bg-gray-800 bg-opacity-50">
                            <div className="ml-6 pl-3 border-l border-gray-600">
                                {children}
                            </div>
                        </div>
                    )}
                </div>
            );
        };        

        // Enhanced Artifact File Tree component 
        const ArtifactFileTree = ({
            files,
            onDownload,
            onDelete,
            listFiles,
            expandedDirs,
            setExpandedDirs,
            parentPath = "",
            onUploadToFolder,
            onCreateFolder,
            onDragOver,
            onDragEnter,
            onDragLeave,
            onDrop,
            onUploadFolderToPath,
            canUpload = true
        }) => {
            const [loadingDirs, setLoadingDirs] = React.useState({});
            
            const handleToggle = async (fullPath) => {
                const isExpanded = !!expandedDirs[fullPath];
                if (isExpanded) {
                    setExpandedDirs({ ...expandedDirs, [fullPath]: null });
                } else {
                    // Set loading state immediately
                    setLoadingDirs({ ...loadingDirs, [fullPath]: true });
                    
                    try {
                        const children = await listFiles(fullPath);
                        setExpandedDirs({ ...expandedDirs, [fullPath]: children });
                    } catch (error) {
                        console.error("Error loading directory:", error);
                    } finally {
                        // Clear loading state
                        setLoadingDirs({ ...loadingDirs, [fullPath]: false });
                    }
                }
            };
        
            return (
                <div className="space-y-2">
                    {files.map((file) => {
                        const fullPath = parentPath ? `${parentPath}/${file.name}` : file.name;
                        return (
                            <ArtifactFileCard
                                key={`${fullPath}-${file.type}`}
                                file={file}
                                onDownload={onDownload}
                                onDelete={onDelete}
                                isExpanded={!!expandedDirs[fullPath]}
                                isLoading={!!loadingDirs[fullPath]}
                                onToggle={handleToggle}
                                fullPath={fullPath}
                                onUploadToFolder={onUploadToFolder}
                                onCreateFolder={onCreateFolder}
                                onDragOver={onDragOver}
                                onDragEnter={onDragEnter}
                                onDragLeave={onDragLeave}
                                onDrop={onDrop}
                                onUploadFolderToPath={onUploadFolderToPath}
                                canUpload={canUpload}
                            >
                                {expandedDirs[fullPath] && (
                                    <div className="py-2">
                                        <ArtifactFileTree
                                            files={expandedDirs[fullPath]}
                                            onDownload={onDownload}
                                            onDelete={onDelete}
                                            listFiles={listFiles}
                                            expandedDirs={expandedDirs}
                                            setExpandedDirs={setExpandedDirs}
                                            parentPath={fullPath}
                                            onUploadToFolder={onUploadToFolder}
                                            onCreateFolder={onCreateFolder}
                                            onDragOver={onDragOver}
                                            onDragEnter={onDragEnter}
                                            onDragLeave={onDragLeave}
                                            onDrop={onDrop}
                                            onUploadFolderToPath={onUploadFolderToPath}
                                            canUpload={canUpload}
                                        />
                                    </div>
                                )}
                            </ArtifactFileCard>
                        );
                    })}
                </div>
            );
        };

        // Enhanced Artifact Info Modal with full file tree functionality
        const ArtifactInfoModal = ({ artifact, onClose, listFiles, am }) => {
            const [files, setFiles] = React.useState(null);
            const [loading, setLoading] = React.useState(false);
            const [uploading, setUploading] = React.useState(false);
            const [expandedDirs, setExpandedDirs] = React.useState({});
            const [uploadProgress, setUploadProgress] = React.useState(0);
            const [operationLoading, setOperationLoading] = React.useState(null); // Track which operation is loading
            const [includeHiddenFiles, setIncludeHiddenFiles] = React.useState(false);
            const [filesIncludeHiddenFiles, setFilesIncludeHiddenFiles] = React.useState(false); // For files panel // Hidden files setting for this dialog

            // Drag and drop state
            const [dragCounter, setDragCounter] = React.useState(0);
            const [isDragOver, setIsDragOver] = React.useState(false);
            
            // Local artifact state that can be updated dynamically
            const [currentArtifact, setCurrentArtifact] = React.useState(artifact);
            
            const canUpload = currentArtifact.staging !== null; // Can only upload to staged artifacts
        
            const handleListFiles = async () => {
                if (loading) return;
                try {
                    setLoading(true);
                    const fileList = await listFiles(currentArtifact.id, "");
                    setFiles(fileList);
                    setExpandedDirs({});
                } catch (error) {
                    console.error("Failed to list files:", error);
                    alert(`Failed to list files: ${error.message || error}`);
                } finally {
                    setLoading(false);
                }
            };
        
            const handleDownloadFile = async (filePath) => {
                try {
                    const url = await am.getFile(artifact.id, filePath);
                    window.open(url, "_blank");
                } catch (error) {
                    console.error("Failed to download file:", error);
                    alert(`Failed to download file: ${error}`);
                }
            };
        
            const handleDeleteFile = async (filePath, fileType) => {
                const confirmMessage = fileType === 'directory' 
                    ? `Are you sure you want to delete the folder "${filePath}" and all its contents?`
                    : `Are you sure you want to delete the file "${filePath}"?`;
                    
                if (!confirm(confirmMessage)) {
                    return;
                }
        
                try {
                    window.showLoadingSpinner(`Deleting ${filePath}...`);
                    // Use the correct method name with proper parameters
                    await am.removeFile({artifact_id: currentArtifact.id, file_path: filePath, _rkwargs: true});
                    
                    // Refresh the file list
                    const updatedFiles = await listFiles(currentArtifact.id, "");
                    setFiles(updatedFiles);
                    
                    // Clear expanded state if we deleted a folder
                    if (fileType === 'directory') {
                        const newExpandedDirs = { ...expandedDirs };
                        Object.keys(newExpandedDirs).forEach(key => {
                            if (key.startsWith(filePath)) {
                                delete newExpandedDirs[key];
                            }
                        });
                        setExpandedDirs(newExpandedDirs);
                    }
                } catch (error) {
                    console.error("Failed to delete file:", error);
                    alert(`Failed to delete file: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleUploadFiles = async (fileList, targetPath = "") => {
                if (!canUpload) {
                    alert('Cannot upload to committed artifacts. Please edit the artifact first to stage it for changes.');
                    return;
                }
        
                try {
                    window.showProgressSpinner('Uploading files...', { 
                        showLogs: true,
                        title: "Parallel File Upload"
                    });
                    setUploading(true);
                    setUploadProgress(0);
                    
                    window.addProgressLog(`Starting upload of ${fileList.length} files...`, 'info');
                    
                    // Create simple, dedicated upload solution for artifacts (no shared state conflicts)
                    console.log('Starting direct artifact upload - bypassing global upload manager to avoid conflicts');
                    
                    // Filter files based on hidden file setting
                    const filteredFiles = filterFiles(fileList, includeHiddenFiles);
                    window.addProgressLog(`Filtered ${fileList.length} files to ${filteredFiles.length} (hidden files ${includeHiddenFiles ? 'included' : 'excluded'})`, 'info');
                    
                    let completedCount = 0;
                    let failedCount = 0;
                    const totalBytes = filteredFiles.reduce((sum, file) => sum + file.size, 0);
                    let uploadedBytes = 0;
                    const fileProgresses = new Map(); // Track progress per file
                    
                    let lastProgressLog = -1;
                    const updateProgress = () => {
                        // Calculate total uploaded bytes from all file progresses
                        uploadedBytes = Array.from(fileProgresses.values()).reduce((sum, bytes) => sum + bytes, 0);
                        const percentage = totalBytes > 0 ? Math.round((uploadedBytes / totalBytes) * 100) : 0;
                        setUploadProgress(percentage);
                        // Only log progress when it has changed by at least 10% or when files complete
                        const currentProgress = Math.floor(percentage / 10) * 10;
                        if (currentProgress !== lastProgressLog || completedCount + failedCount === filteredFiles.length) {
                            lastProgressLog = currentProgress;
                            window.addProgressLog(`Progress: ${completedCount + failedCount}/${filteredFiles.length} files (${percentage}%)`, 'info');
                        }
                    };
                    
                    const finishUpload = async () => {
                        window.addProgressLog(`Upload complete! ${completedCount} succeeded, ${failedCount} failed`, failedCount > 0 ? 'warning' : 'success');
                        
                        try {
                            console.log('Refreshing artifact file list for artifact:', currentArtifact.id);
                            // Refresh the file list
                            const updatedFiles = await listFiles(currentArtifact.id, "");
                            console.log('Got updated files:', updatedFiles?.length || 0, 'files');
                            setFiles(updatedFiles);
                            
                            // If we uploaded to a subfolder, refresh that folder too  
                            if (targetPath && expandedDirs[targetPath]) {
                                console.log('Refreshing expanded directory:', targetPath);
                                const updatedFolderFiles = await listFiles(currentArtifact.id, targetPath);
                                setExpandedDirs(prev => ({ ...prev, [targetPath]: updatedFolderFiles }));
                            }
                            
                            window.addProgressLog('File list refreshed successfully!', 'success');
                        } catch (error) {
                            console.error('Error refreshing file list:', error);
                            window.addProgressLog(`Failed to refresh file list: ${error.message}`, 'error');
                        }
                        
                        // Update spinner with final status
                        setTimeout(() => {
                            if (failedCount === 0) {
                                window.updateProgressSpinner('Upload completed successfully!');
                                window.enableProgressClose();
                            } else {
                                window.updateProgressSpinner(`Upload completed with ${failedCount} errors`);
                                window.enableProgressClose();
                            }
                        }, 1000);
                        
                        setUploading(false);
                        setUploadProgress(0);
                    };
                    
                    // Upload each file directly with XMLHttpRequest
                    const uploadPromises = filteredFiles.map(async (file, index) => {
                        const fileId = `${file.name}-${index}`;
                        fileProgresses.set(fileId, 0);
                        
                        try {
                            const filePath = targetPath ? `${targetPath}/${file.name}` : file.name;
                            window.addProgressLog(`Starting upload: ${file.name}`, 'info');
                            
                            // Get upload URL
                            const uploadUrl = await am.putFile(currentArtifact.id, filePath);
                            
                            // Create promise for this file upload
                            return new Promise((resolve, reject) => {
                                const xhr = new XMLHttpRequest();
                                
                                xhr.upload.addEventListener('progress', (e) => {
                                    if (e.lengthComputable) {
                                        fileProgresses.set(fileId, e.loaded);
                                        updateProgress();
                                    }
                                });
                                
                                xhr.addEventListener('load', () => {
                                    if (xhr.status >= 200 && xhr.status < 300) {
                                        completedCount++;
                                        // Ensure we've counted all bytes for this file
                                        fileProgresses.set(fileId, file.size);
                                        window.addProgressLog(`✓ ${file.name} (${(file.size / 1024).toFixed(1)} KB)`, 'success');
                                        updateProgress();
                                        resolve();
                                    } else {
                                        failedCount++;
                                        window.addProgressLog(`✗ ${file.name}: HTTP ${xhr.status}`, 'error');
                                        reject(new Error(`HTTP ${xhr.status}`));
                                    }
                                });
                                
                                xhr.addEventListener('error', () => {
                                    failedCount++;
                                    window.addProgressLog(`✗ ${file.name}: Network error`, 'error');
                                    reject(new Error('Network error'));
                                });
                                
                                xhr.open('PUT', uploadUrl);
                                xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
                                xhr.send(file);
                            });
                        } catch (error) {
                            failedCount++;
                            window.addProgressLog(`✗ ${file.name}: ${error.message}`, 'error');
                            fileProgresses.delete(fileId);
                            throw error;
                        }
                    });
                    
                    // Wait for all uploads to complete
                    await Promise.allSettled(uploadPromises);
                    
                    // Finish up
                    await finishUpload();
                    
                } catch (error) {
                    console.error("Failed to upload files:", error);
                    window.addProgressLog(`Upload failed: ${error.message}`, 'error');
                    window.enableProgressClose();
                    window.updateProgressSpinner('Upload failed');
                    setUploading(false);
                    setUploadProgress(0);
                }
            };

            const handleUploadToFolder = (folderPath = "") => {
                if (!canUpload) {
                    alert('Cannot upload to committed artifacts. Please edit the artifact first to stage it for changes.');
                    return;
                }
        
                const fileInput = document.createElement('input');
                fileInput.type = 'file';
                fileInput.multiple = true;
                fileInput.onchange = async (e) => {
                    const files = Array.from(e.target.files);
                    if (files.length > 0) {
                        await handleUploadFiles(files, folderPath);
                    }
                };
                fileInput.click();
            };

            const handleCreateFolder = async (parentPath = "") => {
                if (!canUpload) {
                    alert('Cannot create folders in committed artifacts. Please edit the artifact first to stage it for changes.');
                    return;
                }
                
                const folderName = prompt('Enter folder name:');
                if (!folderName || !folderName.trim()) {
                    return;
                }
                
                const sanitizedFolderName = folderName.trim().replace(/[^a-zA-Z0-9._-]/g, '_');
                if (sanitizedFolderName !== folderName.trim()) {
                    if (!confirm(`Folder name will be sanitized to: "${sanitizedFolderName}". Continue?`)) {
                        return;
                    }
                }
                
                try {
                    window.showLoadingSpinner(`Creating folder ${sanitizedFolderName}...`);
                    const keepFilePath = parentPath ? `${parentPath}/${sanitizedFolderName}/.keep` : `${sanitizedFolderName}/.keep`;
                    
                    // Create a .keep file to represent the folder
                    const keepFile = new Blob([''], { type: 'text/plain' });
                    const presignedUrl = await s3.putFile(keepFilePath);
                    
                    const response = await axios.put(presignedUrl, keepFile, {
                        headers: {
                            "Content-Type": "text/plain",
                        },
                    });
                    
                    if (response.status === 200) {
                        console.log(`Folder ${sanitizedFolderName} created successfully`);
                        
                        // Refresh the appropriate file list
                        if (parentPath) {
                            const updatedFiles = await listFiles(parentPath);
                            setExpandedDirs(prev => ({
                                ...prev,
                                [parentPath]: updatedFiles
                            }));
                        } else {
                            const updatedFiles = await listFiles();
                            setFileList(updatedFiles);
                        }
                    } else {
                        console.error("Folder creation failed", response.statusText);
                        alert("Folder creation failed: " + response.statusText);
                    }
                } catch (error) {
                    console.error("Folder creation failed", error);
                    alert(`Folder creation failed: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };

            // Enhanced drag and drop handlers
            const handleDragEnter = (e) => {
                e.preventDefault();
                e.stopPropagation();
                setDragCounter(prev => prev + 1);
                setIsDragOver(true);
            };

            const handleDragLeave = (e) => {
                e.preventDefault();
                e.stopPropagation();
                setDragCounter(prev => prev - 1);
                if (dragCounter <= 1) {
                    setIsDragOver(false);
                }
            };

            const handleDragOver = (e) => {
                e.preventDefault();
                e.stopPropagation();
            };

            const handleDrop = async (e, targetPath = "") => {
                e.preventDefault();
                e.stopPropagation();
                setIsDragOver(false);
                setDragCounter(0);

                if (!canUpload) {
                    alert('Cannot upload to committed artifacts. Please edit the artifact first to stage it for changes.');
                    return;
                }

                const items = Array.from(e.dataTransfer.items);
                if (items.length > 0) {
                    // Process items (supports folders)
                    await processArtifactDroppedItems(items, targetPath);
                } else {
                    // Fallback for older browsers - file only
                    const files = Array.from(e.dataTransfer.files);
                    if (files.length > 0) {
                        await handleUploadFiles(files, targetPath);
                    }
                }
            };

            // Process dropped items with folder support for artifacts
            const processArtifactDroppedItems = async (items, targetPath = "") => {
                try {
                    // CRITICAL: Stop any running upload manager to prevent conflicts
                    if (window.globalUploadManager) {
                        window.globalUploadManager.stop();
                        window.globalUploadManager.reset();
                        // Clear all callbacks to prevent the "No onComplete callback registered" error
                        window.globalUploadManager.onComplete = null;
                        window.globalUploadManager.onProgress = null;
                        window.globalUploadManager.onError = null;
                        window.globalUploadManager.onRetryAvailable = null;
                    }
                    
                    window.showProgressSpinner('Processing dropped items...', { 
                        showLogs: true,
                        title: "Processing Upload"
                    });
                    
                    window.addProgressLog(`Processing ${items.length} dropped items...`, 'info');
                    
                    const filesToUpload = [];
                    
                    // First pass: collect all files from items (including folders)
                    for (let i = 0; i < items.length; i++) {
                        const item = items[i];
                        
                        if (item.webkitGetAsEntry) {
                            const entry = item.webkitGetAsEntry();
                            if (entry) {
                                await processArtifactDirectoryEntry(entry, targetPath, filesToUpload, includeHiddenFiles);
                            }
                        } else if (item.getAsFile) {
                            const file = item.getAsFile();
                            if (file) {
                                filesToUpload.push({ file, targetPath });
                            }
                        }
                    }
                    
                    if (filesToUpload.length === 0) {
                        window.addProgressLog('No files found to upload', 'warning');
                        window.enableProgressClose();
                        return;
                    }
                    
                    window.addProgressLog(`Found ${filesToUpload.length} files to upload`, 'info');
                    
                    // Group files by their target directory
                    const filesByDirectory = new Map();
                    
                    for (const { file, targetPath: itemTargetPath } of filesToUpload) {
                        const key = itemTargetPath || targetPath || "";
                        if (!filesByDirectory.has(key)) {
                            filesByDirectory.set(key, []);
                        }
                        filesByDirectory.get(key).push(file);
                    }
                    
                    // Close current spinner
                    window.hideProgressSpinner();
                    
                    // Upload files directory by directory to maintain structure
                    for (const [dirPath, files] of filesByDirectory) {
                        await handleUploadFiles(files, dirPath);
                    }
                    
                } catch (error) {
                    console.error("Failed to process dropped items:", error);
                    window.addProgressLog(`Failed to process dropped items: ${error.message}`, 'error');
                    window.enableProgressClose();
                    window.updateProgressSpinner('Upload failed');
                }
            };

            // Process directory entries recursively for artifacts
            const processArtifactDirectoryEntry = async (entry, basePath, filesToUpload, includeHidden = false) => {
                // Skip hidden files/folders if includeHidden is false
                if (!includeHidden && entry.name.startsWith('.')) {
                    return;
                }
                
                if (entry.isFile) {
                    return new Promise((resolve) => {
                        entry.file((file) => {
                            const filePath = basePath ? `${basePath}/${entry.fullPath.substring(1)}` : entry.fullPath.substring(1);
                            const targetDir = filePath.substring(0, filePath.lastIndexOf('/'));
                            filesToUpload.push({ file, targetPath: targetDir || "" });
                            resolve();
                        });
                    });
                } else if (entry.isDirectory) {
                    const reader = entry.createReader();
                    const entries = await new Promise((resolve) => {
                        reader.readEntries(resolve);
                    });
                    
                    for (const childEntry of entries) {
                        await processArtifactDirectoryEntry(childEntry, basePath, filesToUpload, includeHidden);
                    }
                }
            };

            const artifactListFiles = async (dirPath = "") => {
                console.log("artifactListFiles called with dirPath:", dirPath);
                console.log("currentArtifact available:", !!currentArtifact);
                if (!currentArtifact) {
                    console.error("currentArtifact is not available in artifactListFiles");
                    return [];
                }
                console.log("Calling listFiles with artifact ID:", currentArtifact.id, "and dirPath:", dirPath);
                return await listFiles(currentArtifact.id, dirPath);
            };

            // Stage/Commit/Version handlers
            const handleStageArtifact = async () => {
                if (operationLoading) return;
                try {
                    setOperationLoading('stage');
                    await am.edit(currentArtifact.id, { stage: true, _rkwargs: true });
                    
                    // Refresh artifact state from backend instead of optimistic update
                    const updatedArtifact = await am.read(currentArtifact.id, { stage: true, _rkwargs: true });
                    setCurrentArtifact(updatedArtifact);
                } catch (error) {
                    console.error('Failed to stage artifact:', error);
                    alert(`Failed to stage artifact: ${error.message || error}`);
                } finally {
                    setOperationLoading(null);
                }
            };

            const handleCommitArtifact = async () => {
                if (operationLoading) return;
                try {
                    setOperationLoading('commit');
                    
                    const commitParams =  { _rkwargs: true };
                    
                    await am.commit(currentArtifact.id, commitParams);
                    
                    // Refresh artifact state from backend instead of optimistic update
                    const updatedArtifact = await am.read(currentArtifact.id, { stage: false, _rkwargs: true });
                    setCurrentArtifact(updatedArtifact);
                    
                    // Clear files since they may have changed
                    setFiles(null);
                    setExpandedDirs({});
                } catch (error) {
                    console.error('Failed to commit artifact:', error);
                    alert(`Failed to commit artifact: ${error.message || error}`);
                } finally {
                    setOperationLoading(null);
                }
            };

            const handleDiscardChanges = async () => {
                if (operationLoading) return;
                if (!confirm('Are you sure you want to discard all staged changes? This cannot be undone.')) {
                    return;
                }
                
                try {
                    setOperationLoading('discard');
                    await am.discard(currentArtifact.id, { _rkwargs: true });
                    
                    // Refresh artifact state from backend instead of optimistic update
                    const updatedArtifact = await am.read(currentArtifact.id, { stage: false, _rkwargs: true });
                    setCurrentArtifact(updatedArtifact);
                    
                    // Clear the file list since files may have been discarded
                    setFiles(null);
                    setExpandedDirs({});
                } catch (error) {
                    console.error('Failed to discard changes:', error);
                    alert(`Failed to discard changes: ${error.message || error}`);
                } finally {
                    setOperationLoading(null);
                }
            };

            const handleNewVersion = async () => {
                if (operationLoading) return;
                try {
                    setOperationLoading('new-version');
                    await am.edit(currentArtifact.id, { stage: true, version: "new", _rkwargs: true });
                    
                    // Refresh artifact state from backend instead of optimistic update
                    const updatedArtifact = await am.read(currentArtifact.id, { stage: true, _rkwargs: true });
                    setCurrentArtifact(updatedArtifact);
                    
                    // Clear files since this is a new version
                    setFiles(null);
                    setExpandedDirs({});
                } catch (error) {
                    console.error('Failed to create new version:', error);
                    alert(`Failed to create new version: ${error.message || error}`);
                } finally {
                    setOperationLoading(null);
                }
            };
        
            return (
                <div className="modal fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm flex items-center justify-center z-50 p-4">
                    <div className="modal-content bg-gray-900 rounded-xl shadow-2xl w-full max-w-7xl max-h-[95vh] overflow-hidden border border-gray-700">
                        {/* Enhanced Header */}
                        <div className="modal-header bg-gradient-to-r from-gray-800 to-gray-700 px-6 py-4 border-b border-gray-600 relative">
                            <div className="flex items-center space-x-3 pr-12">
                                <div className="p-2 bg-blue-600 rounded-lg">
                                    <i className={`fas ${currentArtifact.type === 'collection' ? 'fa-folder' : 'fa-file-alt'} text-white text-lg`}></i>
                                </div>
                                <div>
                                    <h2 className="text-2xl font-bold text-white">{currentArtifact.manifest?.name || currentArtifact.id}</h2>
                                    <p className="text-gray-300 text-sm">{currentArtifact.manifest?.description || "No description"}</p>
                                </div>
                            </div>
                            <button
                                onClick={onClose}
                                className="absolute top-4 right-4 text-gray-400 hover:text-white bg-gray-700 hover:bg-gray-600 rounded-full w-8 h-8 flex items-center justify-center transition duration-200"
                            >
                                <i className="fas fa-times"></i>
                            </button>
                        </div>

                        <div className="modal-body p-6 overflow-y-auto max-h-[calc(95vh-140px)]">
                            {/* Artifact Info Cards */}
                            <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
                                {/* Basic Info and Mode Control Card */}
                                <div className="bg-gray-800 rounded-lg p-4 border border-gray-700">
                                    <h3 className="text-lg font-semibold text-white mb-3 flex items-center">
                                        <i className="fas fa-info-circle text-blue-400 mr-2"></i>
                                        Basic Information
                                    </h3>
                                    <div className="space-y-3 text-sm">
                                        <div className="flex justify-between">
                                            <span className="text-gray-400">Name:</span>
                                            <span className="text-white font-medium">{currentArtifact.manifest?.name || "N/A"}</span>
                                        </div>
                                        <div className="flex justify-between">
                                            <span className="text-gray-400">Type:</span>
                                            <span className="px-2 py-1 bg-blue-900 text-blue-200 rounded text-xs font-medium">
                                                {currentArtifact.type}
                                            </span>
                                        </div>
                                        <div className="flex justify-between items-center">
                                            <span className="text-gray-400">Status:</span>
                                            <span className={`px-2 py-1 rounded text-xs font-medium flex items-center ${
                                                currentArtifact.staging !== null 
                                                    ? 'bg-yellow-900 text-yellow-200' 
                                                    : 'bg-green-900 text-green-200'
                                            }`}>
                                                <i className={`fas ${currentArtifact.staging !== null ? 'fa-edit' : 'fa-check-circle'} mr-1`}></i>
                                                {currentArtifact.staging !== null ? 'Staged' : 'Committed'}
                                            </span>
                                        </div>
                                    </div>
                                    
                                    {/* Statistics in two columns */}
                                    <div className="mt-4 pt-3 border-t border-gray-700">
                                        <div className="grid grid-cols-2 gap-3 text-sm">
                                            <div className="space-y-2">
                                                <div className="flex justify-between">
                                                    <span className="text-gray-400">File Count:</span>
                                                    <span className="text-white font-bold">{currentArtifact.file_count}</span>
                                                </div>
                                                <div className="flex justify-between">
                                                    <span className="text-gray-400">Downloads:</span>
                                                    <span className="text-white font-bold">{Math.floor(currentArtifact.download_count || 0)}</span>
                                                </div>
                                            </div>
                                            <div className="space-y-2">
                                                <div className="flex justify-between">
                                                    <span className="text-gray-400">Views:</span>
                                                    <span className="text-white font-bold">{Math.floor(currentArtifact.view_count || 0)}</span>
                                                </div>
                                                {((currentArtifact.versions && currentArtifact.versions.length > 0 && currentArtifact.versions[currentArtifact.versions.length - 1]?.version) || currentArtifact.manifest?.version) && (
                                                    <div className="flex justify-between">
                                                        <span className="text-gray-400">Version:</span>
                                                        <span className="text-white font-medium">
                                                            {(currentArtifact.versions && currentArtifact.versions.length > 0 && currentArtifact.versions[currentArtifact.versions.length - 1]?.version) || currentArtifact.manifest?.version}
                                                        </span>
                                                    </div>
                                                )}
                                            </div>
                                        </div>
                                    </div>
                                    
                                    {/* Mode Control Section */}
                                    <div className="mt-6 bg-gray-750 rounded-lg p-3 border border-gray-600">
                                        <div className="flex items-center justify-between mb-2">
                                            <span className="text-sm text-gray-300 font-medium">Mode Control</span>
                                            <span className={`text-xs px-2 py-1 rounded ${
                                                currentArtifact.staging !== null ? 'bg-yellow-900 text-yellow-200' : 'bg-green-900 text-green-200'
                                            }`}>
                                                {currentArtifact.staging !== null ? 'Staged' : 'Committed'}
                                            </span>
                                        </div>
                                        <div className="flex gap-2">
                                            {currentArtifact.staging === null ? (
                                                <button
                                                    className="flex-1 bg-yellow-600 hover:bg-yellow-500 text-white font-medium py-1.5 px-2 rounded transition duration-200 flex items-center justify-center text-xs disabled:opacity-50"
                                                    onClick={handleStageArtifact}
                                                    disabled={operationLoading}
                                                >
                                                    <i className={`fas ${operationLoading === 'stage' ? 'fa-spinner fa-spin' : 'fa-edit'} mr-1`}></i> 
                                                    {operationLoading === 'stage' ? 'Staging...' : 'Stage for Edit'}
                                                </button>
                                            ) : (
                                                <>
                                                    <button
                                                        className="flex-1 bg-green-600 hover:bg-green-500 text-white font-medium py-1.5 px-2 rounded transition duration-200 flex items-center justify-center text-xs disabled:opacity-50"
                                                        onClick={handleCommitArtifact}
                                                        disabled={operationLoading}
                                                    >
                                                        <i className={`fas ${operationLoading === 'commit' ? 'fa-spinner fa-spin' : 'fa-check'} mr-1`}></i> 
                                                        {operationLoading === 'commit' ? 'Committing...' : 'Commit'}
                                                    </button>
                                                        <button
                                                        className="flex-1 bg-red-600 hover:bg-red-500 text-white font-medium py-1.5 px-2 rounded transition duration-200 flex items-center justify-center text-xs disabled:opacity-50"
                                                        onClick={handleDiscardChanges}
                                                        disabled={operationLoading}
                                                        >
                                                        <i className={`fas ${operationLoading === 'discard' ? 'fa-spinner fa-spin' : 'fa-undo'} mr-1`}></i> 
                                                        {operationLoading === 'discard' ? 'Discarding...' : 'Discard'}
                                                        </button>
                                                </>
                                                    )}
                                                </div>
                                        {currentArtifact.staging === null && (
                                            <button
                                                className="w-full mt-2 bg-purple-600 hover:bg-purple-500 text-white font-medium py-1.5 px-2 rounded transition duration-200 flex items-center justify-center text-xs disabled:opacity-50"
                                                onClick={handleNewVersion}
                                                disabled={operationLoading}
                                            >
                                                <i className={`fas ${operationLoading === 'new-version' ? 'fa-spinner fa-spin' : 'fa-plus'} mr-1`}></i> 
                                                {operationLoading === 'new-version' ? 'Creating...' : 'New Version'}
                                            </button>
                                        )}
                                    </div>
                                </div>

                                {/* Statistics and Metadata Card */}
                                <div className="bg-gray-800 rounded-lg p-4 border border-gray-700">
                                    <h3 className="text-lg font-semibold text-white mb-3 flex items-center">
                                        <i className="fas fa-chart-bar text-green-400 mr-2"></i>
                                        Metadata
                                    </h3>
                                    {/* Dates */}
                                    <div className="grid grid-cols-2 gap-4 text-sm">
                                        <div className="flex justify-between">
                                            <span className="text-gray-400">Created:</span>
                                            <span className="text-white text-xs">{new Date(currentArtifact.created_at * 1000).toLocaleDateString()}</span>
                                        </div>
                                        <div className="flex justify-between">
                                            <span className="text-gray-400">Modified:</span>
                                            <span className="text-white text-xs">{new Date(currentArtifact.last_modified * 1000).toLocaleDateString()}</span>
                                        </div>
                                    </div>
                                    
                                    {/* Additional Metadata */}
                                    <div className="mt-6 pt-3 border-t border-gray-700 space-y-3 text-sm">
                                        <div>
                                            <span className="text-gray-400 block mb-1">Artifact ID:</span>
                                            <code className="bg-gray-900 text-gray-300 px-2 py-1 rounded text-xs font-mono block break-all">
                                                {currentArtifact.id}
                                            </code>
                                        </div>
                                        {currentArtifact.created_by && (
                                            <div>
                                                <span className="text-gray-400 block mb-1">Created By:</span>
                                                <span className="text-white text-sm">
                                                    {currentArtifact.created_by.split('|')[1] || currentArtifact.created_by}
                                                </span>
                                            </div>
                                        )}
                                        {currentArtifact.workspace && (
                                            <div>
                                                <span className="text-gray-400 block mb-1">Workspace:</span>
                                                <span className="text-white text-sm">
                                                    {currentArtifact.workspace}
                                                </span>
                                            </div>
                                        )}
                                    </div>
                                    
                                    {/* Tags and License */}
                                    {currentArtifact.manifest && (currentArtifact.manifest.tags || currentArtifact.manifest.license) && (
                                        <div className="mt-4 pt-3 border-t border-gray-700">
                                            <div className="flex flex-wrap gap-3">
                                                {currentArtifact.manifest.tags && Array.isArray(currentArtifact.manifest.tags) && currentArtifact.manifest.tags.map((tag, index) => (
                                                    <span key={index} className="px-3 py-1 bg-blue-900 text-blue-200 rounded-full text-sm">
                                                        #{tag}
                                                    </span>
                                                ))}
                                                {currentArtifact.manifest.license && (
                                                    <span className="px-3 py-1 bg-green-900 text-green-200 rounded-full text-sm">
                                                        <i className="fas fa-certificate mr-1"></i>
                                                        {currentArtifact.manifest.license}
                                                    </span>
                                                )}
                                            </div>
                                        </div>
                                    )}
                                </div>
                            </div>
                            
                            {/* File Management Section */}
                            <div className="bg-gray-800 rounded-lg border border-gray-700 overflow-hidden">
                                <div className="bg-gray-750 px-6 py-4 border-b border-gray-700">
                                    <div className="flex justify-between items-center">
                                        <h3 className="text-lg font-semibold text-white flex items-center">
                                            <i className="fas fa-folder-tree text-blue-400 mr-2"></i>
                                            File Management
                                            {currentArtifact.file_count > 0 && (
                                                <span className="ml-2 px-2 py-1 bg-blue-900 text-blue-200 rounded text-sm">
                                                    {currentArtifact.file_count} files
                                                </span>
                                            )}
                                        </h3>
                                        <div className="flex items-center gap-3">
                                            <button
                                                className="bg-gray-600 hover:bg-gray-500 text-white font-medium py-1.5 px-3 rounded transition duration-200 flex items-center text-sm"
                                                onClick={handleListFiles}
                                                disabled={loading}
                                            >
                                                <i className={`fas ${loading ? 'fa-spinner fa-spin' : 'fa-sync-alt'} mr-2`}></i>
                                                {loading ? "Loading..." : files ? "Refresh" : "Load Files"}
                                            </button>
                                            {canUpload && (
                                                <>
                                                    <button
                                                        className="bg-green-600 hover:bg-green-500 text-white font-medium py-1.5 px-3 rounded transition duration-200 flex items-center text-sm"
                                                        onClick={() => handleUploadToFolder("")}
                                                        title="Upload Files"
                                                    >
                                                        <i className="fas fa-upload"></i>
                                                    </button>
                                                    <button
                                                        className="bg-blue-600 hover:bg-blue-500 text-white font-medium py-1.5 px-3 rounded transition duration-200 flex items-center text-sm"
                                                        onClick={() => handleCreateFolder("")}
                                                        title="Create Folder"
                                                    >
                                                        <i className="fas fa-folder-plus"></i>
                                                    </button>
                                                </>
                                            )}
                                            {canUpload && (
                                                <div className="flex items-center gap-2 bg-gray-750 px-3 py-1.5 rounded border border-gray-600">
                                                    <input
                                                        type="checkbox"
                                                        id="artifactIncludeHidden"
                                                        checked={includeHiddenFiles}
                                                        onChange={(e) => setIncludeHiddenFiles(e.target.checked)}
                                                        className="w-3 h-3 text-blue-600 bg-gray-800 border-gray-600 rounded focus:ring-blue-500 focus:ring-1"
                                                    />
                                                    <label htmlFor="artifactIncludeHidden" className="text-xs text-gray-300 cursor-pointer">
                                                        Include .* files
                                                    </label>
                                                </div>
                                            )}
                                            <div className="flex items-center gap-2 text-sm text-gray-400">
                                                {canUpload && <span className="flex items-center"><i className="fas fa-edit mr-1 text-yellow-400"></i> Editable</span>}
                                                {!canUpload && <span className="flex items-center"><i className="fas fa-lock mr-1 text-gray-500"></i> Read-only</span>}
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <div className="p-6">
                                    {/* Drag and drop area */}
                                    {canUpload && (
                                        <div 
                                            className={`border-2 border-dashed rounded-lg p-6 transition-all duration-200 mb-6 ${
                                                isDragOver 
                                                    ? 'border-blue-400 bg-blue-900 bg-opacity-20' 
                                                    : 'border-gray-600 bg-gray-750'
                                            }`}
                                            onDragOver={handleDragOver}
                                            onDragEnter={handleDragEnter}
                                            onDragLeave={handleDragLeave}
                                            onDrop={(e) => handleDrop(e, "")}
                                        >
                                            <div className="text-center">
                                                <i className={`fas fa-cloud-upload-alt text-4xl mb-3 ${
                                                    isDragOver ? 'text-blue-400' : 'text-gray-500'
                                                }`}></i>
                                                <p className="text-gray-300 font-medium mb-1">
                                                    {isDragOver ? 'Drop files here!' : 'Drag and drop files here'}
                                                </p>
                                                <p className="text-gray-500 text-sm">
                                                    Supports multiple files and nested folder structures
                                                </p>
                                                {uploading && uploadProgress > 0 && (
                                <div className="mt-4">
                                                        <div className="w-full bg-gray-700 h-2 rounded-full overflow-hidden">
                                                            <div
                                                                className="bg-blue-500 h-2 rounded-full transition-all duration-300 ease-out"
                                                                style={{ width: `${uploadProgress}%` }}
                                                            ></div>
                                                        </div>
                                                        <p className="text-blue-400 text-sm mt-2 font-medium">
                                                            Uploading... {Math.round(uploadProgress)}%
                                                        </p>
                                                    </div>
                                                )}
                                            </div>
                                        </div>
                                    )}

                                    {/* File Tree */}
                                    {files !== null ? (
                                        files.length === 0 ? (
                                            <div className="text-center py-12">
                                                <div className="w-16 h-16 bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-4">
                                                    <i className="fas fa-folder-open text-2xl text-gray-500"></i>
                                                </div>
                                                <h4 className="text-lg font-medium text-gray-300 mb-2">No Files Yet</h4>
                                                <p className="text-gray-500 text-sm max-w-md mx-auto">
                                                    This artifact doesn't contain any files. 
                                                    {canUpload && " Upload some files to get started!"}
                                                </p>
                                            </div>
                                        ) : (
                                            <div className="space-y-2">
                                                <div className="flex items-center justify-between mb-4">
                                                    <h4 className="text-sm font-medium text-gray-400 uppercase tracking-wide">
                                                        File Structure
                                                    </h4>
                                                    <span className="text-xs text-gray-500">
                                                        {files.length} item{files.length !== 1 ? 's' : ''}
                                                    </span>
                                                </div>
                                                <ArtifactFileTree
                                                    files={files}
                                                    onDownload={handleDownloadFile}
                                                    onDelete={canUpload ? handleDeleteFile : null}
                                                    listFiles={artifactListFiles}
                                                    expandedDirs={expandedDirs}
                                                    setExpandedDirs={setExpandedDirs}
                                                    onUploadToFolder={canUpload ? handleUploadToFolder : null}
                                                    onCreateFolder={canUpload ? handleCreateFolder : null}
                                                    onDragOver={handleDragOver}
                                                    onDragEnter={handleDragEnter}
                                                    onDragLeave={handleDragLeave}
                                                    onDrop={canUpload ? handleDrop : null}
                                                    canUpload={canUpload}
                                                />
                                            </div>
                                        )
                                    ) : (
                                        currentArtifact.file_count === 0 ? (
                                            <div className="text-center py-12">
                                                <div className="w-16 h-16 bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-4">
                                                    <i className="fas fa-folder text-2xl text-gray-500"></i>
                                                </div>
                                                <h4 className="text-lg font-medium text-gray-300 mb-2">Empty Artifact</h4>
                                                <p className="text-gray-500 text-sm max-w-md mx-auto mb-4">
                                                    This artifact contains no files.
                                                    {canUpload && " Start by uploading files or creating folders."}
                                                </p>
                                                {canUpload && (
                                                    <button
                                                        onClick={() => handleUploadToFolder("")}
                                                        className="bg-blue-600 hover:bg-blue-500 text-white font-medium py-2 px-4 rounded-lg transition duration-200"
                                                    >
                                                        <i className="fas fa-upload mr-2"></i>
                                                        Upload First File
                                                    </button>
                                                )}
                                            </div>
                                        ) : (
                                            <div className="text-center py-8">
                                                <p className="text-gray-400 mb-4">Click "Load Files" to view the file structure</p>
                                            </div>
                                        )
                                    )}
                                </div>
                            </div>
                            
                            {/* Advanced Section */}
                            <div className="bg-gray-800 rounded-lg border border-gray-700 mt-6">
                                <details className="group">
                                    <summary className="cursor-pointer p-4 flex items-center justify-between text-gray-300 hover:text-white transition-colors">
                                        <div className="flex items-center">
                                            <i className="fas fa-code text-purple-400 mr-2"></i>
                                            <span className="font-medium">Advanced: Raw Artifact Data</span>
                                        </div>
                                        <i className="fas fa-chevron-down group-open:rotate-180 transition-transform duration-200"></i>
                                    </summary>
                                    <div className="border-t border-gray-700 p-4">
                                        <pre className="bg-gray-900 text-gray-300 p-4 rounded-lg text-xs overflow-auto max-h-64 font-mono">
                                            {JSON.stringify(currentArtifact, null, 2)}
                                        </pre>
                                    </div>
                                </details>
                            </div>
                        </div>

                        {/* Enhanced Footer */}
                        <div className="modal-footer bg-gray-800 px-6 py-4 border-t border-gray-700">
                            <div className="flex items-center justify-center text-sm text-gray-400">
                                <i className="fas fa-info-circle mr-2"></i>
                                <span>Last modified: {new Date(currentArtifact.last_modified * 1000).toLocaleString()}</span>
                            </div>
                        </div>
                    </div>
                </div>
            );
        };

        // Create Artifact Modal Component
        const CreateArtifactModal = ({ onClose, am, onArtifactCreated, presetParentId = null }) => {
            const [manifestYaml, setManifestYaml] = React.useState(`name: "My New Artifact"
description: "Description of the artifact"
version: "1.0.0"
tags: ["example", "dataset"]
license: "MIT"`);
            const [configJson, setConfigJson] = React.useState(`{
  "permissions": {
    "*": "r",
    "@": "r+"
  }
}`);
            const [artifactType, setArtifactType] = React.useState('generic');
            const [artifactAlias, setArtifactAlias] = React.useState('');
            const [parentId, setParentId] = React.useState(presetParentId || '');
            const [customType, setCustomType] = React.useState('');
            const [isCustomType, setIsCustomType] = React.useState(false);
            const [creating, setCreating] = React.useState(false);

            const handleTypeChange = (e) => {
                const value = e.target.value;
                if (value === 'custom') {
                    setIsCustomType(true);
                    setArtifactType('');
                } else {
                    setIsCustomType(false);
                    setArtifactType(value);
                    setCustomType('');
                }
            };

            const getFinalType = () => {
                return isCustomType ? customType : artifactType;
            };

            const handleCreate = async () => {
                const finalType = getFinalType();
                if (!finalType.trim()) {
                    alert('Please enter a type for the artifact.');
                    return;
                }

                try {
                    setCreating(true);
                    window.showProgressSpinner('Creating Artifact...', { 
                        showLogs: true,
                        title: "Creating Artifact"
                    });
                    window.addProgressLog('Parsing manifest and config...', 'info');

                    // Parse YAML manifest
                    let manifest;
                    try {
                        // Simple YAML-like parsing for basic cases
                        const yamlLines = manifestYaml.split('\n');
                        manifest = {};
                        for (const line of yamlLines) {
                            const trimmed = line.trim();
                            if (trimmed && !trimmed.startsWith('#')) {
                                const colonIndex = trimmed.indexOf(':');
                                if (colonIndex > 0) {
                                    const key = trimmed.substring(0, colonIndex).trim();
                                    let value = trimmed.substring(colonIndex + 1).trim();
                                    
                                    // Remove quotes
                                    if ((value.startsWith('"') && value.endsWith('"')) || 
                                        (value.startsWith("'") && value.endsWith("'"))) {
                                        value = value.slice(1, -1);
                                    }
                                    
                                    // Handle arrays (basic)
                                    if (value.startsWith('[') && value.endsWith(']')) {
                                        const arrayContent = value.slice(1, -1);
                                        if (arrayContent.trim()) {
                                            manifest[key] = arrayContent.split(',').map(item => 
                                                item.trim().replace(/^["']|["']$/g, '')
                                            );
                                        } else {
                                            manifest[key] = [];
                                        }
                                    } else {
                                        manifest[key] = value;
                                    }
                                }
                            }
                        }
                    } catch (error) {
                        throw new Error(`Invalid YAML in manifest: ${error.message}`);
                    }

                    // Parse JSON config
                    let config = {};
                    if (configJson.trim()) {
                        try {
                            config = JSON.parse(configJson);
                        } catch (error) {
                            throw new Error(`Invalid JSON in config: ${error.message}`);
                        }
                    }

                    window.addProgressLog('Creating artifact...', 'info');
                    
                    // Create the artifact
                    const createParams = {
                        type: finalType,
                        manifest,
                        config,
                        stage: true, // Always stage initially
                        _rkwargs: true
                    };

                    if (artifactAlias.trim()) {
                        createParams.alias = artifactAlias.trim();
                    }

                    if (parentId.trim()) {
                        createParams.parent_id = parentId.trim();
                    }

                    const artifact = await am.create(createParams);
                    window.addProgressLog('Artifact created successfully!', 'success');
                    window.addProgressLog('Artifact is now in staging mode. You can upload files and commit when ready.', 'info');

                    // Close the creation dialog and show the artifact details
                    onClose();
                    
                    // Notify parent component to show the artifact details
                    if (onArtifactCreated) {
                        await onArtifactCreated(artifact);
                    }

                    // Allow user to close the progress dialog
                    setTimeout(() => {
                        window.enableProgressClose();
                        window.updateProgressSpinner('Artifact created successfully!');
                    }, 1000);

                } catch (error) {
                    console.error('Failed to create artifact:', error);
                    window.addProgressLog(`Failed to create artifact: ${error.message}`, 'error');
                    
                    // Allow user to close after error
                    window.enableProgressClose();
                    window.updateProgressSpinner('Artifact creation failed');
                } finally {
                    setCreating(false);
                }
            };

            return (
                <div className="modal fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
                    <div className="modal-content bg-gray-800 rounded-lg shadow-lg p-6 w-full max-w-4xl max-h-[90vh] overflow-y-auto">
                        <div className="modal-header flex justify-between items-center border-b border-gray-700 pb-4">
                            <h2 className="text-2xl font-bold text-white">Create New Artifact</h2>
                            <button
                                onClick={onClose}
                                className="text-white text-2xl hover:text-red-500 transition"
                            >
                                &times;
                            </button>
                        </div>
                        
                        <div className="modal-body mt-4">
                            <div className="space-y-6">
                                {/* Artifact Metadata */}
                                <div>
                                    <h3 className="text-lg font-bold mb-4 text-white">Artifact Metadata</h3>
                                    
                                    {/* Basic fields */}
                                    <div className="space-y-4">
                                        <div>
                                            <label className="block text-sm font-medium text-gray-300 mb-1">
                                                Alias (optional)
                                    </label>
                                    <input
                                                type="text"
                                                value={artifactAlias}
                                                onChange={(e) => setArtifactAlias(e.target.value)}
                                                placeholder="my-artifact (leave empty to auto-generate)"
                                                className="w-full px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white"
                                            />
                                            <p className="text-xs text-gray-400 mt-1">
                                                Unique identifier for this artifact (lowercase, no spaces). If not provided, will be auto-generated.
                                            </p>
                                </div>

                                        <div>
                                            <label className="block text-sm font-medium text-gray-300 mb-1">
                                                Type
                                            </label>
                                            <div className="flex gap-2">
                                                <select
                                                    value={isCustomType ? 'custom' : artifactType}
                                                    onChange={handleTypeChange}
                                                    className="flex-1 px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white"
                                                >
                                                    <option value="generic">Generic</option>
                                                    <option value="collection">Collection</option>
                                                    <option value="dataset">Dataset</option>
                                                    <option value="model">Model</option>
                                                    <option value="application">Application</option>
                                                    <option value="vector-collection">Vector Collection</option>
                                                    <option value="custom">Custom Type...</option>
                                                </select>
                                                {isCustomType && (
                                                    <input
                                                        type="text"
                                                        value={customType}
                                                        onChange={(e) => setCustomType(e.target.value)}
                                                        placeholder="Enter custom type"
                                                        className="flex-1 px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white"
                                                    />
                                                )}
                                            </div>
                                        </div>

                                        <div>
                                            <label className="block text-sm font-medium text-gray-300 mb-1">
                                                Parent Collection ID (optional)
                                            </label>
                                            <input
                                                type="text"
                                                value={parentId}
                                                onChange={(e) => setParentId(e.target.value)}
                                                placeholder="parent-collection-id"
                                                className="w-full px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white"
                                                readOnly={!!presetParentId}
                                            />
                                            <p className="text-xs text-gray-400 mt-1">
                                                {presetParentId ? `Pre-set to: ${presetParentId}` : 'Leave empty to create as top-level artifact'}
                            </p>
                        </div>
                                    </div>

                                    {/* Manifest YAML */}
                                    <div className="mt-6">
                                        <label className="block text-sm font-medium text-gray-300 mb-1">
                                            Manifest (YAML-like)
                                        </label>
                                        <textarea
                                            value={manifestYaml}
                                            onChange={(e) => setManifestYaml(e.target.value)}
                                            className="w-full px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white font-mono text-sm"
                                            rows="8"
                                            placeholder="Enter YAML-like manifest"
                                        />
                                        <p className="text-xs text-gray-400 mt-1">
                                            Basic YAML parsing supported (name, description, tags, etc.)
                                        </p>
                                    </div>

                                    {/* Config JSON */}
                                    <div className="mt-4">
                                        <label className="block text-sm font-medium text-gray-300 mb-1">
                                            Configuration (JSON)
                                        </label>
                                        <textarea
                                            value={configJson}
                                            onChange={(e) => setConfigJson(e.target.value)}
                                            className="w-full px-3 py-2 border border-gray-600 rounded-md bg-gray-900 text-white font-mono text-sm"
                                            rows="6"
                                            placeholder="Enter JSON configuration"
                                        />
                                        <p className="text-xs text-gray-400 mt-1">
                                            Permissions, schema, and other configuration options
                                        </p>
                                    </div>

                                    {/* Info Box */}
                                    <div className="mt-6 p-4 bg-blue-900 bg-opacity-20 border border-blue-600 rounded-lg">
                                        <div className="flex items-start">
                                            <i className="fas fa-info-circle text-blue-400 mr-3 mt-1"></i>
                                            <div>
                                                <h4 className="text-blue-300 font-medium mb-2">Files Upload</h4>
                                                <p className="text-blue-300 text-sm">
                                                    Files can be uploaded after artifact creation. The artifact will be created in staging mode, 
                                                    allowing you to upload files and commit when ready.
                                                </p>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div className="modal-footer mt-6 flex justify-end gap-3 border-t border-gray-700 pt-4">
                            <button
                                onClick={onClose}
                                className="bg-gray-600 hover:bg-gray-500 text-white font-bold py-2 px-4 rounded transition"
                                disabled={creating}
                            >
                                Cancel
                            </button>
                            <button
                                onClick={handleCreate}
                                className="bg-green-600 hover:bg-green-500 text-white font-bold py-2 px-4 rounded transition duration-300 flex items-center"
                                disabled={creating}
                            >
                                <i className="fas fa-plus mr-2"></i>
                                {creating ? 'Creating...' : 'Create Artifact'}
                            </button>
                        </div>
                    </div>
                </div>
            );
        };                  
        
        // Enhanced Artifacts Panel with full functionality
        const ArtifactsPanel = ({ am }) => {
            const [artifacts, setArtifacts] = React.useState([]);
            const [expandedArtifacts, setExpandedArtifacts] = React.useState({});
            const [selectedArtifact, setSelectedArtifact] = React.useState(null);
            const [showCreateModal, setShowCreateModal] = React.useState(false);
            const [showChildCreateModal, setShowChildCreateModal] = React.useState(false);
            const [presetParentId, setPresetParentId] = React.useState(null);
            const [loading, setLoading] = React.useState(false);

            // Drag and drop state
            const [dragCounter, setDragCounter] = React.useState(0);
            const [isDragOver, setIsDragOver] = React.useState(false);
        
            React.useEffect(() => {
                const fetchTopLevelArtifacts = async () => {
                    if (am) {
                        setLoading(true);
                        try {
                            const topLevelArtifacts = await am.list({stage: 'all', _rkwargs: true});
                        setArtifacts(topLevelArtifacts);
                        } catch (error) {
                            console.error("Failed to fetch artifacts:", error);
                        } finally {
                            setLoading(false);
                        }
                    }
                };
                fetchTopLevelArtifacts();
            }, [am]);
        
            const listArtifacts = async (parentId) => {
                try {
                    const children = await am.list({"parent_id": parentId, "stage": 'all', "_rkwargs": true});
                    return children;
                } catch (error) {
                    console.error("Failed to list artifacts:", error);
                    return [];
                }
            };
        
            const listFiles = async (artifactId, dir, useStaging = null) => {
                try {
                    // If useStaging is not provided, determine it from currentArtifact (if available)
                    if (useStaging === null) {
                        const currentArtifact = await am.read({artifact_id: artifactId, stage: true, _rkwargs: true});
                        useStaging = currentArtifact && currentArtifact.staging !== null;
                    }
                    
                    console.log(`listFiles: artifactId=${artifactId}, dir=${dir}, useStaging=${useStaging}`);
                    
                    if (!artifactId) {
                        console.error("listFiles called without artifactId");
                        return [];
                    }
                    
                    const files = await am.listFiles({artifact_id: artifactId, dir_path: dir, stage: useStaging, _rkwargs: true});
                    console.log(`listFiles result: ${files.length} files found`);
                    return files;
                } catch (error) {
                    console.error("Failed to list files:", error);
                    return [];
                }
            };

            const refreshArtifacts = async () => {
                if (am) {
                    setLoading(true);
                    try {
                        const topLevelArtifacts = await am.list({stage: 'all', _rkwargs: true});
                        setArtifacts(topLevelArtifacts);
                    } catch (error) {
                        console.error("Failed to refresh artifacts:", error);
                    } finally {
                        setLoading(false);
                    }
                }
            };
        
            const handleDelete = async (artifactId, parentId = null) => {
                if (confirm(`Are you sure you want to delete the artifact with ID: ${artifactId}? This will delete all files and cannot be undone.`)) {
                    try {
                        window.showLoadingSpinner('Deleting Artifact...');
                        await am.delete(artifactId, {delete_files: true, recursive: true, _rkwargs: true});
            
                        if (parentId) {
                            // If the artifact is a child, refresh the parent's children
                            const updatedChildren = await am.list(parentId, {stage: 'all', _rkwargs: true});
                            setExpandedArtifacts((prevState) => ({
                                ...prevState,
                                [parentId]: updatedChildren,
                            }));
                        } else {
                            // If the artifact is top-level, refresh the top-level artifacts
                            await refreshArtifacts();
                        }
                    } catch (error) {
                        alert(`Failed to delete artifact with ID: ${artifactId}. Error: ${error.message || error}`);
                    } finally {
                        window.hideLoadingSpinner();
                    }
                }
            };            

            const handleUploadFile = async (collectionId) => {
                if (!collectionId) {
                    alert('Cannot upload files to root. Please select a specific collection.');
                    return;
                }
                
                const fileInput = document.createElement('input');
                fileInput.type = 'file';
                fileInput.multiple = true;
                fileInput.onchange = async (e) => {
                    const files = Array.from(e.target.files);
                    if (files.length > 0) {
                        try {
                            window.showLoadingSpinner('Uploading files to collection...');
                            // TODO: Implement upload to collection functionality
                            // This would require staging the collection first
                            alert('Upload to collection is not yet implemented. Please use the artifact detail modal after creating/editing the collection.');
                        } catch (error) {
                            console.error('Failed to upload files:', error);
                            alert(`Failed to upload files: ${error.message || error}`);
                        } finally {
                            window.hideLoadingSpinner();
                        }
                    }
                };
                fileInput.click();
            };

            const handleCreateSubArtifact = (parentId) => {
                setPresetParentId(parentId);
                setShowChildCreateModal(true);
            };

            const handleCreateChildArtifact = (parentId) => {
                setPresetParentId(parentId);
                setShowChildCreateModal(true);
            };

            // Drag and drop handlers for file upload to collections
            const handleDragEnter = (e) => {
                e.preventDefault();
                e.stopPropagation();
                setDragCounter(prev => prev + 1);
                setIsDragOver(true);
            };

            const handleDragLeave = (e) => {
                e.preventDefault();
                e.stopPropagation();
                setDragCounter(prev => prev - 1);
                if (dragCounter <= 1) {
                    setIsDragOver(false);
                }
            };

            const handleDragOver = (e) => {
                e.preventDefault();
                e.stopPropagation();
            };

            const handleDrop = async (e, collectionId) => {
                e.preventDefault();
                e.stopPropagation();
                setIsDragOver(false);
                setDragCounter(0);

                if (!collectionId) {
                    alert('Cannot upload files to root. Please drop on a specific collection.');
                    return;
                }

                const files = Array.from(e.dataTransfer.files);
                if (files.length > 0) {
                    try {
                        window.showLoadingSpinner('Processing dropped files...');
                        // TODO: Implement drag and drop upload to collection
                        alert('Drag and drop to collections is not yet implemented. Please use the artifact detail modal after creating/editing the collection.');
                    } catch (error) {
                        console.error('Failed to process dropped files:', error);
                        alert(`Failed to process files: ${error.message || error}`);
                    } finally {
                        window.hideLoadingSpinner();
                    }
                }
            };

            const handleArtifactCreated = async (newArtifact = null) => {
                await refreshArtifacts();
                setShowCreateModal(false);
                setShowChildCreateModal(false);
                setPresetParentId(null);
                
                // If a new artifact was created, show its details
                if (newArtifact) {
                    setSelectedArtifact(newArtifact);
                }
            };            
        
            return (
                <div className="main-content">
                    {/* Header with actions */}
                    <div className="flex justify-between items-center mb-6">
                        <div>
                            <h1 className="text-4xl font-bold capitalize mb-2">Artifacts</h1>
                            <p className="text-gray-400">
                                Manage datasets, models, applications and other artifacts
                            </p>
                        </div>
                        <div className="flex gap-3">
                            <button
                                className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                onClick={refreshArtifacts}
                                disabled={loading}
                            >
                                <i className="fas fa-sync mr-2"></i>
                                {loading ? 'Loading...' : 'Refresh'}
                            </button>
                            <button
                                className="bg-green-600 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                onClick={() => setShowCreateModal(true)}
                            >
                                <i className="fas fa-plus mr-2"></i>
                                Create Artifact
                            </button>
                        </div>
                    </div>

                    {/* Artifacts content */}
                    {loading && artifacts.length === 0 ? (
                        <div className="text-center py-8">
                            <i className="fas fa-spinner fa-spin text-4xl text-gray-400 mb-4"></i>
                            <p className="text-gray-400">Loading artifacts...</p>
                        </div>
                    ) : artifacts.length === 0 ? (
                        <div className="text-center py-12">
                            <i className="fas fa-archive text-6xl text-gray-600 mb-6"></i>
                            <h3 className="text-2xl font-bold text-gray-400 mb-4">No Artifacts Found</h3>
                            <p className="text-gray-500 mb-6">
                                Get started by creating your first artifact. You can store datasets, models, applications, and more.
                            </p>
                            <button
                                className="bg-green-600 hover:bg-green-500 text-white font-bold py-3 px-6 rounded-full transition duration-300 flex items-center mx-auto"
                                onClick={() => setShowCreateModal(true)}
                            >
                                <i className="fas fa-plus mr-2"></i>
                                Create Your First Artifact
                            </button>
                        </div>
                    ) : (
                        <>
                            {/* Info box for artifact management */}
                            <div className="bg-blue-900 bg-opacity-30 border border-blue-700 rounded-lg p-4 mb-6">
                                <div className="flex items-start">
                                    <i className="fas fa-info-circle text-blue-400 mr-3 mt-1"></i>
                                    <div className="text-sm text-blue-200">
                                        <p className="font-medium mb-2">Artifact Management Tips:</p>
                                        <ul className="list-disc list-inside space-y-1 text-blue-300">
                                            <li>Collections can contain other artifacts and support drag & drop file uploads</li>
                                            <li>Click "More Info" on any artifact to view and manage its files with full tree functionality</li>
                                            <li>Only staged artifacts allow file uploads - committed artifacts are read-only</li>
                                            <li>Use the artifact manager API for programmatic access and advanced operations</li>
                                        </ul>
                                    </div>
                                </div>
                            </div>

                        <ArtifactTree
                            artifacts={artifacts}
                            expandedArtifacts={expandedArtifacts}
                            setExpandedArtifacts={setExpandedArtifacts}
                            listArtifacts={listArtifacts}
                            onMoreInfo={setSelectedArtifact}
                            onDelete={handleDelete}
                            onUploadFile={handleUploadFile}
                            onCreateFolder={handleCreateSubArtifact}
                            onCreateChildArtifact={handleCreateChildArtifact}
                            onDragOver={handleDragOver}
                            onDragEnter={handleDragEnter}
                            onDragLeave={handleDragLeave}
                            onDrop={handleDrop}
                        />
                        </>
                    )}

                    {/* Modals */}
                    {selectedArtifact && (
                        <ArtifactInfoModal
                            artifact={selectedArtifact}
                            onClose={() => setSelectedArtifact(null)}
                            listFiles={listFiles}
                            am={am}
                        />
                    )}
                    
                    {showCreateModal && (
                        <CreateArtifactModal
                            onClose={() => setShowCreateModal(false)}
                            am={am}
                            onArtifactCreated={handleArtifactCreated}
                        />
                    )}
                    {showChildCreateModal && (
                        <CreateArtifactModal
                            onClose={() => setShowChildCreateModal(false)}
                            am={am}
                            onArtifactCreated={handleArtifactCreated}
                            presetParentId={presetParentId}
                        />
                    )}
                </div>
            );
        };
        

        const WorkspaceCard = ({ workspace, onInfoClick, onEditClick, onBookmarkClick }) => {
            return (
                <div className="flex flex-col items-start p-6 bg-gray-800 rounded-lg shadow-lg mb-6 w-full relative">
                    <button
                        className="absolute top-2 right-2 text-white"
                        onClick={() => onBookmarkClick(workspace.id)}
                    >
                        <i className="fas fa-bookmark"></i>
                    </button>
                    <h3 className="text-xl font-bold">{workspace.id}</h3>
                    <p className="text-gray-400">{workspace.description}</p>
                        <div className="mt-4 flex justify-between w-full">
                        <div className="flex space-x-4">
                            <button
                                className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                onClick={() => onInfoClick(workspace.id)}
                            >
                                <i className="fas fa-info-circle mr-2"></i> Info
                            </button>
                            <a
                                href={`/${workspace.id}`}
                                className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                            >
                                <i className="fas fa-arrow-right mr-2"></i> Open
                            </a>
                        </div>
                        <button
                            className="bg-yellow-600 hover:bg-yellow-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                            onClick={() => onEditClick(workspace)}
                        >
                            <i className="fas fa-edit mr-2"></i> Edit
                        </button>
                    </div>
                </div>
            );
        };        
        
        const WorkspaceInfoModal = ({ workspaceInfo, onClose }) => {
            return (
                <div className="modal">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">{workspaceInfo.name}</h2>
                            <button onClick={onClose} className="text-white text-2xl">&times;</button>
                        </div>
                        <div className="modal-body">
                            <p><strong>Description:</strong> {workspaceInfo.description || "N/A"}</p>
                            <p><strong>Persistent:</strong> {workspaceInfo.persistent ? "Yes" : "No"}</p>
                            <p><strong>Read-Only:</strong> {workspaceInfo.read_only ? "Yes" : "No"}</p>
                            <p><strong>Owners:</strong> {workspaceInfo.owners.length > 0 ? workspaceInfo.owners.join(", ") : "None"}</p>
                            <p><strong>Applications:</strong> {workspaceInfo.applications ? Object.keys(workspaceInfo.applications).join(", ") : "None"}</p>
                            <p><strong>Service Types:</strong> {workspaceInfo.service_types ? Object.keys(workspaceInfo.service_types).join(", ") : "None"}</p>
                            <p><strong>Docs:</strong> {workspaceInfo.docs || "None"}</p>
                            <p><strong>Config:</strong> <pre>{JSON.stringify(workspaceInfo.config, null, 2)}</pre></p>
                        </div>
                    </div>
                </div>
            );
        };
        const MCPServerModal = ({ onCreateMCPServer, onClose }) => {
            const [serverName, setServerName] = React.useState('my-server');
            const [serverUrl, setServerUrl] = React.useState('');
            const [serverType, setServerType] = React.useState('streamable-http');
            const [appName, setAppName] = React.useState('My MCP Server');
            const [appDescription, setAppDescription] = React.useState('Integration with external MCP servers');
            const [authHeaders, setAuthHeaders] = React.useState('');

            const handleSubmit = async (event) => {
                event.preventDefault();
                
                const mcpConfig = {
                    type: "mcp-server",
                    name: appName,
                    version: "1.0.0",
                    description: appDescription,
                    mcpServers: {
                        [serverName]: {
                            type: serverType,
                            url: serverUrl
                        }
                    }
                };

                // Add auth headers if provided
                if (authHeaders.trim()) {
                    try {
                        const headers = JSON.parse(authHeaders);
                        mcpConfig.mcpServers[serverName].headers = headers;
                    } catch (e) {
                        alert('Invalid JSON in auth headers');
                        return;
                    }
                }

                await onCreateMCPServer(mcpConfig);
                onClose();
            };

            return (
                <div className="modal">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">Add MCP Server</h2>
                            <button onClick={onClose} className="text-white text-2xl">&times;</button>
                        </div>
                        <div className="modal-body">
                            <form onSubmit={handleSubmit}>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">App Name</label>
                                    <input
                                        type="text"
                                        value={appName}
                                        onChange={(e) => setAppName(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Description</label>
                                    <input
                                        type="text"
                                        value={appDescription}
                                        onChange={(e) => setAppDescription(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Server Name</label>
                                    <input
                                        type="text"
                                        value={serverName}
                                        onChange={(e) => setServerName(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Server URL</label>
                                    <input
                                        type="url"
                                        value={serverUrl}
                                        onChange={(e) => setServerUrl(e.target.value)}
                                        placeholder="https://example.com/mcp"
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Transport Type</label>
                                    <select
                                        value={serverType}
                                        onChange={(e) => setServerType(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                    >
                                        <option value="streamable-http">Streamable HTTP</option>
                                        <option value="sse">Server-Sent Events</option>
                                    </select>
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">
                                        Auth Headers (JSON, optional)
                                        <p className="text-gray-500 text-xs mt-1">
                                            {'e.g., {"Authorization": "Bearer token"}'}
                                        </p>
                                    </label>
                                    <textarea
                                        value={authHeaders}
                                        onChange={(e) => setAuthHeaders(e.target.value)}
                                        placeholder='{"Authorization": "Bearer your-token-here"}'
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        rows="3"
                                    />
                                </div>
                                <button
                                    type="submit"
                                    className="bg-purple-600 text-white font-bold py-2 px-4 rounded"
                                >
                                    Add MCP Server
                                </button>
                            </form>
                        </div>
                    </div>
                </div>
            );
        };

        const A2AAgentModal = ({ onCreateA2AAgent, onClose }) => {
            const [agentName, setAgentName] = React.useState('my-agent');
            const [agentUrl, setAgentUrl] = React.useState('');
            const [appName, setAppName] = React.useState('My A2A Agent');
            const [appDescription, setAppDescription] = React.useState('Integration with external A2A agents');

            const handleSubmit = async (event) => {
                event.preventDefault();
                
                const a2aConfig = {
                    type: "a2a-agent",
                    name: appName,
                    version: "1.0.0",
                    description: appDescription,
                    a2aAgents: {
                        [agentName]: {
                            url: agentUrl
                        }
                    }
                };

                await onCreateA2AAgent(a2aConfig);
                onClose();
            };

            return (
                <div className="modal">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">Add A2A Agent</h2>
                            <button onClick={onClose} className="text-white text-2xl">&times;</button>
                        </div>
                        <div className="modal-body">
                            <form onSubmit={handleSubmit}>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">App Name</label>
                                    <input
                                        type="text"
                                        value={appName}
                                        onChange={(e) => setAppName(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Description</label>
                                    <input
                                        type="text"
                                        value={appDescription}
                                        onChange={(e) => setAppDescription(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Agent Name</label>
                                    <input
                                        type="text"
                                        value={agentName}
                                        onChange={(e) => setAgentName(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">
                                        Agent URL
                                        <p className="text-gray-500 text-xs mt-1">
                                            Base URL of the A2A agent (e.g., https://example.com/a2a-agent)
                                        </p>
                                    </label>
                                    <input
                                        type="url"
                                        value={agentUrl}
                                        onChange={(e) => setAgentUrl(e.target.value)}
                                        placeholder="https://example.com/a2a-agent"
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <button
                                    type="submit"
                                    className="bg-orange-600 text-white font-bold py-2 px-4 rounded"
                                >
                                    Add A2A Agent
                                </button>
                            </form>
                        </div>
                    </div>
                </div>
            );
        };

        const CreateWorkspaceModal = ({
            onCreateWorkspace,
            onDeleteWorkspace,
            onClose,
            workspace = {},
            isEditing = false,
        }) => {
            const [id, setId] = React.useState(workspace.id || "");
            const [name, setName] = React.useState(workspace.id || "");
            const [description, setDescription] = React.useState(
                workspace.description || ""
            );
            const [persistent, setPersistent] = React.useState(
                workspace.persistent ?? true
            );
            const [readOnly, setReadOnly] = React.useState(
                workspace.read_only ?? false
            );
            const [overwrite, setOverwrite] = React.useState(true);
            const [owners, setOwners] = React.useState(
                workspace.owners ? workspace.owners.join(", ") : ""
            );
            const handleDelete = async (event) => {
                event.preventDefault();
                if (confirm("Are you sure you want to delete this workspace?")) {
                    await onDeleteWorkspace(workspace.id);
                    onClose();
                }
            };
            const handleSubmit = async (event) => {
                event.preventDefault();
                const ownersArray = owners.split(",").map((owner) => owner.trim());
                await onCreateWorkspace(
                    { id, name, description, owners: ownersArray, persistent, read_only: readOnly },
                    overwrite
                );
                onClose();
            };
        
            return (
                <div className="modal">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h2 className="text-2xl font-bold">
                                {isEditing ? "Edit Workspace" : "Create Workspace"}
                            </h2>
                            <button
                                onClick={onClose}
                                className="text-white text-2xl"
                            >
                                &times;
                            </button>
                        </div>
                        <div className="modal-body">
                            <form onSubmit={handleSubmit}>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">ID
                                        <p className="text-gray-500">A workspace id must contain at least one hyphen (e.g. my-workspace), in lowercase letters, numbers and hyphens only.</p>
                                    </label>
                                    <input
                                        type="text"
                                        value={id}
                                        onChange={(e) => setId(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Name
                                        <p className="text-gray-500">A human-readable name for the workspace.</p>
                                    </label>
                                    <input
                                        type="text"
                                        value={name}
                                        onChange={(e) => setName(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Description
                                        <p className="text-gray-500">A brief description of the workspace, this will be displayed in the workspace list.</p>
                                    </label>
                                    <input
                                        type="text"
                                        value={description}
                                        onChange={(e) => setDescription(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                        required
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Owners (comma-separated)
                                        <p className="text-gray-500">A list of owners who can manage the workspace, it must be a comma-separated list of user ids or email addresses.</p>
                                    </label>
                                    <input
                                        type="text"
                                        value={owners}
                                        onChange={(e) => setOwners(e.target.value)}
                                        className="text-black mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Persistent
                                        <p className="text-gray-500">If checked, the workspace will be persistent and will not be deleted after a period of inactivity.</p>
                                    </label>
                                    <input
                                        type="checkbox"
                                        checked={persistent}
                                        onChange={(e) => setPersistent(e.target.checked)}
                                        className="ml-2"
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Read-Only</label>
                                    <input
                                        type="checkbox"
                                        checked={readOnly}
                                        onChange={(e) => setReadOnly(e.target.checked)}
                                        className="ml-2"
                                    />
                                </div>
                                <div className="mb-4">
                                    <label className="block text-sm font-medium text-gray-200">Overwrite
                                        <p className="text-gray-500">If checked, the workspace will be overwritten if it already exists.</p>
                                    </label>
                                    <input
                                        type="checkbox"
                                        checked={overwrite}
                                        onChange={(e) => setOverwrite(e.target.checked)}
                                        className="ml-2"
                                    />
                                </div>

                                {isEditing && <button
                                    className="bg-red-600 mr-3 text-white font-bold py-2 px-4 rounded"
                                    onClick={(evt) => handleDelete(evt)}
                                >
                                    Delete Workspace
                                </button>}
                                
                                <button
                                    type="submit"
                                    className="bg-blue-600 text-white font-bold py-2 px-4 rounded"
                                >
                                    {isEditing ? "Save Workspace" : "Create Workspace"}
                                </button>
                            </form>
                        </div>
                    </div>
                </div>
            );
        };
        
        // Global drag and drop handlers and utility functions
        let globalUploadProgress = 0;
        let globalSetUploadProgress = null;
        let globalSetFileList = null;
        let globalSetExpandedDirs = null;
        let globalS3 = null;
        let globalListFiles = null;

        // Drag and drop event handlers
        const handleDragOver = (e) => {
            e.preventDefault();
            e.stopPropagation();
            e.dataTransfer.dropEffect = 'copy';
        };

        const handleDragEnter = (e) => {
            e.preventDefault();
            e.stopPropagation();
            // Only add visual feedback to the immediate target
            if (e.target === e.currentTarget || e.currentTarget.contains(e.target)) {
                e.currentTarget.classList.add('bg-gray-600', 'border-blue-500');
            }
        };

        const handleDragLeave = (e) => {
            e.preventDefault();
            e.stopPropagation();
            // Only remove visual feedback if we're leaving the drop zone
            if (!e.currentTarget.contains(e.relatedTarget)) {
                e.currentTarget.classList.remove('bg-gray-600', 'border-blue-500');
            }
        };

        // Utility function to upload a single file to a specific path
        const uploadFileToPath = async (file, targetPath = "", showProgress = true) => {
            try {
                if (showProgress) {
                    window.showLoadingSpinner(`Uploading ${file.name}...`);
                }
                const filePath = targetPath ? `${targetPath}/${file.name}` : file.name;
                                    const presignedUrl = await globalS3.putFile(filePath);

                const response = await axios.put(presignedUrl, file, {
                    headers: {
                        "Content-Type": file.type || "application/octet-stream",
                    },
                    onUploadProgress: (progressEvent) => {
                        if (!progressEvent.total) return;
                        const progress = (progressEvent.loaded / progressEvent.total) * 100;
                        if (showProgress && globalSetUploadProgress) {
                            globalSetUploadProgress(progress);
                        }
                    },
                    timeout: 30000, // 30 second timeout
                });

                if (response.status === 200) {
                    console.log(`File ${file.name} uploaded successfully to ${targetPath || 'root'}`);
                    return true;
                } else {
                    console.error(`File upload failed for ${file.name}:`, response.statusText);
                    throw new Error(`Upload failed with status ${response.status}: ${response.statusText}`);
                }
            } catch (error) {
                console.error(`File upload failed for ${file.name}:`, error);
                throw error; // Re-throw to allow proper error handling upstream
            } finally {
                if (showProgress) {
                    if (globalSetUploadProgress) globalSetUploadProgress(0);
                    window.hideLoadingSpinner();
                }
            }
        };

        // Utility function to create folder structure
        const createFolderStructure = async (folderPath) => {
            try {
                const keepFilePath = folderPath ? `${folderPath}/.keep` : `.keep`;
                const keepFile = new Blob([''], { type: 'text/plain' });
                const presignedUrl = await globalS3.putFile(keepFilePath);
                
                const response = await axios.put(presignedUrl, keepFile, {
                    headers: {
                        "Content-Type": "text/plain",
                    },
                });
                
                return response.status === 200;
            } catch (error) {
                console.error("Folder creation failed", error);
                return false;
            }
        };

        // Enhanced utility function to collect files from directory entries for parallel upload
        const processDirectoryEntryForCollection = async (entry, parentPath = "", filesToUpload = [], emptyFolders = [], includeHidden = false) => {
            // Skip hidden files/folders if includeHidden is false
            if (!includeHidden && entry.name.startsWith('.')) {
                return false;
            }
            
            const entryPath = parentPath ? `${parentPath}/${entry.name}` : entry.name;
            
            if (entry.isFile) {
                try {
                    const file = await new Promise((resolve, reject) => {
                        entry.file(resolve, reject);
                    });
                    
                    filesToUpload.push({ file, targetPath: parentPath });
                    return true;
                } catch (error) {
                    console.error(`Failed to read file ${entry.name}:`, error);
                    return false;
                }
            } else if (entry.isDirectory) {
                const reader = entry.createReader();
                const dirEntries = [];
                
                const readEntries = () => {
                    return new Promise((resolve) => {
                        reader.readEntries((entries) => {
                            if (entries.length > 0) {
                                dirEntries.push(...entries);
                                readEntries().then(resolve);
                            } else {
                                resolve();
                            }
                        });
                    });
                };
                
                await readEntries();
                
                // Process files in this directory
                let hasVisibleChildren = false;
                for (const subEntry of dirEntries) {
                    const processed = await processDirectoryEntryForCollection(subEntry, entryPath, filesToUpload, emptyFolders, includeHidden);
                    if (processed) hasVisibleChildren = true;
                }
                
                // Track empty folders (but only if they don't start with . when hidden files are excluded)
                if (dirEntries.length === 0 || !hasVisibleChildren) {
                    if (includeHidden || !entry.name.startsWith('.')) {
                        emptyFolders.push(entryPath);
                    }
                }
                return true;
            }
            return false;
        };

        // Legacy utility function for backward compatibility (kept for single file uploads)
        const processDirectoryEntry = async (entry, parentPath = "") => {
            const entryPath = parentPath ? `${parentPath}/${entry.name}` : entry.name;
            
            if (entry.isFile) {
                try {
                    const file = await new Promise((resolve, reject) => {
                        entry.file(resolve, reject);
                    });
                    
                    window.showLoadingSpinner(`Uploading ${entryPath}...`);
                    
                    await uploadFileToPath(file, parentPath, false);
                    // Small delay to prevent overwhelming the server
                    await new Promise(resolve => setTimeout(resolve, 100));
                    return true;
                } catch (error) {
                    console.error(`Failed to upload file ${entry.name}:`, error);
                    return false;
                }
            } else if (entry.isDirectory) {
                const reader = entry.createReader();
                const dirEntries = [];
                
                const readEntries = () => {
                    return new Promise((resolve) => {
                        reader.readEntries((entries) => {
                            if (entries.length > 0) {
                                dirEntries.push(...entries);
                                readEntries().then(resolve);
                            } else {
                                resolve();
                            }
                        });
                    });
                };
                
                await readEntries();
                
                // Process files in this directory
                for (const subEntry of dirEntries) {
                    await processDirectoryEntry(subEntry, entryPath);
                }
                
                // Only create .keep file if directory is completely empty
                if (dirEntries.length === 0) {
                    try {
                        window.showLoadingSpinner(`Creating empty folder ${entryPath}...`);
                        const keepFile = new Blob([''], { type: 'text/plain' });
                        // Create the .keep file directly in the folder path
                        const keepFilePath = `${entryPath}/.keep`;
                        const presignedUrl = await globalS3.putFile(keepFilePath);
                        await axios.put(presignedUrl, keepFile, {
                            headers: { "Content-Type": "text/plain" }
                        });
                    } catch (error) {
                        console.error(`Failed to create empty folder ${entryPath}:`, error);
                    }
                }
                return true;
            }
            return false;
        };



        // Enhanced utility function to process dropped items with parallel upload
        const processDroppedItems = async (items, targetPath = "", includeHiddenFiles = false) => {
            try {
                window.showProgressSpinner('Processing dropped items...', { 
                    showLogs: true,
                    title: "Direct File Upload"
                });
                
                window.addProgressLog(`Processing ${items.length} dropped items...`, 'info');
                
                const filesToUpload = [];
                const emptyFolders = [];
                
                // First pass: collect all files from items (including folders)
                for (let i = 0; i < items.length; i++) {
                    const item = items[i];
                    
                    if (item.webkitGetAsEntry) {
                        const entry = item.webkitGetAsEntry();
                        if (entry) {
                                await processDirectoryEntryForCollection(entry, targetPath, filesToUpload, emptyFolders, includeHiddenFiles);
                        }
                    } else if (item.getAsFile) {
                        const file = item.getAsFile();
                        if (file) {
                            filesToUpload.push({ file, targetPath });
                        }
                    }
                }
                
                if (filesToUpload.length === 0 && emptyFolders.length === 0) {
                    window.addProgressLog('No files or folders found to upload', 'warning');
                    window.enableProgressClose();
                    return;
                }
                
                window.addProgressLog(`Found ${filesToUpload.length} files and ${emptyFolders.length} empty folders`, 'info');
                
                // Create empty folders first
                for (const folderPath of emptyFolders) {
                    try {
                        const keepFile = new Blob([''], { type: 'text/plain' });
                        const keepFilePath = `${folderPath}/.keep`;
                        const uploadUrl = await globalS3.putFile(keepFilePath);
                        
                        const xhr = new XMLHttpRequest();
                        xhr.open('PUT', uploadUrl);
                        xhr.setRequestHeader('Content-Type', 'text/plain');
                        await new Promise((resolve, reject) => {
                            xhr.addEventListener('load', () => {
                                if (xhr.status >= 200 && xhr.status < 300) {
                                    window.addProgressLog(`Created empty folder: ${folderPath}`, 'info');
                                    resolve();
                                } else {
                                    reject(new Error(`HTTP ${xhr.status}`));
                                }
                            });
                            xhr.addEventListener('error', () => reject(new Error('Network error')));
                            xhr.send(keepFile);
                        });
                    } catch (error) {
                        window.addProgressLog(`Failed to create empty folder ${folderPath}: ${error.message}`, 'error');
                    }
                }
                
                if (filesToUpload.length === 0) {
                    await refreshFileList(targetPath);
                    window.enableProgressClose();
                    window.updateProgressSpinner('Folders created successfully!');
                    return;
                }
                
                let completedCount = 0;
                let failedCount = 0;

                // Filter files based on hidden file setting
                const filteredUploads = filesToUpload.filter(({ file }) => 
                    shouldIncludeFile(file.webkitRelativePath || file.name, includeHiddenFiles)
                );
                
                window.addProgressLog(`Filtered ${filesToUpload.length} files to ${filteredUploads.length} (hidden files ${includeHiddenFiles ? 'included' : 'excluded'})`, 'info');
                
                const finishUpload = async () => {
                    window.addProgressLog(`Upload complete! ${completedCount} succeeded, ${failedCount} failed`, failedCount > 0 ? 'warning' : 'success');
                    
                    try {
                        await refreshFileList(targetPath);
                        window.addProgressLog('File list refreshed successfully!', 'success');
                    } catch (error) {
                        window.addProgressLog(`Failed to refresh file list: ${error.message}`, 'error');
                    }
                    
                    setTimeout(() => {
                        if (failedCount === 0) {
                            window.updateProgressSpinner('All files uploaded successfully!');
                            window.enableProgressClose();
                        } else {
                            window.updateProgressSpinner(`Upload completed with ${failedCount} errors`);
                            window.enableProgressClose();
                        }
                    }, 1000);
                };
                
                // Upload each file directly
                const uploadPromises = filteredUploads.map(async ({ file, targetPath: fileTargetPath }) => {
                    try {
                        const relativePath = file.webkitRelativePath || file.name;
                        window.addProgressLog(`Starting upload: ${relativePath}`, 'info');
                        
                        // Get upload URL
                        const uploadUrl = await globalS3.putFile(fileTargetPath);
                        
                        return new Promise((resolve, reject) => {
                            const xhr = new XMLHttpRequest();
                            
                            xhr.addEventListener('load', () => {
                                if (xhr.status >= 200 && xhr.status < 300) {
                                    completedCount++;
                                    window.addProgressLog(`✓ ${relativePath} (${(file.size / 1024).toFixed(1)} KB)`, 'success');
                                    resolve();
                                } else {
                                    failedCount++;
                                    window.addProgressLog(`✗ ${relativePath}: HTTP ${xhr.status}`, 'error');
                                    reject(new Error(`HTTP ${xhr.status}`));
                                }
                            });
                            
                            xhr.addEventListener('error', () => {
                                failedCount++;
                                window.addProgressLog(`✗ ${relativePath}: Network error`, 'error');
                                reject(new Error('Network error'));
                            });
                            
                            xhr.open('PUT', uploadUrl);
                            xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
                            xhr.send(file);
                        });
                    } catch (error) {
                        failedCount++;
                        window.addProgressLog(`✗ ${file.webkitRelativePath || file.name}: ${error.message}`, 'error');
                        throw error;
                    }
                });
                
                // Wait for all uploads to complete
                await Promise.allSettled(uploadPromises);
                
                // Finish up
                await finishUpload();
                
            } catch (error) {
                console.error("Failed to process dropped items:", error);
                window.addProgressLog(`Failed to process dropped items: ${error.message}`, 'error');
                window.enableProgressClose();
                window.updateProgressSpinner('Upload failed');
            }
        };

        // Utility function to refresh file list
        const refreshFileList = async (targetPath = "") => {
            if (targetPath) {
                const updatedFiles = await globalListFiles(targetPath);
                if (globalSetExpandedDirs) {
                    globalSetExpandedDirs(prev => ({
                        ...prev,
                        [targetPath]: updatedFiles
                    }));
                }
            } else {
                const updatedFiles = await globalListFiles();
                if (globalSetFileList) globalSetFileList(updatedFiles);
            }
        };

        const handleFileDrop = async (e, targetPath = "") => {
            e.preventDefault();
            e.stopPropagation();
            e.currentTarget.classList.remove('bg-gray-600', 'border-blue-500');
            
            const items = Array.from(e.dataTransfer.items);
            if (items.length > 0) {
                // Use existing processDroppedItems for directory handling
                // Note: filesIncludeHiddenFiles not available in global scope, using default false
                await processDroppedItems(items, targetPath, false);
                            } else {
                    // Use parallel upload for file-only drops
                    const files = Array.from(e.dataTransfer.files);
                    if (files.length > 0) {
                        // Note: filesIncludeHiddenFiles not available in global scope, using default false
                        await handleParallelFileUpload(files, targetPath, false);
                    }
                }
        };

        const handleParallelFileUpload = async (files, targetPath = "", includeHiddenFiles = false) => {
            try {
                window.showProgressSpinner(`Uploading ${files.length} files...`, { 
                    showLogs: true,
                    title: "Direct File Upload"
                });
                
                window.addProgressLog(`Starting upload of ${files.length} files to ${targetPath || 'root'}...`, 'info');
                
                // Filter files based on hidden file setting
                const filteredFiles = filterFiles(files, includeHiddenFiles);
                window.addProgressLog(`Filtered ${files.length} files to ${filteredFiles.length} (hidden files ${includeHiddenFiles ? 'included' : 'excluded'})`, 'info');
                
                let completedCount = 0;
                let failedCount = 0;
                let totalBytes = filteredFiles.reduce((sum, file) => sum + file.size, 0);
                let uploadedBytes = 0;
                
                const finishUpload = async () => {
                    window.addProgressLog(`Upload complete! ${completedCount} succeeded, ${failedCount} failed`, failedCount > 0 ? 'warning' : 'success');
                    
                    try {
                        await refreshFileList(targetPath);
                        window.addProgressLog('File list refreshed successfully!', 'success');
                    } catch (error) {
                        window.addProgressLog(`Failed to refresh file list: ${error.message}`, 'error');
                    }
                    
                    setTimeout(() => {
                        if (failedCount === 0) {
                            window.updateProgressSpinner('Upload completed successfully!');
                            window.enableProgressClose();
                        } else {
                            window.updateProgressSpinner(`Upload completed with ${failedCount} errors`);
                            window.enableProgressClose();
                        }
                    }, 1000);
                };
                
                // Upload each file directly with XMLHttpRequest
                const uploadPromises = filteredFiles.map(async (file) => {
                    try {
                        const filePath = targetPath ? `${targetPath}/${file.name}` : file.name;
                        window.addProgressLog(`Starting upload: ${file.name}`, 'info');
                        
                        // Get upload URL
                        const uploadUrl = await globalS3.putFile(filePath);
                        
                        return new Promise((resolve, reject) => {
                            const xhr = new XMLHttpRequest();
                            
                            xhr.upload.addEventListener('progress', (e) => {
                                if (e.lengthComputable) {
                                    // Simple progress update
                                    const percentage = totalBytes > 0 ? Math.round((uploadedBytes / totalBytes) * 100) : 0;
                                    // Note: This is approximate since we're updating from multiple concurrent uploads
                                }
                            });
                            
                            xhr.addEventListener('load', () => {
                                if (xhr.status >= 200 && xhr.status < 300) {
                                    completedCount++;
                                    uploadedBytes += file.size;
                                    window.addProgressLog(`✓ ${file.name} (${(file.size / 1024).toFixed(1)} KB)`, 'success');
                                    resolve();
                                } else {
                                    failedCount++;
                                    window.addProgressLog(`✗ ${file.name}: HTTP ${xhr.status}`, 'error');
                                    reject(new Error(`HTTP ${xhr.status}`));
                                }
                            });
                            
                            xhr.addEventListener('error', () => {
                                failedCount++;
                                window.addProgressLog(`✗ ${file.name}: Network error`, 'error');
                                reject(new Error('Network error'));
                            });
                            
                            xhr.open('PUT', uploadUrl);
                            xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
                            xhr.send(file);
                        });
                    } catch (error) {
                        failedCount++;
                        window.addProgressLog(`✗ ${file.name}: ${error.message}`, 'error');
                        throw error;
                    }
                });
                
                // Wait for all uploads to complete
                await Promise.allSettled(uploadPromises);
                
                // Finish up
                await finishUpload();
                
            } catch (error) {
                console.error("Failed to upload files:", error);
                window.addProgressLog(`Upload failed: ${error.message}`, 'error');
                window.enableProgressClose();
                window.updateProgressSpinner('Upload failed');
            }
        };

        const handleUploadFolderToPath = async (folderPath) => {
            const fileInput = document.createElement('input');
            fileInput.type = 'file';
            fileInput.webkitdirectory = true;
            fileInput.multiple = true;
            fileInput.onchange = async (event) => {
                const files = Array.from(event.target.files);
                if (files.length === 0) return;
                
                // Note: filesIncludeHiddenFiles not available in global scope, using default false
                await handleParallelFolderUpload(files, folderPath, false);
            };
            fileInput.click();
        };

        const handleParallelFolderUpload = async (files, baseFolderPath, includeHiddenFiles = false) => {
            try {
                window.showProgressSpinner(`Uploading folder with ${files.length} files...`, { 
                    showLogs: true,
                    title: "Direct Folder Upload"
                });
                
                window.addProgressLog(`Starting upload of ${files.length} files to ${baseFolderPath || 'root'}...`, 'info');
                
                // Filter files based on hidden file setting
                const filteredFiles = filterFiles(files, includeHiddenFiles);
                window.addProgressLog(`Filtered ${files.length} files to ${filteredFiles.length} (hidden files ${includeHiddenFiles ? 'included' : 'excluded'})`, 'info');
                
                let completedCount = 0;
                let failedCount = 0;
                
                // Analyze folder structure and identify empty folders (considering only visible files)
                const folderContents = new Map();
                for (const file of filteredFiles) {
                    const relativePath = file.webkitRelativePath;
                    const pathParts = relativePath.split('/');
                    const fileName = pathParts.pop();
                    const fileFolderPath = pathParts.join('/');
                    
                    // Track folder contents
                    if (fileFolderPath) {
                        if (!folderContents.has(fileFolderPath)) {
                            folderContents.set(fileFolderPath, []);
                        }
                        folderContents.get(fileFolderPath).push(fileName);
                    }
                }
                
                // Create .keep files for empty folders first
                for (const [folderPath, contents] of folderContents.entries()) {
                    if (contents.length === 0) {
                        try {
                            const fullFolderPath = baseFolderPath ? `${baseFolderPath}/${folderPath}` : folderPath;
                            const keepFile = new Blob([''], { type: 'text/plain' });
                            const keepFilePath = `${fullFolderPath}/.keep`;
                            const uploadUrl = await globalS3.putFile(keepFilePath);
                            
                            const xhr = new XMLHttpRequest();
                            xhr.open('PUT', uploadUrl);
                            xhr.setRequestHeader('Content-Type', 'text/plain');
                            await new Promise((resolve, reject) => {
                                xhr.addEventListener('load', () => {
                                    if (xhr.status >= 200 && xhr.status < 300) {
                                        window.addProgressLog(`Created empty folder: ${fullFolderPath}`, 'info');
                                        resolve();
                                    } else {
                                        reject(new Error(`HTTP ${xhr.status}`));
                                    }
                                });
                                xhr.addEventListener('error', () => reject(new Error('Network error')));
                                xhr.send(keepFile);
                            });
                        } catch (error) {
                            window.addProgressLog(`Failed to create empty folder ${folderPath}: ${error.message}`, 'error');
                        }
                    }
                }
                
                const finishUpload = async () => {
                    window.addProgressLog(`Folder upload complete! ${completedCount} succeeded, ${failedCount} failed`, failedCount > 0 ? 'warning' : 'success');
                    
                    try {
                        await refreshFileList();
                        window.addProgressLog('File list refreshed successfully!', 'success');
                    } catch (error) {
                        window.addProgressLog(`Failed to refresh file list: ${error.message}`, 'error');
                    }
                    
                    setTimeout(() => {
                        if (failedCount === 0) {
                            window.updateProgressSpinner('Folder uploaded successfully!');
                            window.enableProgressClose();
                        } else {
                            window.updateProgressSpinner(`Folder upload completed with ${failedCount} errors`);
                            window.enableProgressClose();
                        }
                    }, 1000);
                };
                
                // Upload each file directly with XMLHttpRequest
                const uploadPromises = filteredFiles.map(async (file) => {
                    try {
                        const relativePath = file.webkitRelativePath;
                        const pathParts = relativePath.split('/');
                        const fileName = pathParts.pop();
                        const fileFolderPath = pathParts.join('/');
                        const fullPath = baseFolderPath ? 
                            (fileFolderPath ? `${baseFolderPath}/${fileFolderPath}/${fileName}` : `${baseFolderPath}/${fileName}`) :
                            relativePath;
                        
                        window.addProgressLog(`Starting upload: ${relativePath}`, 'info');
                        
                        // Get upload URL
                        const uploadUrl = await globalS3.putFile(fullPath);
                        
                        return new Promise((resolve, reject) => {
                            const xhr = new XMLHttpRequest();
                            
                            xhr.addEventListener('load', () => {
                                if (xhr.status >= 200 && xhr.status < 300) {
                                    completedCount++;
                                    window.addProgressLog(`✓ ${relativePath} (${(file.size / 1024).toFixed(1)} KB)`, 'success');
                                    resolve();
                                } else {
                                    failedCount++;
                                    window.addProgressLog(`✗ ${relativePath}: HTTP ${xhr.status}`, 'error');
                                    reject(new Error(`HTTP ${xhr.status}`));
                                }
                            });
                            
                            xhr.addEventListener('error', () => {
                                failedCount++;
                                window.addProgressLog(`✗ ${relativePath}: Network error`, 'error');
                                reject(new Error('Network error'));
                            });
                            
                            xhr.open('PUT', uploadUrl);
                            xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
                            xhr.send(file);
                        });
                    } catch (error) {
                        failedCount++;
                        window.addProgressLog(`✗ ${file.webkitRelativePath}: ${error.message}`, 'error');
                        throw error;
                    }
                });
                
                // Wait for all uploads to complete
                await Promise.allSettled(uploadPromises);
                
                // Finish up
                await finishUpload();
                
            } catch (error) {
                console.error("Folder upload failed:", error);
                window.addProgressLog(`Folder upload failed: ${error.message}`, 'error');
                window.enableProgressClose();
                window.updateProgressSpinner('Folder upload failed');
            }
        };

        const MainContent = ({
            isCollapsed,
            enabledPanels,
            ws,
            s3,
            am,
            workspaceId,
            panel,
            clients,
            services,
            apps,
            files,
            runningApps,
            onShowDetails,
            onInstallApp,
            isInstallingApp,
            setClients,
            setApps,
            setRunningApps,
            onTakeScreenshot,
        }) => {
        
            const [workspaces, setWorkspaces] = React.useState([]);
            const [showCreateModal, setShowCreateModal] = React.useState(false);
            const [selectedWorkspaceInfo, setSelectedWorkspaceInfo] = React.useState(null);
            const [editingWorkspace, setEditingWorkspace] = React.useState(null);
            const [currentWorkspaceInfo, setCurrentWorkspaceInfo] = React.useState(null);
            const [bookmarkedItems, setBookmarkedItems] = React.useState([]);
            const [uploadProgress, setUploadProgress] = React.useState(0);
            const [fileList, setFileList] = React.useState(files);
            const [selectedApp, setSelectedApp] = React.useState(null);
            const [selectedRunningApp, setSelectedRunningApp] = React.useState(null);
            const [showMCPServerModal, setShowMCPServerModal] = React.useState(false);
            const [showA2AAgentModal, setShowA2AAgentModal] = React.useState(false);
            const [filesIncludeHiddenFiles, setFilesIncludeHiddenFiles] = React.useState(false); // For files panel
        
            // Centralized expandedDirs state
            const [expandedDirs, setExpandedDirs] = React.useState({});

            // Set global references
            React.useEffect(() => {
                globalSetUploadProgress = setUploadProgress;
                globalSetFileList = setFileList;
                globalSetExpandedDirs = setExpandedDirs;
                globalS3 = s3;
                globalListFiles = async (path = '') => {
                    try {
                        const files = await s3.listFiles(path);
                        return files;
                    } catch (error) {
                        console.error("Failed to list files", error);
                        return [];
                    }
                };
            }, [s3]);
        
            React.useEffect(() => {
                setFileList(files); // Keep file list updated
            }, [files]);
        
            React.useEffect(() => {
                const fetchWorkspaces = async () => {
                    if (panel === 'development' && ws) {
                        const workspacesList = await ws.listWorkspaces();
                        console.log('Workspaces:', workspacesList);
                        setWorkspaces(workspacesList);
                    }
                    if (panel === 'dashboard' && ws) {
                        try {
                            const workspaceInfo = await ws.getWorkspaceInfo(workspaceId);
                            console.log('Workspace Info:', workspaceInfo);
                            setCurrentWorkspaceInfo(workspaceInfo);
                        } catch (error) {
                            console.error('Failed to fetch workspace info:', error);
                        }
                    }
                };
                fetchWorkspaces();
            }, [panel, ws]);
        
            // Update bookmarks when currentWorkspaceInfo changes
            React.useEffect(() => {
                // Check for bookmarks in config
                if (currentWorkspaceInfo && currentWorkspaceInfo.config && currentWorkspaceInfo.config.bookmarks) {
                    setBookmarkedItems(currentWorkspaceInfo.config.bookmarks);
                } else {
                    setBookmarkedItems([]);
                }
            }, [currentWorkspaceInfo]);
        
            const handleDeleteWorkspace = async (workspaceId) => {
                try {
                    window.showLoadingSpinner('Deleting Workspace...');
                    await ws.deleteWorkspace(workspaceId);
                    setWorkspaces(await ws.listWorkspaces());
                    setSelectedWorkspaceInfo(null);
                } catch (error) {
                    alert(`Failed to delete workspace: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleCreateWorkspace = async (workspaceData, overwrite) => {
                try {
                    window.showLoadingSpinner('Creating Workspace...');
                    await ws.createWorkspace({ ...workspaceData }, overwrite);
                    setWorkspaces(await ws.listWorkspaces());
                } catch (error) {
                    alert(`Failed to create workspace: ${error}`);
                    throw error;
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleInfoClick = async (workspaceId) => {
                try {
                    window.showLoadingSpinner('Loading Workspace Info...');
                    const workspaceInfo = await ws.getWorkspaceInfo(workspaceId);
                    setSelectedWorkspaceInfo(workspaceInfo);
                } catch (error) {
                    alert(`Failed to get workspace info: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleEditWorkspace = (workspace) => {
                setEditingWorkspace(workspace); // Open the create modal for editing
            };
        
            const handleSaveEditedWorkspace = async (workspaceData, overwrite) => {
                try {
                    window.showLoadingSpinner('Updating Workspace...');
                    await ws.createWorkspace({ ...workspaceData }, overwrite);
                    setWorkspaces(await ws.listWorkspaces());
                    setEditingWorkspace(null); // Close the modal after editing
                } catch (error) {
                    alert(`Failed to update workspace: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleBookmarkWorkspace = async (newWorkspaceId) => {
                try {
                    window.showLoadingSpinner('Bookmarking Workspace...');
                    await ws.bookmark({
                        bookmark_type: 'workspace',
                        id: newWorkspaceId
                    });
                    // Refresh the workspace info
                    const workspaceInfo = await ws.getWorkspaceInfo(workspaceId);
                    setCurrentWorkspaceInfo(workspaceInfo);
                } catch (error) {
                    alert(`Failed to bookmark workspace: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleBookmarkService = async (serviceId) => {
                try {
                    window.showLoadingSpinner('Bookmarking Service...');
                    await ws.bookmark({
                        bookmark_type: 'service',
                        id: serviceId
                    });
                    // Refresh the workspace info
                    const workspaceInfo = await ws.getWorkspaceInfo(workspaceId);
                    setCurrentWorkspaceInfo(workspaceInfo);
                } catch (error) {
                    alert(`Failed to bookmark service: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        
            const handleUnbookmarkItem = async (bookmark_type, id) => {
                try {
                    window.showLoadingSpinner('Removing Bookmark...');
                    await ws.unbookmark({
                        bookmark_type,
                        id
                    });
                    // Refresh the workspace info
                    const workspaceInfo = await ws.getWorkspaceInfo(workspaceId);
                    setCurrentWorkspaceInfo(workspaceInfo);
                } catch (error) {
                    alert(`Failed to unbookmark workspace: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };
        

        
            // Enhanced single file upload using parallel upload manager
            const handleFileUpload = async (file, targetPath = "", includeHiddenFiles = false) => {
                if (file) {
                    await handleParallelFileUpload([file], targetPath, includeHiddenFiles);
                }
            };
        
            const handleFileDownload = async (filePath) => {
                try {
                    const presignedUrl = await s3.getFile(filePath);
                    window.open(presignedUrl, '_blank'); // Trigger file download
                } catch (error) {
                    console.error("Failed to generate download link", error);
                }
            };
        
            const handleFileDelete = async (fullPath, type) => {
                try {
                    let answer;
                    if (type === "directory") {
                        answer = confirm(
                            `Are you sure you want to delete the directory ${fullPath} and all its contents?`
                        );
                    } else {
                        answer = confirm(`Are you sure you want to delete the file ${fullPath}?`);
                    }
                    if (!answer) return;
            
                    window.showLoadingSpinner(`Deleting ${fullPath}...`);
                    
                    // Delete the file or directory
                    if (type === "directory") {
                        await s3.deleteDirectory(fullPath + "/");
                    } else {
                        await s3.deleteFile(fullPath);
                    }
            
                    // Determine the parent directory
                    const parentPath = fullPath.substring(0, fullPath.lastIndexOf("/")) || ""; // Root if no slash
            
                    if (parentPath) {
                        // Refresh the parent directory in expandedDirs
                        const updatedFiles = await listFiles(parentPath);
                        setExpandedDirs((prevState) => ({
                            ...prevState,
                            [parentPath]: updatedFiles,
                        }));
                    } else {
                        // Refresh the top-level file list
                        const updatedFiles = await listFiles("");
                        setFileList(updatedFiles);
                    }
                } catch (error) {
                    console.error("Failed to delete file/directory", error);
                    alert(`Failed to delete ${type === "directory" ? "directory" : "file"}: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };            
        
            const listFiles = async (path = '') => {
                try {
                    const files = await s3.listFiles(path); // Ensure this calls the server to get updated data
                    return files;
                } catch (error) {
                    console.error("Failed to list files", error);
                    return [];
                }
            };

            const handleUploadToFolder = async (folderPath) => {
                const fileInput = document.createElement('input');
                fileInput.type = 'file';
                fileInput.multiple = true;
                fileInput.onchange = async (event) => {
                    const files = Array.from(event.target.files);
                    if (files.length === 0) return;
                    
                    // Use parallel upload for multiple files, fallback to single upload for one file
                    if (files.length === 1) {
                        // Single file - use existing method for quick uploads
                        await handleFileUpload(files[0], folderPath, filesIncludeHiddenFiles);
                    } else {
                        // Multiple files - use parallel upload manager
                        await handleParallelFileUpload(files, folderPath, filesIncludeHiddenFiles);
                    }
                };
                fileInput.click();
            };



            const handleCreateFolder = async (parentPath) => {
                const folderName = prompt('Enter folder name:');
                if (!folderName || !folderName.trim()) {
                    return;
                }
                
                const sanitizedFolderName = folderName.trim().replace(/[^a-zA-Z0-9._-]/g, '_');
                if (sanitizedFolderName !== folderName.trim()) {
                    if (!confirm(`Folder name will be sanitized to: "${sanitizedFolderName}". Continue?`)) {
                        return;
                    }
                }
                
                try {
                    window.showLoadingSpinner(`Creating folder ${sanitizedFolderName}...`);
                    const keepFilePath = parentPath ? `${parentPath}/${sanitizedFolderName}/.keep` : `${sanitizedFolderName}/.keep`;
                    
                    // Create a .keep file to represent the folder
                    const keepFile = new Blob([''], { type: 'text/plain' });
                    const presignedUrl = await s3.putFile(keepFilePath);
                    
                    const response = await axios.put(presignedUrl, keepFile, {
                        headers: {
                            "Content-Type": "text/plain",
                        },
                    });
                    
                    if (response.status === 200) {
                        console.log(`Folder ${sanitizedFolderName} created successfully`);
                        
                        // Refresh the appropriate file list
                        if (parentPath) {
                            const updatedFiles = await listFiles(parentPath);
                            setExpandedDirs(prev => ({
                                ...prev,
                                [parentPath]: updatedFiles
                            }));
                        } else {
                            const updatedFiles = await listFiles();
                            setFileList(updatedFiles);
                        }
                    } else {
                        console.error("Folder creation failed", response.statusText);
                        alert("Folder creation failed: " + response.statusText);
                    }
                } catch (error) {
                    console.error("Folder creation failed", error);
                    alert(`Folder creation failed: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };

            // App management handlers
            const handleUninstallApp = async (appId) => {
                if (!confirm(`Are you sure you want to uninstall app ${appId}?`)) {
                    return;
                }
                try {
                                         // Show progress spinner with logs for uninstall
                     window.showProgressSpinner('Uninstalling Application...', { 
                         showLogs: true,
                         title: "Uninstalling Application"
                     });
                    window.addProgressLog(`Starting uninstall for app: ${appId}`, 'info');
                    
                    if (!ws || !ws.getService) {
                        throw new Error('WebSocket connection not ready. Please wait for the connection to be established.');
                    }
                    
                    window.addProgressLog('Connecting to server...', 'info');
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    
                    window.addProgressLog('Uninstalling application...', 'info');
                    await controller.uninstall(appId);
                    window.addProgressLog('Application uninstalled successfully!', 'success');
                    
                    window.updateProgressSpinner('Refreshing application list...');
                    await refreshApps(ws);
                    window.addProgressLog('Application list refreshed', 'info');
                    
                                         // Allow user to close the dialog
                     setTimeout(() => {
                         window.enableProgressClose();
                         window.updateProgressSpinner('Uninstall completed successfully!');
                     }, 1000);
                    
                } catch (error) {
                    console.error('Failed to uninstall app:', error);
                    window.addProgressLog(`Uninstall failed: ${error.message}`, 'error');
                    
                                         // Allow user to close after error
                     window.enableProgressClose();
                     window.updateProgressSpinner('Uninstall failed');
                }
            };

            const handleStartApp = async (appId) => {
                try {
                                         // Show progress spinner with logs
                     window.showProgressSpinner('Starting Application...', { 
                         showLogs: true,
                         title: "Starting Application"
                     });
                    window.addProgressLog(`Initializing startup for app: ${appId}`, 'info');
                    
                    if (!ws || !ws.getService) {
                        throw new Error('WebSocket connection not ready. Please wait for the connection to be established.');
                    }
                    
                    window.addProgressLog('Connecting to server...', 'info');
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    
                    // Create progress callback
                    const progressCallback = window.createProgressCallback();
                    
                    window.addProgressLog('Starting application with progress tracking...', 'info');
                    const appInfo = await controller.start(appId, {
                        progress_callback: progressCallback,
                        _rkwargs: true
                    });
                    
                    window.addProgressLog('Application started successfully!', 'success');
                    console.log('App started:', appInfo);
                    
                    window.updateProgressSpinner('Refreshing application lists...');
                    // Refresh both apps and running apps lists
                    await refreshApps(ws);
                    await refreshRunningApps(ws);
                    window.addProgressLog('Application lists refreshed.', 'success');
                    
                                         // Allow user to close the dialog
                     setTimeout(() => {
                         window.enableProgressClose();
                         window.updateProgressSpinner('Application started successfully!');
                     }, 1000);
                    
                } catch (error) {
                    console.error('Failed to start app:', error);
                    window.addProgressLog(`Failed to start app: ${error.message}`, 'error');
                    
                                         // Allow user to close after error
                     window.enableProgressClose();
                     window.updateProgressSpinner('Application startup failed');
                }
            };

            const handleStopApp = async (sessionId) => {
                if (!confirm(`Are you sure you want to stop session ${sessionId}?`)) {
                    return;
                }
                try {
                    window.showLoadingSpinner('Stopping Application...');
                    if (!ws || !ws.getService) {
                        throw new Error('WebSocket connection not ready. Please wait for the connection to be established.');
                    }
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    await controller.stop(sessionId);
                    await refreshRunningApps(ws);
                } catch (error) {
                    console.error('Failed to stop app:', error);
                    alert(`Failed to stop app: ${error}`);
                } finally {
                    window.hideLoadingSpinner();
                }
            };



            const refreshApps = async (wsConnection) => {
                try {
                    if (!wsConnection || !wsConnection.getService) {
                        console.warn('WebSocket connection not ready for refreshApps');
                        return;
                    }
                    const controller = await wsConnection.getService('public/server-apps', { case_conversion: 'camel' });
                    const apps = await controller.listApps();
                    setApps(apps);
                } catch (error) {
                    console.error('Failed to refresh apps:', error);
                }
            };

            const refreshRunningApps = async (wsConnection) => {
                try {
                    if (!wsConnection || !wsConnection.getService) {
                        console.warn('WebSocket connection not ready for refreshRunningApps');
                        return;
                    }
                    const controller = await wsConnection.getService('public/server-apps', { case_conversion: 'camel' });
                    const running = await controller.listRunning();
                    setRunningApps(running);
                } catch (error) {
                    console.error('Failed to refresh running apps:', error);
                }
            };

            const handleCreateMCPServer = async (mcpConfig) => {
                try {
                                         // Show progress spinner with logs
                     window.showProgressSpinner('Installing MCP Server...', { 
                         showLogs: true,
                         title: "Installing MCP Server"
                     });
                    window.addProgressLog('Starting MCP server installation...', 'info');
                    
                    if (!ws || !ws.getService) {
                        throw new Error('WebSocket connection not ready. Please wait for the connection to be established.');
                    }
                    
                    window.addProgressLog('Connecting to server...', 'info');
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    
                    // Create progress callback
                    const progressCallback = window.createProgressCallback();
                    
                    window.addProgressLog('Installing MCP server with progress tracking...', 'info');
                    const appInfo = await controller.install({
                        config: mcpConfig,
                        overwrite: true,
                        progress_callback: progressCallback,
                        _rkwargs: true
                    });
                    
                    window.addProgressLog('MCP server installed successfully!', 'success');
                    console.log('MCP Server installed:', appInfo);
                    
                    window.updateProgressSpinner('Refreshing application list...');
                    await refreshApps(ws);
                    window.addProgressLog('Application list refreshed', 'info');
                    
                                         // Allow user to close the dialog
                     setTimeout(() => {
                         window.enableProgressClose();
                         window.updateProgressSpinner('MCP Server installation completed!');
                     }, 1000);
                    
                } catch (error) {
                    console.error('Failed to install MCP server:', error);
                    window.addProgressLog(`MCP server installation failed: ${error.message}`, 'error');
                    
                                         // Allow user to close after error
                     window.enableProgressClose();
                     window.updateProgressSpinner('MCP server installation failed');
                }
            };

            const handleCreateA2AAgent = async (a2aConfig) => {
                try {
                                         // Show progress spinner with logs
                     window.showProgressSpinner('Installing A2A Agent...', { 
                         showLogs: true,
                         title: "Installing A2A Agent"
                     });
                    window.addProgressLog('Starting A2A agent installation...', 'info');
                    
                    if (!ws || !ws.getService) {
                        throw new Error('WebSocket connection not ready. Please wait for the connection to be established.');
                    }
                    
                    window.addProgressLog('Connecting to server...', 'info');
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    
                    // Create progress callback
                    const progressCallback = window.createProgressCallback();
                    
                    window.addProgressLog('Installing A2A agent with progress tracking...', 'info');
                    const appInfo = await controller.install({
                        config: a2aConfig,
                        overwrite: true,
                        progress_callback: progressCallback,
                        _rkwargs: true
                    });
                    
                    window.addProgressLog('A2A agent installed successfully!', 'success');
                    console.log('A2A Agent installed:', appInfo);
                    
                    window.updateProgressSpinner('Refreshing application list...');
                    await refreshApps(ws);
                    window.addProgressLog('Application list refreshed', 'info');
                    
                                         // Allow user to close the dialog
                     setTimeout(() => {
                         window.enableProgressClose();
                         window.updateProgressSpinner('A2A Agent installation completed!');
                     }, 1000);
                    
                } catch (error) {
                    console.error('Failed to install A2A agent:', error);
                    window.addProgressLog(`A2A agent installation failed: ${error.message}`, 'error');
                    
                                         // Allow user to close after error
                     window.enableProgressClose();
                     window.updateProgressSpinner('A2A agent installation failed');
                }
            };

            const onAddMCPServer = () => {
                setShowMCPServerModal(true);
            };

            const onAddA2AAgent = () => {
                setShowA2AAgentModal(true);
            };
        
            return (
                <div
                    className={`main-content transition-all duration-300 ${isCollapsed ? 'ml-16' : 'ml-64'}`}
                >
                    {panel === 'dashboard' && (
                        <>
                            <h1 className="text-4xl font-bold capitalize">Dashboard</h1>
                            {/* Header Section for Workspace Info */}
                            {currentWorkspaceInfo && (
                                <div className="relative p-6 bg-gray-800 rounded-lg shadow-lg m-10">
                                    {/* Bookmark Icon in the Upper Right Corner */}
                                    <button
                                        className="absolute top-4 right-4 text-yellow-400 hover:text-yellow-500 transition duration-300"
                                        onClick={() => handleBookmarkWorkspace(currentWorkspaceInfo.id)}
                                    >
                                        <i className="fas fa-bookmark fa-2x"></i>
                                    </button>

                                    {/* Add cleanup button - new code */}
                                    <button
                                        className="absolute top-4 right-16 text-blue-400 hover:text-blue-500 transition duration-300 flex items-center"
                                        onClick={async () => {
                                            try {
                                                window.showLoadingSpinner('Cleaning up Workspace...');
                                                await window.remoteServer.cleanup();
                                                // Refresh clients list after cleanup
                                                const updatedClients = await ws.listClients();
                                                setClients(updatedClients);
                                            } catch (error) {
                                                console.error('Cleanup failed:', error);
                                                alert(`Failed to cleanup workspace: ${error}`);
                                            } finally {
                                                window.hideLoadingSpinner();
                                            }
                                        }}
                                        title="Remove dead clients and cleanup workspace"
                                    >
                                        <i className="fas fa-broom fa-2x"></i>
                                    </button>
                                
                                    {/* Header Section */}
                                    <div className="flex items-center mb-6">
                                        <i className="fas fa-folder-open fa-2x text-blue-400 mr-4"></i>
                                        <h2 className="text-3xl font-bold text-white">Workspace: {currentWorkspaceInfo.name}</h2>
                                    </div>
                                
                                    {/* Main Info Section */}
                                    <div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-2">
                                        <div>
                                            <p className="text-lg text-gray-400 mb-4 flex items-center">
                                                <i className="fas fa-tag mr-2 text-blue-400"></i>
                                                <strong>ID: </strong> {currentWorkspaceInfo.id}
                                            </p>
                                            <p className="text-lg text-gray-400 mb-4 flex items-center">
                                                <i className="fas fa-tag mr-2 text-blue-400"></i>
                                                <strong>Name: </strong> {currentWorkspaceInfo.name}
                                            </p>
                                            <p className="text-lg text-gray-400 mb-4 flex items-center">
                                                <i className="fas fa-shield-alt mr-2 text-green-400"></i>
                                                <strong>Persistent: </strong> {currentWorkspaceInfo.persistent ? 'Yes' : 'No'}
                                            </p>
                                            <p className="text-lg text-gray-400 mb-4 flex items-center">
                                                <i className="fas fa-lock mr-2 text-red-400"></i>
                                                <strong>Read-Only: </strong> {currentWorkspaceInfo.read_only ? 'Yes' : 'No'}
                                            </p>
                                        </div>
                                        <div>
                                            <div className="flex items-center text-lg text-gray-400 mb-4">
                                                <i className="fas fa-users mr-2 text-yellow-400"></i>
                                                <strong>Owners: </strong>
                                                <div className="flex flex-wrap ml-2">
                                                    {currentWorkspaceInfo.owners ? (
                                                        currentWorkspaceInfo.owners.map((owner, idx) => (
                                                            <span key={idx} className="bg-gray-600 text-white rounded-full px-3 py-1 mr-2 mb-2 text-sm">
                                                                {owner}
                                                            </span>
                                                        ))
                                                    ) : (
                                                        <span>No owners</span>
                                                    )}
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div className="text-gray-300 p-2 rounded-lg mb-3">
                                        <p className="text-md">
                                            <strong>Description: </strong> {currentWorkspaceInfo.description || 'No description available'}
                                        </p>
                                    </div>
                                
                                    {/* Info Box */}
                                    <div className="bg-gray-700 text-gray-300 p-4 rounded-lg mb-6">
                                        <p className="text-md mb-4">
                                            <i className="fas fa-info-circle text-blue-400 mr-2"></i>
                                            A Hypha workspace is an isolated virtual space for connected users, computational clients, and AI agents, similar to an online meeting room. To connect to this workspace, you need to 
                                            <a href="#development" className="text-blue-400 underline ml-1">generate an access token</a>.
                                        </p>
                                    </div>
                                </div>
                                
                                
                            )}
                            {bookmarkedItems.length > 0 && (
                                <>
                                  <hr className="my-8 border-gray-700"></hr>
                                  <div className="flex items-center mb-6">
                                    {/* Icon for bookmarks */}
                                    <i className="fas fa-bookmark fa-2x text-yellow-400 mr-3"></i>
                                    <h2 className="text-2xl font-bold">Bookmarks</h2>
                                  </div>
                                  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-8 mt-6">
                                    {bookmarkedItems.map((item, idx) => (
                                      <div
                                        key={idx}
                                        className="p-6 bg-gray-800 rounded-lg shadow-lg relative hover:shadow-xl transition-shadow duration-300"
                                      >
                                        {/* Icon based on type */}
                                        <div className="flex items-center mb-4">
                                          {item.bookmark_type === "workspace" ? (
                                            <i className="fas fa-folder fa-2x text-blue-400 mr-3"></i>
                                          ) : (
                                            <i className="fas fa-cogs fa-2x text-green-400 mr-3"></i>
                                          )}
                                          <p className="text-white whitespace-pre-wrap break-words">{item.name}</p>
                                        </div>
                                        <p className="text-gray-400 whitespace-pre-wrap break-words">ID: <code>{item.id}</code></p>
                                        {/* Description */}
                                        <p className="text-gray-400 mb-4">{item.description || "No description available"}</p>
                              
                                        {/* Type label */}
                                        <span
                                          className={`text-sm font-semibold ${
                                            item.bookmark_type === "workspace" ? "text-blue-300" : "text-green-300"
                                          } mb-4`}
                                        >
                                          {item.bookmark_type.charAt(0).toUpperCase() + item.bookmark_type.slice(1)}
                                        </span>
                              
                                        {/* Button to go to the workspace (only for workspace type) */}
                                        {item.bookmark_type === "workspace" && (
                                          <a
                                            href={`/${item.id}`}
                                            className="absolute bottom-4 right-4 bg-blue-500 hover:bg-blue-400 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                          >
                                            <i className="fas fa-arrow-right mr-2"></i> Go to Workspace
                                          </a>
                                        )}
                              
                                        {/* Delete Button */}
                                        <button
                                            onClick={() => handleUnbookmarkItem(item.bookmark_type, item.id)}
                                            className="absolute top-4 right-4 text-gray-400 hover:text-red-500 transition duration-300"
                                            >
                                            <i className="fas fa-times fa-2x"></i>
                                            </button>
                                      </div>
                                    ))}
                                  </div>
                                </>
                            )}
                            <hr className="my-8 border-gray-700"></hr>
                            <div className="flex items-center mb-6">
                                <i className="fas fa-users fa-2x text-yellow-400 mr-3"></i>
                                <h2 className="text-2xl font-bold">Clients</h2>
                            </div>
                            <p className="text-xl text-gray-400 mt-4">
                                Clients connected to workspace: <code>{workspaceId}</code>
                            </p>
                            <div className="grid grid-cols-1 md:grid-cols-1 lg:grid-cols-2 gap-8 mt-6">
                                {clients.map(client => (
                                    <ClientCard key={client.id} client={client} />
                                ))}
                            </div>
                            <hr className="my-8 border-gray-700"></hr>
                            <div className="flex items-center mb-6">
                                <i className="fas fa-cogs fa-2x text-green-400 mr-3"></i>
                                <h2 className="text-2xl font-bold">Services</h2>
                            </div>
                            <p className="text-xl text-gray-400 mt-4">
                                Services available in workspace: <code>{workspaceId}</code>
                            </p>
                            <div className="grid grid-cols-1 md:grid-cols-1 lg:grid-cols-2 gap-8 mt-6">
                                {services.map(service => (
                                    service.type !== "built-in" && (
                                        <ServiceCard 
                                            key={service.id} 
                                            service={service} 
                                            onBookmarkService={handleBookmarkService} 
                                            onShowDetails={onShowDetails} 
                                        />
                                    )
                                ))}
                            </div>
                        </>
                    )}
        
                    {panel === 'applications' && (
                        <>
                            <h1 className="text-4xl font-bold capitalize">Applications</h1>
                            <div
                                style={{ display: 'block', width: '100%', height: '100%', zIndex: 1000 }}
                                id="hypha-window-container"
                            ></div>
                            <p className="text-xl text-gray-400 mt-4">
                                Applications installed in workspace: <code>{workspaceId}</code>
                            </p>
                            <div className="flex gap-4 mt-6">
                                {/* Split button: Main area for New App, small icon for Install From URL */}
                                <div className={`flex rounded-full overflow-hidden ${
                                    isInstallingApp || !ws ? 'opacity-50' : ''
                                }`}>
                                    {/* Main button for New App */}
                                    <button
                                        className={`font-bold py-2 px-4 transition duration-300 flex items-center ${
                                            isInstallingApp || !ws
                                                ? 'bg-gray-700 cursor-not-allowed' 
                                                : 'bg-green-600 hover:bg-green-500'
                                        } text-white`}
                                        onClick={() => window.loadCodeEditor(ws, refreshApps)}
                                        disabled={isInstallingApp || !ws}
                                    >
                                        <i className="fas fa-code mr-2"></i> New App
                                    </button>
                                    {/* Small icon button for Install From URL */}
                                    <button
                                        className={`font-bold py-2 px-3 border-l border-gray-500 transition duration-300 flex items-center ${
                                            isInstallingApp || !ws
                                                ? 'bg-gray-600 cursor-not-allowed' 
                                                : 'bg-gray-600 hover:bg-gray-500'
                                        } text-white`}
                                        onClick={() => onInstallApp()}
                                        disabled={isInstallingApp || !ws}
                                        title="Install From URL"
                                    >
                                        {isInstallingApp ? (
                                            <i className="fas fa-spinner fa-spin"></i>
                                        ) : (
                                            <i className="fas fa-link"></i>
                                        )}
                                    </button>
                                </div>
                                <button
                                    className={`font-bold py-2 px-4 rounded-full transition duration-300 flex items-center ${
                                        isInstallingApp || !ws
                                            ? 'bg-gray-700 cursor-not-allowed' 
                                            : 'bg-purple-600 hover:bg-purple-500'
                                    } text-white`}
                                    onClick={() => onAddMCPServer()}
                                    disabled={isInstallingApp || !ws}
                                >
                                    <i className="fas fa-cogs mr-2"></i> Add MCP Server
                                </button>
                                <button
                                    className={`font-bold py-2 px-4 rounded-full transition duration-300 flex items-center ${
                                        isInstallingApp || !ws
                                            ? 'bg-gray-700 cursor-not-allowed' 
                                            : 'bg-orange-600 hover:bg-orange-500'
                                    } text-white`}
                                    onClick={() => onAddA2AAgent()}
                                    disabled={isInstallingApp || !ws}
                                >
                                    <i className="fas fa-robot mr-2"></i> Add A2A Agent
                                </button>
                                <button
                                    className={`font-bold py-2 px-4 rounded-full transition duration-300 flex items-center ${
                                        isInstallingApp || !ws
                                            ? 'bg-gray-700 cursor-not-allowed' 
                                            : 'bg-gray-600 hover:bg-gray-500'
                                    } text-white`}
                                    onClick={() => refreshApps(ws)}
                                    disabled={isInstallingApp || !ws}
                                >
                                    <i className="fas fa-sync mr-2"></i> Refresh
                                </button>
                            </div>
                            
                            <hr className="my-8 border-gray-700"></hr>
                            
                            <div className="flex items-center mb-6">
                                <i className="fas fa-th-large fa-2x text-blue-400 mr-3"></i>
                                <h2 className="text-2xl font-bold">Installed Applications</h2>
                            </div>
                            
                            {apps.length === 0 ? (
                                <div className="text-center py-8 text-gray-400">
                                    <i className="fas fa-inbox text-4xl mb-4"></i>
                                    <p>No apps installed</p>
                                </div>
                            ) : (
                                <div className="grid grid-cols-1 md:grid-cols-1 lg:grid-cols-2 gap-8">
                                    {apps.map(app => (
                                        <AppCard 
                                            key={app.id} 
                                            app={app} 
                                            onUninstall={handleUninstallApp}
                                            onShowDetails={setSelectedApp}
                                            onStart={handleStartApp}
                                        />
                                    ))}
                                </div>
                            )}
                            
                            <hr className="my-8 border-gray-700"></hr>
                            
                            <div className="flex items-center justify-between mb-6">
                                <div className="flex items-center">
                                    <i className="fas fa-play-circle fa-2x text-green-400 mr-3"></i>
                                    <h2 className="text-2xl font-bold">Running Applications</h2>
                                </div>
                                <button
                                    className={`font-bold py-2 px-4 rounded-full transition duration-300 flex items-center ${
                                        isInstallingApp || !ws
                                            ? 'bg-gray-700 cursor-not-allowed' 
                                            : 'bg-gray-600 hover:bg-gray-500'
                                    } text-white`}
                                    onClick={() => refreshRunningApps(ws)}
                                    disabled={isInstallingApp || !ws}
                                >
                                    <i className="fas fa-sync mr-2"></i> Refresh
                                </button>
                            </div>
                            
                            {runningApps.length === 0 ? (
                                <div className="text-center py-8 text-gray-400">
                                    <i className="fas fa-sleep text-4xl mb-4"></i>
                                    <p>No apps currently running</p>
                                </div>
                            ) : (
                                <div className="grid grid-cols-1 md:grid-cols-1 lg:grid-cols-2 gap-8">
                                    {runningApps.map(app => (
                                        <RunningAppCard 
                                            key={app.id} 
                                            app={app} 
                                            onStop={handleStopApp}
                                            onShowDetails={setSelectedRunningApp}
                                            onTakeScreenshot={onTakeScreenshot}
                                        />
                                    ))}
                                </div>
                            )}
                        </>
                    )}
        
                    {panel === 'files' && (
                        <>
                            <h1 className="text-4xl font-bold capitalize">Files</h1>
                            <p className="text-xl text-gray-400 mt-4">
                                Files in workspace: <code>{workspaceId}</code>
                            </p>
                            
                            {/* Root folder management buttons */}
                            <div className="flex flex-wrap items-center gap-4 mt-6">
                                <div className="flex gap-4">
                                <button
                                    className="bg-green-600 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                    onClick={() => handleUploadToFolder("")}
                                >
                                    <i className="fas fa-upload mr-2"></i> Upload Files
                                </button>
                                <button
                                    className="bg-purple-600 hover:bg-purple-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                    onClick={() => handleUploadFolderToPath("")}
                                >
                                    <i className="fas fa-folder-open mr-2"></i> Upload Folder
                                </button>
                                <button
                                    className="bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                    onClick={() => handleCreateFolder("")}
                                >
                                    <i className="fas fa-folder-plus mr-2"></i> Create Folder
                                </button>
                                </div>
                                <div className="flex items-center gap-2 bg-gray-800 px-4 py-2 rounded-full border border-gray-600">
                                    <input
                                        type="checkbox"
                                        id="filesIncludeHidden"
                                        checked={filesIncludeHiddenFiles}
                                        onChange={(e) => setFilesIncludeHiddenFiles(e.target.checked)}
                                        className="w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2"
                                    />
                                    <label htmlFor="filesIncludeHidden" className="text-sm text-gray-300 cursor-pointer">
                                        Include hidden files (.DS_Store, .gitignore, etc.)
                                    </label>
                                </div>
                            </div>
                            
                            <div 
                                className="p-4 border-dashed border-4 border-gray-600 rounded mt-6 transition-all duration-200"
                                onDragOver={handleDragOver}
                                onDragEnter={handleDragEnter}
                                onDragLeave={handleDragLeave}
                                onDrop={(e) => handleFileDrop(e, "")}
                            >
                                <p className="text-center text-gray-500">
                                    Drag and drop files or folders here to upload to root folder
                                </p>
                                <p className="text-center text-gray-400 text-sm mt-2">
                                    Supports nested folder structures
                                </p>
                                {!!uploadProgress && (
                                    <div className="w-full bg-gray-600 h-4 rounded relative flex items-center justify-center mt-4">
                                        <div
                                            className="bg-blue-500 h-4 rounded"
                                            style={{ width: `${uploadProgress}%` }}
                                        ></div>
                                        <span className="absolute text-white text-sm">
                                            {Math.round(uploadProgress, 1)}%
                                        </span>
                                    </div>
                                )}
                            </div>
                            <div className="mt-6">
                                {fileList.length === 0 ? (
                                    <p>No files available.</p>
                                ) : (
                                    <FileTree
                                        files={fileList}
                                        onDelete={handleFileDelete}
                                        onDownload={handleFileDownload}
                                        listFiles={listFiles}
                                        // Pass the centralized expandedDirs and setExpandedDirs
                                        expandedDirs={expandedDirs}
                                        setExpandedDirs={setExpandedDirs}
                                        onUploadToFolder={handleUploadToFolder}
                                        onCreateFolder={handleCreateFolder}
                                        onDragOver={handleDragOver}
                                        onDragEnter={handleDragEnter}
                                        onDragLeave={handleDragLeave}
                                        onDrop={handleFileDrop}
                                        onUploadFolderToPath={handleUploadFolderToPath}
                                    />
                                )}
                            </div>
                        </>
                    )}
        
                    {panel === 'development' && (
                        <>
                            <h1 className="text-4xl font-bold capitalize">Development</h1>


                            <hr className="my-8 border-gray-700"></hr>
        
                            <h2 className="text-2xl font-bold mt-5">
                                Workspaces <i className="fas fa-folder-open text-xl text-gray-400"></i>
                            </h2>
                            <p className="text-xl text-gray-400 mt-4">
                                Workspaces accessible to you
                            </p>
                            <div className="flex justify-between items-center mt-6">
                                <button
                                    className="bg-green-600 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-full transition duration-300 flex items-center"
                                    onClick={() => setShowCreateModal(true)}
                                >
                                    <i className="fas fa-plus mr-2"></i> Create Workspace
                                </button>
                            </div>
                            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-8 mt-6">
                                {workspaces.map((workspace) => (
                                    <WorkspaceCard
                                        key={workspace.id}
                                        workspace={workspace}
                                        onInfoClick={handleInfoClick}
                                        onEditClick={handleEditWorkspace}
                                        onBookmarkClick={handleBookmarkWorkspace}
                                    />
                                ))}
                            </div>

                            <hr className="my-8 border-gray-700"></hr>

                            <h2 className="text-2xl font-bold mt-5">
                                Connection Tokens <i className="fas fa-key text-xl text-gray-400"></i>
                            </h2>
                            <TokenPanel
                                workspaceId={workspaceId}
                                onGenerateToken={async (workspace, expiryTime, clientId, permission, extraScopes) => {
                                    const tokenConfig = { expires_in: expiryTime, workspace };
                                    if (clientId && clientId.trim()) {
                                        tokenConfig.client_id = clientId.trim();
                                    }
                                    if (permission && permission !== 'read_write') {
                                        tokenConfig.permission = permission;
                                    }
                                    if (extraScopes && extraScopes.length > 0) {
                                        tokenConfig.extra_scopes = extraScopes;
                                    }
                                    const token = await ws.generateToken(tokenConfig);
                                    return token;
                                }}
                            />

                            <hr className="my-8 border-gray-700"></hr>

                            <h2 className="text-2xl font-bold mt-5">
                                Environment Variables <i className="fas fa-cog text-xl text-gray-400"></i>
                            </h2>
                            <EnvManagementPanel ws={ws} />
                        </>
                    )}
                    { panel === 'artifacts' && (
                        <>
                            <h1 className="text-4xl font-bold capitalize">Artifacts</h1>
                            <p className="text-xl text-gray-400 mt-4">
                                Artifacts in workspace: <code>{workspaceId}</code>
                            </p>
                            <div className="mt-6">
                                <ArtifactsPanel am={am} />
                            </div>
                        </>
                    )}
        
                    {showCreateModal && (
                        <CreateWorkspaceModal
                            onDeleteWorkspace={handleDeleteWorkspace}
                            onCreateWorkspace={handleCreateWorkspace}
                            onClose={() => setShowCreateModal(false)}
                        />
                    )}
        
                    {editingWorkspace && (
                        <CreateWorkspaceModal
                            workspace={editingWorkspace} // Prefill with existing workspace data
                            onDeleteWorkspace={handleDeleteWorkspace}
                            onCreateWorkspace={handleSaveEditedWorkspace} // Save edited data
                            onClose={() => setEditingWorkspace(null)}
                            isEditing={true} // Indicator to show that it's editing mode
                        />
                    )}
        
                    {selectedWorkspaceInfo && (
                        <WorkspaceInfoModal
                            workspaceInfo={selectedWorkspaceInfo}
                            onClose={() => setSelectedWorkspaceInfo(null)}
                        />
                    )}
                    
                    {selectedApp && (
                        <AppDetailsModal
                            app={selectedApp}
                            onClose={() => setSelectedApp(null)}
                        />
                    )}
                    
                    {selectedRunningApp && (
                        <AppDetailsModal
                            app={selectedRunningApp}
                            onClose={() => setSelectedRunningApp(null)}
                        />
                    )}
                    
                    {showMCPServerModal && (
                        <MCPServerModal
                            onCreateMCPServer={handleCreateMCPServer}
                            onClose={() => setShowMCPServerModal(false)}
                        />
                    )}
                    
                    {showA2AAgentModal && (
                        <A2AAgentModal
                            onCreateA2AAgent={handleCreateA2AAgent}
                            onClose={() => setShowA2AAgentModal(false)}
                        />
                    )}
                    
                    <footer className="bg-gray-900 text-gray-400 py-6 mt-16">
                        <div className="container mx-auto text-center">
                            <p>Hypha is an open-source platform released under the MIT license.</p>
                            <p>
                                Visit our <a href="https://github.com/amun-ai/hypha" target="_blank" className="text-gray-300 hover:text-white">GitHub repository</a> for more information.
                            </p>
                        </div>
                    </footer>
                </div>
            );
        };

        const config = window.defaultService.getServerConfig();

        const getActivePanelFromHash = () => {
            const hash = window.location.hash.slice(1); // Remove the "#" from the hash
            return hash || 'dashboard'; // Default to 'dashboard' panel if no hash
        };

        const App = () => {
            const [isCollapsed, setIsCollapsed] = React.useState(false);
            const [enabledPanels, setEnabledPanels] = React.useState(['dashboard', 'development']);
            const [activePanel, setActivePanel] = React.useState(getActivePanelFromHash);
            const [clients, setClients] = React.useState([]);
            const [services, setServices] = React.useState([]);
            const [apps, setApps] = React.useState([]);
            const [runningApps, setRunningApps] = React.useState([]);
            const [files, setFiles] = React.useState([]);
            const [ws, setWs] = React.useState(null);
            const [s3, setS3] = React.useState(null);
            const [am, setAM] = React.useState(null);
            const [selectedService, setSelectedService] = React.useState(null);
            const [isInstallingApp, setIsInstallingApp] = React.useState(false);
            const [isLoadingSpinnerVisible, setIsLoadingSpinnerVisible] = React.useState(true); // Show loading initially
            const [loadingMessage, setLoadingMessage] = React.useState('Connecting to Hypha server...');
            const [showSpinnerLogs, setShowSpinnerLogs] = React.useState(false);
            const [spinnerLogs, setSpinnerLogs] = React.useState([]);
            const [spinnerCloseEnabled, setSpinnerCloseEnabled] = React.useState(false);
            const [spinnerTitle, setSpinnerTitle] = React.useState("Operation Progress");
            const [spinnerRetryAction, setSpinnerRetryAction] = React.useState(null);
            const [includeHiddenFiles, setIncludeHiddenFiles] = React.useState(false);
            const [screenshotData, setScreenshotData] = React.useState(null);
            const [screenshotSessionId, setScreenshotSessionId] = React.useState(null);
            const [screenshotAppName, setScreenshotAppName] = React.useState(null);
        
            // Expose spinner control functions globally for code editor and other components
            window.showLoadingSpinner = (message = 'Loading...') => {
                setLoadingMessage(message);
                setShowSpinnerLogs(false);
                setSpinnerLogs([]);
                setSpinnerCloseEnabled(false);
                setSpinnerTitle("Operation Progress");
                setIsLoadingSpinnerVisible(true);
            };
            
            window.hideLoadingSpinner = () => {
                setIsLoadingSpinnerVisible(false);
                setLoadingMessage('Loading...');
                setShowSpinnerLogs(false);
                setSpinnerLogs([]);
                setSpinnerCloseEnabled(false);
                setSpinnerTitle("Operation Progress");
            };
            
            // Enhanced spinner with log functionality
            window.showProgressSpinner = (message = 'Processing...', options = {}) => {
                const { showLogs = true, clearLogs = true, title = "Operation Progress" } = options;
                setLoadingMessage(message);
                setShowSpinnerLogs(showLogs);
                setSpinnerCloseEnabled(false); // Always start disabled
                setSpinnerTitle(title);
                if (clearLogs) {
                    setSpinnerLogs([]);
                }
                // Reset hidden files setting to default for each new upload session
                if (showLogs) {
                    setIncludeHiddenFiles(false);
                }
                setIsLoadingSpinnerVisible(true);
            };
            
            window.addProgressLog = (message, type = 'info') => {
                const logEntry = {
                    message,
                    type, // 'info', 'success', 'warning', 'error'
                    timestamp: new Date().toISOString()
                };
                setSpinnerLogs(prev => [...prev, logEntry]);
            };
            
            window.updateProgressSpinner = (message) => {
                setLoadingMessage(message);
            };
            
            window.enableProgressClose = () => {
                setSpinnerCloseEnabled(true);
            };

            window.addRetryButton = (onRetry) => {
                if (typeof setSpinnerRetryAction === 'function') {
                    setSpinnerRetryAction(() => onRetry);
                }
            };
            
            window.hideProgressSpinner = () => {
                setIsLoadingSpinnerVisible(false);
                setLoadingMessage('Loading...');
                setShowSpinnerLogs(false);
                setSpinnerLogs([]);
                setSpinnerCloseEnabled(false);
                setSpinnerTitle("Operation Progress");
                setSpinnerRetryAction(null);
                setIncludeHiddenFiles(false);
            };
            
            // Helper to create a progress callback function
            window.createProgressCallback = () => {
                return (progress) => {
                    console.log('Progress callback received:', progress);
                    
                    // Handle the new simplified format: {type, message}
                    if (progress.message) {
                        const type = progress.type || 'info';
                        window.addProgressLog(progress.message, type);
                        
                        // Update the main spinner message for important updates
                        if (type === 'success' || type === 'error') {
                            window.updateProgressSpinner(progress.message);
                        }
                    }
                    
                    // Legacy support for other properties (if any)
                    if (progress.step) {
                        window.addProgressLog(`Step: ${progress.step}`, 'info');
                    }
                    
                    if (progress.progress !== undefined) {
                        window.addProgressLog(`Progress: ${progress.progress}%`, 'info');
                    }
                    
                    if (progress.error) {
                        window.addProgressLog(`Error: ${progress.error}`, 'error');
                    }
                    
                    if (progress.warning) {
                        window.addProgressLog(`Warning: ${progress.warning}`, 'warning');
                    }
                    
                    if (progress.success) {
                        window.addProgressLog(`Success: ${progress.success}`, 'success');
                    }
                    
                    // For debugging: log the entire progress object if it has unexpected properties
                    const knownProps = ['message', 'type', 'step', 'progress', 'error', 'warning', 'success'];
                    const unknownProps = Object.keys(progress).filter(key => !knownProps.includes(key));
                    if (unknownProps.length > 0) {
                        window.addProgressLog(`Additional info: ${JSON.stringify(Object.fromEntries(unknownProps.map(key => [key, progress[key]])))}`, 'info');
                    }
                };
            };

            // Adaptive Parallel File Upload Manager
            class ParallelUploadManager {
                constructor(maxWorkers = 10) {
                    this.instanceId = Math.random().toString(36).substr(2, 9); // Add unique ID
                    this.maxWorkers = maxWorkers;
                    this.queue = [];
                    this.activeUploads = new Map();
                    this.workers = [];
                    this.isRunning = false;
                    this.failedUploads = []; // Track failed uploads for retry
                    this.completedUploads = []; // Track successful uploads
                    this.stats = {
                        total: 0,
                        completed: 0,
                        failed: 0,
                        bytes: {
                            total: 0,
                            uploaded: 0
                        }
                    };
                    this.onProgress = null;
                    this.onComplete = null;
                    this.onError = null;
                    this.onRetryAvailable = null; // Callback when retry is available
                }

                addUpload(uploadJob) {
                    // uploadJob should have: { file, getUploadUrl, onFileComplete, onFileError, targetPath }
                    const jobId = `${Date.now()}-${Math.random()}`;
                    const job = {
                        id: jobId,
                        ...uploadJob,
                        status: 'queued',
                        startTime: null,
                        endTime: null,
                        bytesUploaded: 0
                    };
                    
                    this.queue.push(job);
                    this.stats.total++;
                    this.stats.bytes.total += job.file.size;
                    
                    // DISABLED AUTO-START to prevent conflicts with artifact uploads
                    // The caller must explicitly call start() when ready
                    // if (!this.isRunning) {
                    //     this.start();
                    // }
                    
                    return jobId;
                }

                async start() {
                    if (this.isRunning) return;
                    
                    this.isRunning = true;
                    console.log(`Starting parallel upload manager with ${this.maxWorkers} workers`);
                    
                    // Create workers
                    for (let i = 0; i < this.maxWorkers; i++) {
                        this.createWorker(i);
                    }
                }

                async createWorker(workerId) {
                    const worker = async () => {
                        while (this.isRunning && (this.queue.length > 0 || this.activeUploads.size > 0)) {
                            if (this.queue.length === 0) {
                                // Wait a bit and check again
                                await new Promise(resolve => setTimeout(resolve, 100));
                                continue;
                            }

                            const job = this.queue.shift();
                            if (!job) continue;

                            job.status = 'uploading';
                            job.startTime = Date.now();
                            this.activeUploads.set(job.id, job);

                            try {
                                await this.executeUpload(job, workerId);
                                
                                job.status = 'completed';
                                job.endTime = Date.now();
                                this.stats.completed++;
                                // Don't add bytes here - they're already tracked in progress handler or executeUpload
                                this.completedUploads.push(job);
                                
                                if (job.onFileComplete) {
                                    job.onFileComplete(job);
                                }
                                
                            } catch (error) {
                                job.status = 'failed';
                                job.endTime = Date.now();
                                job.error = error;
                                this.stats.failed++;
                                // Subtract any bytes that were uploaded but failed
                                this.stats.bytes.uploaded -= job.bytesUploaded;
                                this.failedUploads.push(job);
                                
                                console.error(`Upload failed for ${job.file.name}:`, error);
                                
                                if (job.onFileError) {
                                    job.onFileError(job, error);
                                }
                                
                                if (this.onError) {
                                    this.onError(job, error);
                                }
                            } finally {
                                this.activeUploads.delete(job.id);
                                this.updateProgress();
                            }
                        }
                    };

                    this.workers.push(worker());
                }

                async executeUpload(job, workerId) {
                    const { file, getUploadUrl, targetPath } = job;
                    
                    console.log(`Worker ${workerId}: Uploading ${file.name} to ${targetPath || 'root'}`);
                    
                    try {
                        // Get upload URL
                        const filePath = targetPath ? `${targetPath}/${file.name}` : file.name;
                        const uploadUrl = await getUploadUrl(filePath);
                        
                        if (!uploadUrl) {
                            throw new Error('Failed to get upload URL');
                        }
                        
                        console.log(`Worker ${workerId}: Got upload URL for ${file.name}`);
                        
                        // Create XMLHttpRequest for progress tracking
                        return new Promise((resolve, reject) => {
                        const xhr = new XMLHttpRequest();
                        
                        xhr.upload.addEventListener('progress', (event) => {
                            if (event.lengthComputable) {
                                const oldUploaded = job.bytesUploaded;
                                job.bytesUploaded = event.loaded;
                                
                                // Update global stats
                                this.stats.bytes.uploaded += (event.loaded - oldUploaded);
                                this.updateProgress();
                            }
                        });
                        
                        xhr.addEventListener('load', () => {
                            console.log(`Worker ${workerId}: Upload completed for ${file.name} with status ${xhr.status}`);
                            if (xhr.status >= 200 && xhr.status < 300) {
                                // Ensure final byte count is correct
                                if (job.bytesUploaded < job.file.size) {
                                    const remaining = job.file.size - job.bytesUploaded;
                                    job.bytesUploaded = job.file.size;
                                    this.stats.bytes.uploaded += remaining;
                                }
                                resolve();
                            } else {
                                reject(new Error(`Upload failed with status ${xhr.status}: ${xhr.statusText}`));
                            }
                        });
                        
                        xhr.addEventListener('error', () => {
                            console.error(`Worker ${workerId}: Network error uploading ${file.name}`);
                            reject(new Error('Upload failed due to network error'));
                        });
                        
                        xhr.addEventListener('abort', () => {
                            console.error(`Worker ${workerId}: Upload aborted for ${file.name}`);
                            reject(new Error('Upload aborted'));
                        });
                        
                        console.log(`Worker ${workerId}: Starting XMLHttpRequest for ${file.name}`);
                        xhr.open('PUT', uploadUrl);
                        xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
                        xhr.send(file);
                    });
                        
                    } catch (error) {
                        console.error(`Worker ${workerId}: Exception in executeUpload for ${file.name}:`, error);
                        throw error;
                    }
                }

                updateProgress() {
                    const progress = {
                        total: this.stats.total,
                        completed: this.stats.completed,
                        failed: this.stats.failed,
                        active: this.activeUploads.size,
                        queued: this.queue.length,
                        percentage: this.stats.total > 0 ? Math.round((this.stats.completed / this.stats.total) * 100) : 0,
                        bytesPercentage: this.stats.bytes.total > 0 ? Math.round((this.stats.bytes.uploaded / this.stats.bytes.total) * 100) : 0,
                        bytesTotal: this.stats.bytes.total,
                        bytesUploaded: this.stats.bytes.uploaded
                    };
                    
                    if (this.onProgress) {
                        this.onProgress(progress);
                    }
                    
                    // Check if all uploads are complete
                    console.log(`Progress check: completed=${this.stats.completed}, failed=${this.stats.failed}, total=${this.stats.total}, queue=${this.queue.length}, active=${this.activeUploads.size}`);
                    if (this.stats.completed + this.stats.failed >= this.stats.total && this.queue.length === 0 && this.activeUploads.size === 0) {
                        console.log('All uploads complete, triggering callbacks');
                        this.stop();
                        if (this.onComplete) {
                            console.log('Calling onComplete callback');
                            try {
                                this.onComplete(this.stats);
                            } catch (error) {
                                console.error('Error in onComplete callback:', error);
                            }
                        } else {
                            console.warn('No onComplete callback registered');
                        }
                        
                        // Notify if retry is available
                        if (this.failedUploads.length > 0 && this.onRetryAvailable) {
                            this.onRetryAvailable(this.failedUploads.length);
                        }
                    }
                }

                stop() {
                    this.isRunning = false;
                    console.log('Parallel upload manager stopped');
                }

                reset() {
                    this.stop();
                    this.queue = [];
                    this.activeUploads.clear();
                    this.workers = [];
                    this.failedUploads = [];
                    this.completedUploads = [];
                    this.stats = {
                        total: 0,
                        completed: 0,
                        failed: 0,
                        bytes: {
                            total: 0,
                            uploaded: 0
                        }
                    };
                }

                // Retry failed uploads
                retryFailedUploads() {
                    if (this.failedUploads.length === 0) {
                        console.log('No failed uploads to retry');
                        return;
                    }

                    console.log(`Retrying ${this.failedUploads.length} failed uploads`);
                    
                    // Reset failed uploads back to queue
                    const failedJobs = [...this.failedUploads];
                    this.failedUploads = [];
                    
                    // Reset stats for failed uploads
                    this.stats.failed = 0;
                    this.stats.total = this.stats.completed + failedJobs.length;
                    
                    // Re-add failed jobs to queue
                    for (const job of failedJobs) {
                        job.status = 'queued';
                        job.error = null;
                        job.startTime = null;
                        job.endTime = null;
                        job.bytesUploaded = 0;
                        this.queue.push(job);
                    }
                    
                    // Start processing if not running
                    if (!this.isRunning) {
                        this.start();
                    }
                }

                // Get failed uploads for display
                getFailedUploads() {
                    return this.failedUploads.map(job => ({
                        name: job.file.name,
                        error: job.error?.message || 'Unknown error',
                        size: job.file.size
                    }));
                }

                getProgress() {
                    return {
                        total: this.stats.total,
                        completed: this.stats.completed,
                        failed: this.stats.failed,
                        active: this.activeUploads.size,
                        queued: this.queue.length,
                        percentage: this.stats.total > 0 ? Math.round((this.stats.completed / this.stats.total) * 100) : 0,
                        bytesPercentage: this.stats.bytes.total > 0 ? Math.round((this.stats.bytes.uploaded / this.stats.bytes.total) * 100) : 0
                    };
                }
            }

            // Global upload manager instance
            window.globalUploadManager = new ParallelUploadManager(10);

            // Keep backward compatibility
            window.showInstallSpinner = (message = 'Installing Application...') => {
                window.showProgressSpinner(message, { showLogs: true, title: "Installing Application" });
            };
            
            window.hideInstallSpinner = () => {
                window.hideProgressSpinner();
            };

            React.useEffect(() => {
                // Connect to the Hypha server
                const connectToServer = async () => {
                    try{
                        setLoadingMessage('Connecting to Hypha server...');
                        const remoteServer = await hyphaWebsocketClient.connectToServer(config);
                        window.remoteServer = remoteServer;
                        
                        setLoadingMessage('Loading services...');
                        const newPanels = [];
                        try{
                            await remoteServer.getService('public/server-apps', { case_conversion: 'camel' });
                            newPanels.push('applications');
                        }
                        catch(e){
                            console.log("Server apps service not available");
                        }
                        try {
                            const s3 = await remoteServer.getService('public/s3-storage', { case_conversion: 'camel' });
                            newPanels.push('files');
                            setS3(s3);
                        }
                        catch(e){
                            console.log("S3 storage service not available");
                        }
                        try {
                            // get artifact service
                            const am = await remoteServer.getService('public/artifact-manager', { case_conversion: 'camel' });
                            newPanels.push('artifacts');
                            setAM(am);
                        }
                        catch(e){
                            console.log("Artifacts service not available");
                        }
                        
                        setLoadingMessage('Initializing workspace...');
                        setEnabledPanels([...enabledPanels, ...newPanels]);
                        setWs(remoteServer);
                        
                        // Hide loading overlay after successful connection
                        setTimeout(() => {
                            setIsLoadingSpinnerVisible(false);
                        }, 500); // Small delay to show "Initializing workspace..." message
                    }
                    catch(e){
                        // Hide loading overlay on error
                        setIsLoadingSpinnerVisible(false);
                        // clear access token
                        document.cookie = 'access_token=; path=/; max-age=0; samesite=lax';
                        const redirectUrl = '/public/apps/hypha-login/?redirect=' + window.location.href;
                        alert(`Failed to connect to the server: ${e}, redirecting to login: ${redirectUrl}`);
                        window.location.href = redirectUrl;
                    }
                };
                connectToServer();
            }, []);
        
            React.useEffect(() => {
                // Fetch initial workspace data based on active panel
                const fetchWorkspaceData = async () => {
                    if (!ws) {
                        return;
                    }
                    
                    // Show loading overlay for data fetching when switching panels
                    if (activePanel === 'dashboard') {
                        setLoadingMessage('Loading dashboard data...');
                        setIsLoadingSpinnerVisible(true);
                        try {
                            setClients(await ws.listClients());
                            setServices(await ws.listServices(config.workspace));
                        } finally {
                            setIsLoadingSpinnerVisible(false);
                        }
                    } else if (activePanel === 'applications') {
                        setLoadingMessage('Loading applications...');
                        setIsLoadingSpinnerVisible(true);
                        try {
                            const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                            const apps = await controller.listApps();
                            const running = await controller.listRunning();
                            setApps(apps);
                            setRunningApps(running);
                        } catch (e) {
                            alert(`Failed to list apps: ${e.message}`);
                        } finally {
                            setIsLoadingSpinnerVisible(false);
                        }
                    } else if (activePanel === 'files') {
                        setLoadingMessage('Loading files...');
                        setIsLoadingSpinnerVisible(true);
                        try {
                            const s3 = await ws.getService('public/s3-storage', { case_conversion: 'camel' });
                            const files = await s3.listFiles();
                            setFiles(files);
                        } catch (e) {
                            alert(`Failed to list files: ${e.message}`);
                        } finally {
                            setIsLoadingSpinnerVisible(false);
                        }
                    } else if (activePanel === 'artifacts') {
                        setLoadingMessage('Loading artifacts...');
                        setIsLoadingSpinnerVisible(true);
                        try {
                            const am = await ws.getService('public/artifact-manager', { case_conversion: 'camel' });
                            setAM(am);
                        } catch (e) {
                            alert(`Failed to list artifacts: ${e.message}`);
                        } finally {
                            setIsLoadingSpinnerVisible(false);
                        }
                    }
                };
                fetchWorkspaceData();
                document.title = `${activePanel.charAt(0).toUpperCase() + activePanel.slice(1)} - Hypha Workspace Management`;
            }, [activePanel, ws]);
        
            const onShowDetails = (service) => {
                setSelectedService(service);
            };
        
            const onInstallApp = async () => {
                if (!ws || !ws.getService) {
                    alert('WebSocket connection not ready. Please wait for the connection to be established.');
                    return;
                }
                
                const url = prompt(
                    'Enter the URL of the app to install (*.hypha.html)',
                    window.location.origin + '/ws/code_template.hypha.html'
                );
                if (!url) return;
                
                setIsInstallingApp(true);
                try {
                    window.showLoadingSpinner('Installing Application...');
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    const appInfo = await controller.install(url, { overwrite: true, _rkwargs: true});
                    console.log('App installed:', appInfo);
                    setApps(await controller.listApps());
                } catch (e) {
                    console.error(e);
                    alert(`Failed to install app: ${e.message}`);
                } finally {
                    setIsInstallingApp(false);
                    window.hideLoadingSpinner();
                }
            };

            const handleTakeScreenshot = async (sessionId, appName = null, showSpinner = true) => {
                try {
                    if (showSpinner) {
                        window.showLoadingSpinner('Taking Screenshot...');
                    }
                    if (!ws || !ws.getService) {
                        throw new Error('WebSocket connection not ready. Please wait for the connection to be established.');
                    }
                    const controller = await ws.getService('public/server-apps', { case_conversion: 'camel' });
                    const screenshotBytes = await controller.takeScreenshot(sessionId);
                    
                    // Convert bytes to base64
                    let screenshotBase64;
                    if (screenshotBytes instanceof Uint8Array) {
                        // If it's already a Uint8Array, convert directly
                        screenshotBase64 = btoa(String.fromCharCode.apply(null, screenshotBytes));
                    } else if (typeof screenshotBytes === 'string') {
                        // If it's already a base64 string, use it directly
                        screenshotBase64 = screenshotBytes;
                    } else if (Array.isArray(screenshotBytes)) {
                        // If it's an array of numbers, convert to Uint8Array first
                        const uint8Array = new Uint8Array(screenshotBytes);
                        screenshotBase64 = btoa(String.fromCharCode.apply(null, uint8Array));
                    } else {
                        throw new Error('Unexpected screenshot data format');
                    }
                    
                    setScreenshotData(screenshotBase64);
                    setScreenshotSessionId(sessionId);
                    setScreenshotAppName(appName);
                } catch (error) {
                    console.error('Failed to take screenshot:', error);
                    if (showSpinner) {
                        alert(`Failed to take screenshot: ${error}`);
                    }
                } finally {
                    if (showSpinner) {
                        window.hideLoadingSpinner();
                    }
                }
            };
        
            const closeModal = () => {
                setSelectedService(null);
            };

            const handleScreenshotRefresh = async () => {
                if (screenshotSessionId) {
                    await handleTakeScreenshot(screenshotSessionId, screenshotAppName, false);
                }
            };

            const handleScreenshotClose = () => {
                setScreenshotData(null);
                setScreenshotSessionId(null);
                setScreenshotAppName(null);
            };

            React.useEffect(() => {
                const updateHash = () => {
                    window.location.hash = activePanel; // Update the URL hash when the active panel changes
                };
                updateHash();
            }, [activePanel]);

            React.useEffect(() => {
                const handleHashChange = () => {
                    setActivePanel(getActivePanelFromHash()); // Set the active panel based on the URL hash when it changes
                };

                window.addEventListener('hashchange', handleHashChange);
                return () => window.removeEventListener('hashchange', handleHashChange); // Cleanup event listener
            }, []);

            return (
                <div>
                    <Sidebar isCollapsed={isCollapsed} enabledPanels={enabledPanels} onToggle={() => setIsCollapsed(!isCollapsed)} setActivePanel={setActivePanel} />
                    <MainContent
                        isCollapsed={isCollapsed}
                        enabledPanels={enabledPanels}
                        ws={ws}
                        s3={s3}
                        am={am}
                        workspaceId={config.workspace}
                        panel={activePanel}
                        clients={clients}
                        services={services}
                        apps={apps}
                        runningApps={runningApps}
                        files={files}
                        onShowDetails={onShowDetails}
                        onInstallApp={onInstallApp}
                        isInstallingApp={isInstallingApp}
                        setClients={setClients}
                        setApps={setApps}
                        setRunningApps={setRunningApps}
                        onTakeScreenshot={handleTakeScreenshot}
                    />
                    {selectedService && <Modal serviceInfo={selectedService} onClose={() => setSelectedService(null)} />}
                    {screenshotData && <ScreenshotDialog 
                        screenshotData={screenshotData} 
                        sessionId={screenshotSessionId} 
                        appName={screenshotAppName}
                        onClose={handleScreenshotClose}
                        onRefresh={handleScreenshotRefresh}
                    />}
                    <SpinnerOverlay 
                    isVisible={isLoadingSpinnerVisible} 
                    message={loadingMessage}
                    showLogs={showSpinnerLogs}
                    logs={spinnerLogs}
                    onClose={window.hideProgressSpinner}
                    closeEnabled={spinnerCloseEnabled}
                    title={spinnerTitle}
                    retryAction={spinnerRetryAction}
                    includeHiddenFiles={includeHiddenFiles}
                />
                </div>
            );
        };
        
        ReactDOM.render(<App />, document.getElementById('app'));
        
    </script>
</body>

</html>

