Files
Pivot/templates/gmail_labels.html
2026-10-14 13:34:37 +02:00

160 lines
9.6 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Mails verplaatsen{% endblock %}
{% block page_title %}Mails verplaatsen{% endblock %}
{% block main_class %}medium{% endblock %}
{% block loader_text %}Bezig met Google...{% endblock %}
{% block extra_css %}
<style>
.stappen { display: grid; gap: 14px; }
.rij { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.rij .field { flex: 1 1 260px; margin: 0; }
.modus { display: flex; flex-wrap: wrap; gap: 10px; }
.modus label { flex: 1 1 240px; display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; margin: 0;
border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; font-weight: 400; }
.modus label:has(input:checked) { border-color: var(--primary-color); background: var(--primary-light); }
.modus input { width: auto; margin-top: 3px; }
.modus strong { display: block; }
.samenvatting { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; justify-content: space-between;
padding: 14px 16px; border-radius: var(--radius); background: var(--surface-muted); margin-top: 16px; }
.samenvatting .pijl { font-size: 1.3em; color: var(--text-muted, #64748b); }
.voortgang { height: 10px; border-radius: 999px; background: var(--surface-muted); overflow: hidden; margin: 10px 0 6px; }
.voortgang div { height: 100%; width: 0; background: var(--primary-color); transition: width .4s; }
.tellers { display: flex; flex-wrap: wrap; gap: 14px; font-size: .92em; }
td.nowrap { white-space: nowrap; }
</style>
{% endblock %}
{% block content %}
<div class="card">
<h2 class="card-title">🏷️ Berichten met een label naar een andere mailbox</h2>
<p class="field-hint" style="margin-top:-6px">Kies de mailbox en het label. PIVOT kopieert elk bericht met dat label (met bijlagen,
originele datum, gelezen/ongelezen en ster) naar de doelmailbox, onder een label met dezelfde naam.</p>
<form method="GET" action="{{ url_for('gmail_labels.overzicht') }}" class="stappen" onsubmit="showLoader()">
<div class="rij">
<div class="field">
<label for="bron">1. Bronmailbox</label>
<input type="email" id="bron" name="bron" required value="{{ bron.email if bron else bron_in }}" placeholder="bv. secretariaat@school.be">
</div>
<button type="submit" class="btn-secondary">🔍 Labels ophalen</button>
</div>
{% if bron %}
<div class="muted small" style="margin-top:-6px">📬 {{ bron.naam or bron.email }} · {{ bron.email }}{% if bron.ou %} · {{ bron.ou }}{% endif %}</div>
{% if labels %}
<div class="field" style="margin:0">
<label for="label">2. Label</label>
<select id="label" name="label" required>
<option value="">— kies een label —</option>
{% for l in labels %}
<option value="{{ l.id }}" {{ 'selected' if gekozen and gekozen.id == l.id }}>{{ l.naam }}{% if l.aantal is not none %} ({{ l.aantal }}){% endif %}</option>
{% endfor %}
</select>
</div>
<div class="field" style="margin:0">
<label for="doel">3. Doelmailbox</label>
<input type="email" id="doel" name="doel" required value="{{ doel.email if doel else doel_in }}" placeholder="bv. directie@school.be">
</div>
<div><button type="submit" class="btn-secondary">Controleren</button></div>
{% elif not fout %}
<p class="muted">Deze mailbox heeft geen eigen labels.</p>
{% endif %}
{% endif %}
</form>
{% if fout %}<div class="alert alert-danger" style="margin-top:14px">{{ fout }}</div>{% endif %}
{% if bron and doel and gekozen %}
<form method="POST" action="{{ url_for('gmail_labels.start') }}" style="margin-top:18px"
onsubmit="const v = this.modus.value === 'verplaatsen'; return confirm({{ (gekozen.aantal|string if gekozen.aantal is not none else 'Alle') |tojson|forceescape }} + ' bericht(en) met label ' + {{ gekozen.naam|tojson|forceescape }} + (v ? ' VERPLAATSEN' : ' kopiëren') + ' van ' + {{ bron.email|tojson|forceescape }} + ' naar ' + {{ doel.email|tojson|forceescape }} + '?' + (v ? '\n\nIn de bronmailbox gaan ze naar de prullenbak (30 dagen terug te halen).' : ''));">
<input type="hidden" name="bron" value="{{ bron.email }}">
<input type="hidden" name="doel" value="{{ doel.email }}">
<input type="hidden" name="label" value="{{ gekozen.id }}">
<label style="margin-bottom:8px">4. Wat moet er gebeuren?</label>
<div class="modus">
<label><input type="radio" name="modus" value="kopieren" checked>
<span><strong>📋 Kopiëren</strong><span class="muted small">De berichten blijven ook in de bronmailbox staan.</span></span></label>
<label><input type="radio" name="modus" value="verplaatsen">
<span><strong>📦 Verplaatsen</strong><span class="muted small">Na het kopiëren gaan ze in de bronmailbox naar de prullenbak.</span></span></label>
</div>
<div class="samenvatting">
<span><strong>{{ gekozen.aantal if gekozen.aantal is not none else '?' }}</strong> bericht(en) met label <strong>{{ gekozen.naam }}</strong></span>
<span>{{ bron.email }} <span class="pijl">→</span> {{ doel.email }}</span>
<button type="submit" class="btn-success" {{ 'disabled' if status.bezig }}>▶ Starten</button>
</div>
</form>
{% endif %}
</div>
{% if status.bezig or status.resultaat or status.fout %}
<div class="card" id="voortgangKaart">
<h3 class="card-title">⏳ Opdracht</h3>
{% if status.opdracht %}<p class="muted small" id="opdracht">Label <strong>{{ status.opdracht.label }}</strong>:
{{ status.opdracht.bron }} → {{ status.opdracht.doel }} ({{ 'verplaatsen' if status.opdracht.modus == 'verplaatsen' else 'kopiëren' }})</p>{% endif %}
<div class="voortgang"><div id="balk"></div></div>
<div class="tellers">
<span><b id="tVoortgang">{{ status.voortgang }}</b> / <b id="tTotaal">{{ status.totaal }}</b></span>
<span>✅ <b id="tGelukt">{{ status.gelukt }}</b> gelukt</span>
<span>⏭️ <b id="tOver">{{ status.overgeslagen }}</b> stonden er al</span>
<span>⚠️ <b id="tFout">{{ status.fouten }}</b> mislukt</span>
</div>
<div class="alert alert-success" id="resultaat" style="margin-top:12px" {{ '' if status.resultaat and not status.bezig else 'hidden' }}>{{ status.resultaat or '' }}</div>
<div class="alert alert-danger" id="foutmelding" style="margin-top:12px" {{ '' if status.fout else 'hidden' }}>{{ status.fout or '' }}</div>
<ul class="muted small" id="foutvoorbeelden">{% for f in status.foutvoorbeelden %}<li>{{ f }}</li>{% endfor %}</ul>
</div>
{% endif %}
{% if geschiedenis %}
<div class="card">
<h3 class="card-title">🕑 Vorige opdrachten</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Gestart</th><th>Door</th><th>Label</th><th>Van → naar</th><th>Soort</th><th class="text-right">Gelukt</th><th class="text-right">Mislukt</th></tr></thead>
<tbody>
{% for h in geschiedenis %}
<tr title="{{ h.Melding or '' }}">
<td class="nowrap">{{ h.Gestart.strftime('%d-%m-%Y %H:%M') }}{% if not h.Klaar %} <span class="badge badge-warning">bezig</span>{% endif %}</td>
<td>{{ h.Door or '' }}</td>
<td><strong>{{ h.Label }}</strong></td>
<td class="small">{{ h.Bron }} → {{ h.Doel }}</td>
<td>{{ 'Verplaatst' if h.Modus == 'verplaatsen' else 'Gekopieerd' }}</td>
<td class="text-right">{{ h.Gelukt if h.Gelukt is not none else '' }}{% if h.Overgeslagen %} <span class="muted small">(+{{ h.Overgeslagen }})</span>{% endif %}</td>
<td class="text-right">{{ h.Fouten or '' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
<p class="field-hint">Eenmalig nodig in de Google Admin-console (Beveiliging › API-beheer › Domeinbrede delegatie, bij het
serviceaccount van PIVOT): het bereik <code>{{ scope }}</code>. Een onderbroken opdracht kan je gewoon opnieuw starten:
berichten die al gekopieerd werden, worden overgeslagen.</p>
{% endblock %}
{% block scripts %}
<script>
(function () {
const kaart = document.getElementById('voortgangKaart');
if (!kaart) return;
const zet = (id, w) => document.getElementById(id).textContent = w;
function kijk() {
fetch({{ url_for('gmail_labels.status')|tojson }}, { credentials: 'same-origin' }).then(r => r.json()).then(s => {
zet('tVoortgang', s.voortgang); zet('tTotaal', s.totaal); zet('tGelukt', s.gelukt);
zet('tOver', s.overgeslagen); zet('tFout', s.fouten);
document.getElementById('balk').style.width = (s.totaal ? Math.round(100 * s.voortgang / s.totaal) : (s.bezig ? 3 : 100)) + '%';
const res = document.getElementById('resultaat'), fout = document.getElementById('foutmelding');
res.hidden = !(s.resultaat && !s.bezig); res.textContent = s.resultaat || '';
fout.hidden = !s.fout; fout.textContent = s.fout || '';
document.getElementById('foutvoorbeelden').innerHTML = (s.foutvoorbeelden || []).map(f => `<li>${f.replace(/</g, '&lt;')}</li>`).join('');
if (s.bezig) setTimeout(kijk, 2000);
}).catch(() => setTimeout(kijk, 5000));
}
kijk();
})();
</script>
{% endblock %}