PIVOT 1.1.0
This commit is contained in:
commit
8a53234eb6
161 files changed
+31109
No files matched your search
@@ -0,0 +1,151 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}SGR groepen{% endblock %}
|
||||
{% block page_title %}SGR groepen{% endblock %}
|
||||
{% block main_class %}wide{% endblock %}
|
||||
{% block loader_text %}Groepen ophalen uit Smartschool...{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.keuze { display: flex; gap: 8px; align-items: center; margin: 0; }
|
||||
.keuze input { width: 240px; }
|
||||
.tellers { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 6px; }
|
||||
.tellers span { padding: 4px 12px; border-radius: 999px; background: var(--surface-muted); border: 1px solid var(--border); font-size: .88em; }
|
||||
.tellers b { margin-left: 4px; }
|
||||
.filter-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 12px 0; }
|
||||
.filter-bar input[type=search] { flex: 0 1 340px; }
|
||||
.groepen { display: grid; gap: 8px; }
|
||||
details.groep { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface, #fff); }
|
||||
details.groep[open] { border-color: var(--primary-color); }
|
||||
details.groep > summary { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 10px 14px;
|
||||
cursor: pointer; list-style: none; }
|
||||
details.groep > summary::-webkit-details-marker { display: none; }
|
||||
details.groep > summary::before { content: "▸"; color: var(--text-muted, #64748b); transition: transform .15s; }
|
||||
details.groep[open] > summary::before { transform: rotate(90deg); }
|
||||
.groep .gnaam { font-weight: 600; }
|
||||
.groep .pad { font-size: .85em; color: var(--text-muted, #64748b); }
|
||||
.groep .aantal { margin-left: auto; padding: 2px 10px; border-radius: 999px; background: var(--primary-light);
|
||||
color: var(--primary-color); font-weight: 700; font-size: .88em; white-space: nowrap; }
|
||||
.groep .aantal.leeg { background: var(--surface-muted); color: var(--text-muted, #64748b); font-weight: 400; }
|
||||
.groep .inhoud { padding: 0 14px 12px; }
|
||||
.groep table { margin: 0; }
|
||||
.rol { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: .85em; background: var(--surface-muted); }
|
||||
.rol.Leerling { background: #dbeafe; color: #1d4ed8; }
|
||||
.rol.Leerkracht { background: #dcfce7; color: #15803d; }
|
||||
mark { background: #fef08a; padding: 0; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="page-head">
|
||||
<h2>👥 SGR groep in Smartschool</h2>
|
||||
<div class="actions">
|
||||
<form method="GET" action="{{ url_for('sgr_groepen.overzicht') }}" class="keuze" onsubmit="showLoader()">
|
||||
<input type="text" name="groep" value="{{ groep }}" aria-label="Hoofdgroep" title="Naam of code van de Smartschool-groep">
|
||||
<button type="submit" class="btn-light btn-sm">Tonen</button>
|
||||
</form>
|
||||
{% if groepen %}<a class="btn btn-light btn-sm" href="{{ url_for('sgr_groepen.export', groep=groep if groep != standaard else None) }}">⬇️ CSV</a>{% endif %}
|
||||
<a class="btn btn-secondary btn-sm" href="{{ url_for('sgr_groepen.overzicht', groep=groep if groep != standaard else None, vernieuw=1) }}" onclick="showLoader()">🔄 Opnieuw ophalen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if fout %}
|
||||
<div class="alert alert-danger">{{ fout }}</div>
|
||||
{% elif not groepen %}
|
||||
<p class="muted">De groep <strong>{{ hoofd.naam }}</strong> bestaat in Smartschool, maar heeft geen subgroepen.</p>
|
||||
{% else %}
|
||||
<div class="tellers">
|
||||
<span>Subgroepen <b>{{ groepen|length }}</b></span>
|
||||
<span title="Elk lidmaatschap apart geteld">Lidmaatschappen <b>{{ aantal_leden }}</b></span>
|
||||
<span title="Wie in meer dan één groep zit, telt één keer">Verschillende personen <b>{{ uniek }}</b></span>
|
||||
{% set leeg = groepen|selectattr('leden', 'equalto', [])|selectattr('fout', 'none')|list|length %}
|
||||
{% if leeg %}<span>Zonder leden <b>{{ leeg }}</b></span>{% endif %}
|
||||
</div>
|
||||
<div class="filter-bar">
|
||||
<input type="search" id="zoek" placeholder="Zoek een groep of een lid (naam, gebruikersnaam)..." aria-label="Zoeken">
|
||||
<button type="button" class="btn-light btn-sm" id="allesOpen">Alles openklappen</button>
|
||||
<button type="button" class="btn-light btn-sm" id="allesDicht">Alles dichtklappen</button>
|
||||
<span class="muted small" id="zoekTeller"></span>
|
||||
<span class="muted small">Opgehaald uit Smartschool op {{ opgehaald }}</span>
|
||||
</div>
|
||||
|
||||
<div class="groepen" id="groepen">
|
||||
{% for g in groepen %}
|
||||
<details class="groep" style="margin-left: {{ g.diepte * 24 }}px" data-groep="{{ (g.naam ~ ' ' ~ g.code ~ ' ' ~ g.omschrijving)|lower }}">
|
||||
<summary>
|
||||
<span class="gnaam">{{ g.naam }}</span>
|
||||
{% if g.code and g.code != g.naam %}<span class="muted small">{{ g.code }}</span>{% endif %}
|
||||
{% if g.pad %}<span class="pad">in {{ g.pad|join(' › ') }}</span>{% endif %}
|
||||
{% if g.fout %}
|
||||
<span class="badge badge-danger" title="{{ g.fout }}">leden niet op te halen</span>
|
||||
{% else %}
|
||||
<span class="aantal {{ 'leeg' if not g.leden }}">{{ g.leden|length }} {{ 'lid' if g.leden|length == 1 else 'leden' }}{% if g.aantal_sub %} · {{ g.aantal_sub }} subgroep{{ 'en' if g.aantal_sub != 1 }}{% endif %}</span>
|
||||
{% endif %}
|
||||
</summary>
|
||||
<div class="inhoud">
|
||||
{% if g.omschrijving and g.omschrijving != g.naam %}<p class="muted small" style="margin:0 0 8px">{{ g.omschrijving }}</p>{% endif %}
|
||||
{% if g.fout %}
|
||||
<div class="alert alert-danger" style="margin:0">Leden konden niet opgehaald worden: {{ g.fout }}</div>
|
||||
{% elif not g.leden %}
|
||||
<p class="muted small" style="margin:0">Deze groep heeft momenteel geen rechtstreekse leden.</p>
|
||||
{% else %}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Naam</th><th>Voornaam</th><th>Gebruikersnaam</th><th>Rol</th><th>E-mail</th></tr></thead>
|
||||
<tbody>
|
||||
{% for l in g.leden %}
|
||||
<tr class="lid" data-tekst="{{ (l.naam ~ ' ' ~ l.voornaam ~ ' ' ~ l.voornaam ~ ' ' ~ l.naam ~ ' ' ~ l.gebruikersnaam ~ ' ' ~ l.email)|lower }}">
|
||||
<td><strong>{{ l.naam }}</strong></td>
|
||||
<td>{{ l.voornaam }}</td>
|
||||
<td>{{ l.gebruikersnaam }}</td>
|
||||
<td>{% if l.rol %}<span class="rol {{ l.rol }}">{{ l.rol }}</span>{% endif %}</td>
|
||||
<td class="small">{{ l.email }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</details>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<p class="field-hint" style="margin-top:14px">Toont alle groepen onder <strong>{{ groep }}</strong> in Smartschool met hun huidige,
|
||||
rechtstreekse leden. De standaard hoofdgroep ({{ standaard }}) stel je in via 🔌 Koppelingen › Smartschool.
|
||||
Gegevens worden 10 minuten bewaard.</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
(function () {
|
||||
const lijst = document.getElementById('groepen');
|
||||
if (!lijst) return;
|
||||
const groepen = Array.from(lijst.querySelectorAll('details.groep'));
|
||||
const zoekveld = document.getElementById('zoek'), teller = document.getElementById('zoekTeller');
|
||||
document.getElementById('allesOpen').onclick = () => groepen.forEach(d => { if (d.style.display !== 'none') d.open = true; });
|
||||
document.getElementById('allesDicht').onclick = () => groepen.forEach(d => d.open = false);
|
||||
zoekveld.addEventListener('input', () => {
|
||||
const z = zoekveld.value.trim().toLowerCase();
|
||||
let treffers = 0, zichtbaar = 0;
|
||||
groepen.forEach(d => {
|
||||
const naamTreffer = !z || d.dataset.groep.includes(z);
|
||||
let lidTreffer = 0;
|
||||
d.querySelectorAll('tr.lid').forEach(tr => {
|
||||
const ok = !z || naamTreffer || tr.dataset.tekst.includes(z);
|
||||
tr.style.display = ok ? '' : 'none';
|
||||
if (z && tr.dataset.tekst.includes(z)) lidTreffer++;
|
||||
});
|
||||
const toon = naamTreffer || lidTreffer > 0;
|
||||
d.style.display = toon ? '' : 'none';
|
||||
if (toon) zichtbaar++;
|
||||
treffers += lidTreffer;
|
||||
if (z) d.open = lidTreffer > 0;
|
||||
});
|
||||
teller.textContent = z ? `${zichtbaar} groep(en)` + (treffers ? `, ${treffers} lid/leden gevonden` : '') : '';
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user