test/moxie/admin/templates/documents.html
2026-03-24 04:04:58 +00:00

148 lines
5.6 KiB
HTML
Executable File

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documents - MOXIE Admin</title>
<link rel="stylesheet" href="/{{ settings.admin_path }}/static/admin.css">
</head>
<body>
<nav class="navbar">
<div class="nav-brand">MOXIE Admin</div>
<div class="nav-links">
<a href="/{{ settings.admin_path }}/">Dashboard</a>
<a href="/{{ settings.admin_path }}/endpoints">Endpoints</a>
<a href="/{{ settings.admin_path }}/documents">Documents</a>
<a href="/{{ settings.admin_path }}/comfyui">ComfyUI</a>
</div>
</nav>
<main class="container">
<h1>Document Management</h1>
<section class="upload-section">
<h2>Upload Document</h2>
<form id="upload-form" class="form-inline">
<div class="form-group">
<input type="file" id="document-file" name="file" accept=".txt,.md,.pdf,.docx,.html" required>
</div>
<div class="form-group">
<label for="chunk_size">Chunk Size</label>
<input type="number" id="chunk_size" name="chunk_size" value="500" min="100" max="2000">
</div>
<div class="form-group">
<label for="overlap">Overlap</label>
<input type="number" id="overlap" name="overlap" value="50" min="0" max="500">
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
</section>
<section class="documents-section">
<h2>Uploaded Documents</h2>
<table class="documents-table">
<thead>
<tr>
<th>Filename</th>
<th>Type</th>
<th>Chunks</th>
<th>Uploaded</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="documents-list">
{% for doc in documents %}
<tr data-id="{{ doc.id }}">
<td>{{ doc.filename }}</td>
<td>{{ doc.file_type }}</td>
<td>{{ doc.chunk_count }}</td>
<td>{{ doc.created_at }}</td>
<td>
<button class="btn btn-danger btn-sm delete-btn" data-id="{{ doc.id }}">Delete</button>
</td>
</tr>
{% else %}
<tr>
<td colspan="5" class="empty-message">No documents uploaded yet</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
<div id="toast" class="toast hidden"></div>
</main>
<script>
// Upload form
document.getElementById('upload-form').addEventListener('submit', async (e) => {
e.preventDefault();
const fileInput = document.getElementById('document-file');
const file = fileInput.files[0];
if (!file) {
showToast('Please select a file', 'error');
return;
}
const formData = new FormData();
formData.append('file', file);
formData.append('chunk_size', document.getElementById('chunk_size').value);
formData.append('overlap', document.getElementById('overlap').value);
try {
const response = await fetch('/{{ settings.admin_path }}/documents/upload', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.status === 'success') {
showToast(`Uploaded: ${result.filename}`, 'success');
setTimeout(() => location.reload(), 1500);
} else {
showToast('Upload failed: ' + (result.detail || 'Unknown error'), 'error');
}
} catch (error) {
showToast('Upload failed', 'error');
}
});
// Delete buttons
document.querySelectorAll('.delete-btn').forEach(btn => {
btn.addEventListener('click', async () => {
if (!confirm('Delete this document?')) return;
const docId = btn.dataset.id;
try {
const response = await fetch(`/{{ settings.admin_path }}/documents/${docId}`, {
method: 'DELETE'
});
const result = await response.json();
if (result.status === 'success') {
showToast('Document deleted', 'success');
btn.closest('tr').remove();
} else {
showToast('Delete failed', 'error');
}
} catch (error) {
showToast('Delete failed', 'error');
}
});
});
function showToast(message, type) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = 'toast ' + type;
setTimeout(() => toast.classList.add('hidden'), 3000);
}
</script>
</body>
</html>