alpinux-static/app/templates/trash.html
Alpinux b3af420d36 feat: corbeille avec purge automatique 30 jours
- Suppression déplace dans .trash/ (arborescence préservée + .trashinfo)
- /trash : liste, restauration (conflit overwrite/rename), suppression
  définitive, vidage complet
- Purge automatique des fichiers > 30 jours à chaque visite /trash
- Badge rouge dans la nav avec le nombre de fichiers en corbeille
- Extraction du tableau de fichiers en partial _file_table.html
  partagé entre browse et trash

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:40:35 +02:00

92 lines
3.3 KiB
HTML

{% extends "base.html" %}
{% block title %}Corbeille{% endblock %}
{% block content %}
<section class="card">
<div class="trash-header">
<h2>Corbeille
{% if entries %}
<span class="trash-count-label">— {{ entries|length }} fichier{{ 's' if entries|length > 1 else '' }}</span>
{% endif %}
</h2>
{% if entries %}
<form method="post" action="{{ url_for('trash_empty') }}"
onsubmit="return confirm('Vider définitivement toute la corbeille ?')">
<button type="submit" class="btn btn-danger">Vider la corbeille</button>
</form>
{% endif %}
</div>
<p class="trash-info">Les fichiers sont supprimés définitivement après 30 jours.</p>
{% if entries %}
{% set mode = 'trash' %}
{% include '_file_table.html' %}
{% else %}
<p class="empty">La corbeille est vide.</p>
{% endif %}
</section>
<div id="restore-conflict-panel" class="conflict-panel" style="display:none">
<p class="conflict-title">⚠ Un fichier existe déjà à cet emplacement : <strong id="restore-conflict-name"></strong></p>
<div class="resize-chips resize-chips--radio">
<label class="chip"><input type="radio" name="restore-conflict" value="overwrite" checked><span>Écraser</span></label>
<label class="chip"><input type="radio" name="restore-conflict" value="rename"><span>Renommer</span></label>
</div>
<div class="conflict-actions">
<button type="button" id="restore-confirm" class="btn btn-primary">Confirmer la restauration</button>
<button type="button" id="restore-cancel" class="btn-rename-cancel">Annuler</button>
</div>
</div>
<script>
(function () {
const RESTORE_URL = {{ url_for('trash_restore') | tojson }};
const conflictPanel = document.getElementById('restore-conflict-panel');
const conflictName = document.getElementById('restore-conflict-name');
const confirmBtn = document.getElementById('restore-confirm');
const cancelBtn = document.getElementById('restore-cancel');
let pendingPath = null;
async function doRestore(path, conflict) {
const fd = new FormData();
fd.append('path', path);
if (conflict) fd.append('conflict', conflict);
try {
const resp = await fetch(RESTORE_URL, { method: 'POST', body: fd });
if (resp.status === 409) {
pendingPath = path;
conflictName.textContent = path.split('/').pop();
conflictPanel.style.display = 'block';
conflictPanel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
return;
}
if (resp.redirected) { window.location.href = resp.url; return; }
if (resp.ok) { window.location.href = resp.url || window.location.href; return; }
alert('Erreur lors de la restauration.');
} catch (_) {
alert('Erreur réseau.');
}
}
document.addEventListener('click', e => {
const btn = e.target.closest('.btn-restore');
if (!btn) return;
doRestore(btn.dataset.path, '');
});
confirmBtn.addEventListener('click', () => {
const strategy = document.querySelector('input[name="restore-conflict"]:checked')?.value || 'overwrite';
conflictPanel.style.display = 'none';
if (pendingPath) doRestore(pendingPath, strategy);
pendingPath = null;
});
cancelBtn.addEventListener('click', () => {
conflictPanel.style.display = 'none';
pendingPath = null;
});
})();
</script>
{% endblock %}