Report-Generator / templates /drive_manager.html
Jaimodiji's picture
Upload folder using huggingface_hub
c001f24
Raw
History Blame
9.31 kB
{% extends "base.html" %}
{% block title %}Drive Manager{% endblock %}
{% block styles %}
<style>
.source-card {
cursor: pointer;
transition: all 0.3s ease;
}
.source-card:hover {
transform: translateY(-5px);
border-color: #0d6efd !important;
box-shadow: 0 8px 16px rgba(13, 110, 253, 0.3);
}
.recent-pdf-card:hover {
transform: translateY(-3px) scale(1.02);
box-shadow: 0 6px 20px rgba(13, 110, 253, 0.4);
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid mt-4" style="width: 90%; margin: auto;">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Drive Sync Manager</h1>
<div>
{% if not drive_connected %}
<a href="/drive/connect" class="btn btn-outline-warning me-2">
<i class="bi bi-google me-1"></i> Connect Drive
</a>
{% endif %}
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSourceModal">
<i class="bi bi-plus-lg me-1"></i> Add Drive Source
</button>
</div>
</div>
{% if recent_pdfs %}
<div class="card border-secondary mb-4" style="background: linear-gradient(135deg, #1a1d20 0%, #212529 100%);">
<div class="card-header border-secondary" style="background: linear-gradient(90deg, rgba(13,110,253,0.15) 0%, rgba(13,110,253,0.05) 100%);">
<h5 class="mb-0 text-primary"><i class="bi bi-clock-history me-2"></i>Recently Opened PDFs</h5>
</div>
<div class="card-body">
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-3">
{% for pdf in recent_pdfs %}
<div class="col">
<div class="card h-100 border-primary source-card" onclick="location.href='/drive/api/open/{{ pdf.file_id }}'" style="background: linear-gradient(135deg, #212529 0%, #2b3035 100%); transition: all 0.3s ease;">
<div class="card-body d-flex flex-column">
<div class="mb-2 flex-grow-1">
<h6 class="card-title text-primary mb-2" style="word-wrap: break-word; line-height: 1.4;">
<i class="bi bi-file-pdf-fill me-2"></i>{{ pdf.filename }}
</h6>
</div>
<div class="mt-auto pt-2 border-top border-secondary">
<small class="text-muted">
<i class="bi bi-clock me-1"></i>{{ pdf.opened_at }}
</small>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% if drive_connected %}
<div class="card bg-dark text-white border-warning mb-4 source-card" onclick="location.href='/drive/api/browse/root'">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<h5 class="card-title text-warning mb-0"><i class="bi bi-google me-2"></i>My Drive</h5>
<small class="text-muted">Browse your personal Google Drive (API)</small>
</div>
<i class="bi bi-chevron-right text-muted"></i>
</div>
</div>
{% endif %}
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4" id="sources-grid">
{% for source in sources %}
<div class="col">
<div class="card h-100 bg-dark text-white border-secondary source-card">
<div class="card-body" onclick="location.href='/drive/browse/{{ source.id }}'">
<div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title text-primary">
{% if source.source_type == 'file' %}
<i class="bi bi-file-earmark-arrow-down me-2"></i>
{% else %}
<i class="bi bi-hdd-network me-2"></i>
{% endif %}
{{ source.name }}
</h5>
<div class="dropdown" onclick="event.stopPropagation()">
<button class="btn btn-link text-muted p-0" data-bs-toggle="dropdown">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu dropdown-menu-dark">
<li><button class="dropdown-item sync-btn" data-id="{{ source.id }}"><i class="bi bi-arrow-repeat me-2"></i>Sync Now</button></li>
<li><hr class="dropdown-divider"></li>
<li><button class="dropdown-item text-danger delete-btn" data-id="{{ source.id }}"><i class="bi bi-trash me-2"></i>Delete</button></li>
</ul>
</div>
</div>
<p class="card-text text-muted small text-truncate">{{ source.url }}</p>
<div class="mt-3">
<small class="text-secondary">
Last Synced: {{ source.last_synced or 'Never' }}
</small>
</div>
</div>
</div>
</div>
{% else %}
<div class="col-12 text-center text-muted py-5">
<i class="bi bi-cloud-slash display-4 mb-3 d-block"></i>
<p>No drive sources added yet.</p>
</div>
{% endfor %}
</div>
</div>
<!-- Add Modal -->
<div class="modal fade" id="addSourceModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title">Add Public Drive Folder</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="add-source-form">
<div class="mb-3">
<label class="form-label">Name (Local Folder Name)</label>
<input type="text" class="form-control" name="name" required placeholder="e.g. Question Papers 2024">
</div>
<div class="mb-3">
<label class="form-label">Drive Folder URL</label>
<input type="url" class="form-control" name="url" required placeholder="https://drive.google.com/drive/folders/...">
<div class="form-text text-muted">Must be a publicly accessible Google Drive folder link.</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="save-source-btn">Add Source</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
document.getElementById('save-source-btn').addEventListener('click', async () => {
const form = document.getElementById('add-source-form');
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const formData = new FormData(form);
try {
const res = await fetch('/drive/add', {
method: 'POST',
body: formData
});
const data = await res.json();
if (data.success) {
location.reload();
} else {
alert('Error: ' + data.error);
}
} catch (e) {
alert('Error adding source');
}
});
document.querySelectorAll('.sync-btn').forEach(btn => {
btn.addEventListener('click', async () => {
const id = btn.dataset.id;
if(!confirm('Start sync in background? Large folders may take time.')) return;
try {
const res = await fetch(`/drive/sync/${id}`, { method: 'POST' });
const data = await res.json();
if (data.success) alert('Sync started!');
else alert('Error: ' + data.error);
} catch (e) {
alert('Request failed');
}
});
});
document.querySelectorAll('.delete-btn').forEach(btn => {
btn.addEventListener('click', async () => {
const id = btn.dataset.id;
if(!confirm('Delete this source and all downloaded files locally?')) return;
try {
const res = await fetch(`/drive/delete/${id}`, { method: 'POST' });
const data = await res.json();
if (data.success) location.reload();
else alert('Error: ' + data.error);
} catch (e) {
alert('Request failed');
}
});
});
</script>
{% endblock %}