feat: role filter in results grid + role-scoped Excel and Art.30 exports
- New Role dropdown in filter bar (All / Ansatte / Elever) — filters the results grid client-side via applyFilters() and clearFilters(). - Exports respect the active role: exportExcel() and exportArticle30() append ?role=student|staff to the fetch URL when a role is selected. - _build_excel_bytes(role='') and _build_article30_docx(role='') filter to a local _items list at the top; all internal sheets (Summary, GPS, External transfers, Art.30 staff/student tables) see only the filtered subset. Filenames get _elever or _ansatte suffix. - i18n: m365_filter_all_roles / m365_filter_staff / m365_filter_student added to en/da/de.json. - CLAUDE.md, README.md, CHANGELOG.md, MANUAL-EN.md, MANUAL-DA.md updated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
28c9effd17
commit
0c35a7a83d
11 files changed
+68
-18
No files matched your search
@@ -669,6 +669,7 @@ function applyFilters() {
|
||||
const dispVal = document.getElementById('filterDisposition')?.value || '';
|
||||
const transferVal = document.getElementById('filterTransfer')?.value || '';
|
||||
const specialVal = document.getElementById('filterSpecial')?.value || '';
|
||||
const roleVal = document.getElementById('filterRole')?.value || '';
|
||||
S.filteredData = S.flaggedData.filter(f => {
|
||||
if (search && !f.name.toLowerCase().includes(search)) return false;
|
||||
if (srcVal && f.source_type !== srcVal) return false;
|
||||
@@ -676,6 +677,8 @@ function applyFilters() {
|
||||
if (transferVal && (f.transfer_risk || '') !== transferVal) return false;
|
||||
if (specialVal === '1' && !(f.special_category && f.special_category.length)) return false;
|
||||
if (specialVal === 'photo' && !(f.face_count > 0)) return false;
|
||||
if (roleVal === 'student' && f.user_role !== 'student') return false;
|
||||
if (roleVal === 'staff' && f.user_role === 'student') return false;
|
||||
return true;
|
||||
});
|
||||
const grid = document.getElementById('grid');
|
||||
@@ -721,7 +724,8 @@ async function exportExcel() {
|
||||
return;
|
||||
}
|
||||
// Browser / localhost fallback: fetch as blob and trigger download
|
||||
const r = await fetch('/api/export_excel');
|
||||
const _roleParam = document.getElementById('filterRole')?.value || '';
|
||||
const r = await fetch('/api/export_excel' + (_roleParam ? '?role=' + encodeURIComponent(_roleParam) : ''));
|
||||
if (!r.ok) {
|
||||
const err = await r.json().catch(() => ({error: 'Export failed'}));
|
||||
log('Export error: ' + (err.error || r.status), 'err');
|
||||
@@ -762,7 +766,8 @@ async function exportArticle30() {
|
||||
const btn = document.getElementById('exportA30Btn');
|
||||
if (btn) { btn.disabled = true; btn.textContent = '⏳'; }
|
||||
try {
|
||||
const r = await fetch('/api/export_article30');
|
||||
const _roleParam30 = document.getElementById('filterRole')?.value || '';
|
||||
const r = await fetch('/api/export_article30' + (_roleParam30 ? '?role=' + encodeURIComponent(_roleParam30) : ''));
|
||||
if (!r.ok) {
|
||||
const err = await r.json().catch(() => ({error: 'Export failed'}));
|
||||
log('Article 30 export error: ' + (err.error || r.status), 'err');
|
||||
@@ -796,6 +801,8 @@ function clearFilters() {
|
||||
if (ft) ft.value = '';
|
||||
const fs = document.getElementById('filterSpecial');
|
||||
if (fs) fs.value = '';
|
||||
const fr = document.getElementById('filterRole');
|
||||
if (fr) fr.value = '';
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user