Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>File System Test App</title> | |
| <!-- Bootstrap CSS --> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <!-- Font Awesome --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <!-- TinyMCE --> | |
| <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script> | |
| <style> | |
| body { | |
| background-color: #f8f9fa; | |
| } | |
| .main-container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| .card { | |
| margin-bottom: 20px; | |
| border: none; | |
| box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); | |
| } | |
| .card-header { | |
| background-color: #f8f9fa; | |
| border-bottom: 1px solid #e9ecef; | |
| } | |
| .file-item { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 10px; | |
| border-bottom: 1px solid #e9ecef; | |
| } | |
| .file-item:last-child { | |
| border-bottom: none; | |
| } | |
| .system-info-content { | |
| max-height: 500px; | |
| overflow-y: auto; | |
| font-family: monospace; | |
| font-size: 14px; | |
| background-color: #f8f9fa; | |
| padding: 15px; | |
| border-radius: 4px; | |
| } | |
| .test-btn { | |
| margin: 5px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="main-container"> | |
| <h1 class="mb-4">File System Test App</h1> | |
| <div class="row"> | |
| <!-- Text Editor Card --> | |
| <div class="col-md-6"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h5 class="card-title mb-0">Create & Save Text File</h5> | |
| </div> | |
| <div class="card-body"> | |
| <div class="mb-3"> | |
| <label for="filename" class="form-label">Filename</label> | |
| <input type="text" class="form-control" id="filename" placeholder="Enter filename"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Content</label> | |
| <textarea id="editor" rows="10" class="form-control"></textarea> | |
| </div> | |
| <button id="save-btn" class="btn btn-primary">Save File</button> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h5 class="card-title mb-0">Upload File</h5> | |
| </div> | |
| <div class="card-body"> | |
| <form id="upload-form"> | |
| <div class="mb-3"> | |
| <label for="file-upload" class="form-label">Select a file</label> | |
| <input class="form-control" type="file" id="file-upload"> | |
| </div> | |
| <button type="submit" class="btn btn-primary">Upload</button> | |
| </form> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h5 class="card-title mb-0">Testing Tools</h5> | |
| </div> | |
| <div class="card-body"> | |
| <button id="system-info-btn" class="btn btn-info test-btn"> | |
| <i class="fas fa-info-circle"></i> System Info | |
| </button> | |
| <button id="binary-file-btn" class="btn btn-warning test-btn"> | |
| <i class="fas fa-file-binary"></i> Create Binary File | |
| </button> | |
| <button id="command-output-btn" class="btn btn-secondary test-btn"> | |
| <i class="fas fa-terminal"></i> Test Command Output | |
| </button> | |
| <button id="large-file-btn" class="btn btn-danger test-btn"> | |
| <i class="fas fa-file-alt"></i> Create Large File (10MB) | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Files List Card --> | |
| <div class="col-md-6"> | |
| <div class="card"> | |
| <div class="card-header d-flex justify-content-between align-items-center"> | |
| <h5 class="card-title mb-0">Files</h5> | |
| <button id="refresh-files-btn" class="btn btn-sm btn-outline-secondary"> | |
| <i class="fas fa-sync-alt"></i> Refresh | |
| </button> | |
| </div> | |
| <div class="card-body p-0"> | |
| <div id="files-list" class="list-group list-group-flush"> | |
| <div class="text-center py-4"> | |
| <i class="fas fa-spinner fa-spin"></i> Loading files... | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h5 class="card-title mb-0">System Information</h5> | |
| </div> | |
| <div class="card-body"> | |
| <div id="system-info" class="system-info-content"> | |
| <p>Click the "System Info" button to load system details...</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Toast container for notifications --> | |
| <div class="toast-container position-fixed bottom-0 end-0 p-3"> | |
| <div id="toast" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> | |
| <div class="toast-header"> | |
| <strong class="me-auto" id="toast-title">Notification</strong> | |
| <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> | |
| </div> | |
| <div class="toast-body" id="toast-message"> | |
| Message goes here | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Bootstrap & jQuery --> | |
| <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> | |
| <script> | |
| // Initialize TinyMCE | |
| tinymce.init({ | |
| selector: '#editor', | |
| height: 300, | |
| menubar: false, | |
| plugins: 'lists link image table code', | |
| toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist | link image | table | code', | |
| content_style: 'body { font-family: -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif; font-size: 14px; }' | |
| }); | |
| // Show toast notification | |
| function showToast(title, message, type = 'success') { | |
| const toast = document.getElementById('toast'); | |
| document.getElementById('toast-title').textContent = title; | |
| document.getElementById('toast-message').textContent = message; | |
| // Remove previous color classes | |
| toast.classList.remove('bg-success', 'bg-danger', 'bg-warning', 'text-white'); | |
| // Add appropriate color class | |
| if (type === 'success') { | |
| toast.classList.add('bg-success', 'text-white'); | |
| } else if (type === 'error') { | |
| toast.classList.add('bg-danger', 'text-white'); | |
| } else if (type === 'warning') { | |
| toast.classList.add('bg-warning'); | |
| } | |
| // Show the toast | |
| const bsToast = new bootstrap.Toast(toast); | |
| bsToast.show(); | |
| } | |
| // Load file list | |
| function loadFiles() { | |
| fetch('/list-files') | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| const filesList = document.getElementById('files-list'); | |
| if (data.files.length === 0) { | |
| filesList.innerHTML = '<div class="text-center py-4">No files found</div>'; | |
| return; | |
| } | |
| filesList.innerHTML = ''; | |
| data.files.forEach(file => { | |
| const fileItem = document.createElement('div'); | |
| fileItem.className = 'file-item'; | |
| fileItem.innerHTML = ` | |
| <div> | |
| <div><strong>${file.name}</strong></div> | |
| <small class="text-muted">${file.size_readable} - ${file.modified}</small> | |
| </div> | |
| <div> | |
| <a href="${file.url}" class="btn btn-sm btn-outline-primary" target="_blank"> | |
| <i class="fas fa-download"></i> | |
| </a> | |
| <button class="btn btn-sm btn-outline-danger delete-file" data-filename="${file.name}"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </div> | |
| `; | |
| filesList.appendChild(fileItem); | |
| }); | |
| // Add delete event listeners | |
| document.querySelectorAll('.delete-file').forEach(button => { | |
| button.addEventListener('click', function() { | |
| const filename = this.getAttribute('data-filename'); | |
| deleteFile(filename); | |
| }); | |
| }); | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error loading files:', error); | |
| showToast('Error', 'Failed to load files', 'error'); | |
| }); | |
| } | |
| // Delete file | |
| function deleteFile(filename) { | |
| if (confirm(`Are you sure you want to delete ${filename}?`)) { | |
| fetch(`/delete-file/${filename}`, { | |
| method: 'DELETE' | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showToast('Success', `File ${filename} deleted successfully`); | |
| loadFiles(); | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error deleting file:', error); | |
| showToast('Error', 'Failed to delete file', 'error'); | |
| }); | |
| } | |
| } | |
| // Save file | |
| document.getElementById('save-btn').addEventListener('click', function() { | |
| const filename = document.getElementById('filename').value; | |
| if (!filename) { | |
| showToast('Error', 'Please enter a filename', 'error'); | |
| return; | |
| } | |
| const content = tinymce.get('editor').getContent(); | |
| const formData = new FormData(); | |
| formData.append('filename', filename); | |
| formData.append('content', content); | |
| fetch('/save-file', { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showToast('Success', 'File saved successfully'); | |
| loadFiles(); | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error saving file:', error); | |
| showToast('Error', 'Failed to save file', 'error'); | |
| }); | |
| }); | |
| // Upload file | |
| document.getElementById('upload-form').addEventListener('submit', function(e) { | |
| e.preventDefault(); | |
| const fileInput = document.getElementById('file-upload'); | |
| if (!fileInput.files[0]) { | |
| showToast('Error', 'Please select a file to upload', 'error'); | |
| return; | |
| } | |
| const formData = new FormData(); | |
| formData.append('file', fileInput.files[0]); | |
| fetch('/upload-file', { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showToast('Success', 'File uploaded successfully'); | |
| loadFiles(); | |
| fileInput.value = ''; | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error uploading file:', error); | |
| showToast('Error', 'Failed to upload file', 'error'); | |
| }); | |
| }); | |
| // Refresh files list | |
| document.getElementById('refresh-files-btn').addEventListener('click', loadFiles); | |
| // System info | |
| document.getElementById('system-info-btn').addEventListener('click', function() { | |
| fetch('/system-info') | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| const systemInfo = document.getElementById('system-info'); | |
| systemInfo.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`; | |
| showToast('Success', 'System information loaded'); | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error getting system info:', error); | |
| showToast('Error', 'Failed to get system info', 'error'); | |
| }); | |
| }); | |
| // Binary file test | |
| document.getElementById('binary-file-btn').addEventListener('click', function() { | |
| fetch('/test-binary-file') | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showToast('Success', `Binary file created: ${data.file_size} bytes`); | |
| loadFiles(); | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error creating binary file:', error); | |
| showToast('Error', 'Failed to create binary file', 'error'); | |
| }); | |
| }); | |
| // Command output test | |
| document.getElementById('command-output-btn').addEventListener('click', function() { | |
| fetch('/test-command-output') | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showToast('Success', 'Command output saved to files'); | |
| loadFiles(); | |
| } else { | |
| showToast('Error', data.message, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error testing command output:', error); | |
| showToast('Error', 'Failed to test command output', 'error'); | |
| }); | |
| }); | |
| // Load files on page load | |
| document.addEventListener('DOMContentLoaded', loadFiles); | |
| </script> | |
| </body> | |
| </html> |