Jira 25 #90

Merged
NiekRabelink merged 1 commits from dev into main 2026-09-15 20:12:28 +00:00
Showing only changes of commit 8498d82e10 - Show all commits
+261 -146
View File
@@ -202,6 +202,20 @@ foreach ($usedProjectKeys as $uKey => $val) {
if (empty($activeProjectKeys)) {
$activeProjectKeys = array_fill_keys(['SD', 'IN', 'AAN', 'GEN'], true);
}
if (!empty($userQueueFilters)) {
$filteredActiveKeys = [];
foreach ($userQueueFilters as $code) {
$clean = strtoupper(trim($code));
if ($clean === 'DX') {
$filteredActiveKeys['SD'] = true;
} elseif ($clean !== 'MY_QUEUES') {
$filteredActiveKeys[$clean] = true;
}
}
if (!empty($filteredActiveKeys)) {
$activeProjectKeys = $filteredActiveKeys;
}
}
// Haal projectstatussen op uit jiraData
$rawProjectStatuses = $jiraData['project_statuses'] ?? [];
@@ -587,54 +601,18 @@ $statusesJson = json_encode($allStatusesList, JSON_HEX_TAG | JSON_HEX_APOS | JSO
</div>
</div>
<!-- Rij 3: Status Multi-select Dropdown & Zoekveld -->
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 relative z-30">
<!-- Rij 2: Status Filters PER Project (Direct onder de projectknoppen) & Zoekveld -->
<div class="flex flex-col md:flex-row md:items-center justify-between gap-3 pt-0.5 relative z-30">
<!-- Linkerkant: Statussen multi-select dropdown -->
<!-- Linkerkant: Status Dropdowns PER Project -->
<div class="flex flex-wrap items-center gap-2 relative z-50">
<div class="relative z-50" id="statusDropdownWrapper">
<button
type="button"
onclick="toggleStatusDropdown()"
id="statusDropdownBtn"
class="flex items-center space-x-2 px-3.5 py-2 rounded-xl text-xs font-semibold bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 hover:border-slate-300 dark:hover:border-slate-600 text-slate-800 dark:text-slate-200 transition cursor-pointer shadow-2xs"
aria-expanded="false"
>
<i data-lucide="check-square" class="w-3.5 h-3.5 text-indigo-500"></i>
<span>Status:</span>
<span id="statusDropdownLabel" class="font-bold text-indigo-600 dark:text-indigo-400">Alle statussen</span>
<span id="statusDropdownBadge" class="hidden px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-indigo-100 dark:bg-indigo-950/60 text-indigo-700 dark:text-indigo-300"></span>
<i data-lucide="chevron-down" id="statusDropdownChevron" class="w-3.5 h-3.5 text-slate-400 transition-transform duration-200"></i>
</button>
<!-- Dropdown Menu met Checkboxes (Gegroepeerd per project) -->
<div
id="statusDropdownMenu"
class="hidden absolute left-0 top-full mt-2 w-[calc(100vw-2.5rem)] sm:w-96 max-w-sm bg-white dark:bg-slate-900 rounded-2xl shadow-2xl border border-slate-200 dark:border-slate-800 py-3 px-3.5 z-50 text-xs space-y-2.5"
>
<!-- Quick actions header -->
<div class="flex items-center justify-between pb-2 border-b border-slate-100 dark:border-slate-800">
<span class="font-bold text-slate-900 dark:text-white text-[11px] uppercase tracking-wider">Statussen per Project</span>
<div class="flex items-center space-x-1.5">
<button type="button" onclick="selectAllStatuses(true)" class="px-2 py-0.5 rounded-md text-[10px] font-bold text-indigo-600 dark:text-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-950/60 transition cursor-pointer">
Alles
</button>
<span class="text-slate-300 dark:text-slate-700">•</span>
<button type="button" onclick="selectActiveStatusesOnly()" class="px-2 py-0.5 rounded-md text-[10px] font-bold text-emerald-600 dark:text-emerald-400 hover:bg-emerald-50 dark:hover:bg-emerald-950/60 transition cursor-pointer" title="Alleen actieve taken (geen gesloten)">
Actief
</button>
<span class="text-slate-300 dark:text-slate-700">•</span>
<button type="button" onclick="selectAllStatuses(false)" class="px-2 py-0.5 rounded-md text-[10px] font-bold text-slate-500 hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer">
Geen
</button>
</div>
<div class="flex items-center space-x-1.5 text-slate-400 dark:text-slate-500 mr-0.5 flex-shrink-0">
<i data-lucide="filter" class="w-3.5 h-3.5 text-indigo-500"></i>
<span class="text-[11px] font-bold uppercase tracking-wider">Status:</span>
</div>
<!-- Status Checkboxes List (scrollable, gegroepeerd per project) -->
<div class="max-h-80 overflow-y-auto space-y-2.5 pr-1 custom-scrollbar" id="statusCheckboxList">
<!-- Dynamisch gevuld via renderStatusCheckboxes() -->
</div>
</div>
<!-- Hier worden de status dropdowns per project dynamisch ingeladen -->
<div id="projectStatusDropdownsWrapper" class="flex flex-wrap items-center gap-2">
</div>
<!-- Actieve filters reset knop als er iets gefilterd is -->
@@ -645,7 +623,7 @@ $statusesJson = json_encode($allStatusesList, JSON_HEX_TAG | JSON_HEX_APOS | JSO
</div>
<!-- Rechterkant: Zoekveld -->
<div class="relative w-full sm:w-64">
<div class="relative w-full md:w-64 flex-shrink-0">
<i data-lucide="search" class="w-3.5 h-3.5 text-slate-400 absolute left-2.5 top-1/2 -translate-y-1/2 pointer-events-none"></i>
<input
type="text"
@@ -1148,7 +1126,7 @@ function updateActiveFilterBadge() {
}
// =========================================================================
// STATUS MULTI-SELECT CHECKBOX DROPDOWN LOGICA (GEGROEPEERD PER PROJECT)
// STATUS MULTI-SELECT CHECKBOX DROPDOWN LOGICA (PER PROJECT DROPDOWNS)
// =========================================================================
function getTotalStatusCount() {
@@ -1175,63 +1153,48 @@ function isIssueStatusSelected(iss) {
return false;
}
// Renders the per-project status dropdowns into #projectStatusDropdownsWrapper
function renderStatusCheckboxes() {
const container = document.getElementById('statusCheckboxList');
const container = document.getElementById('projectStatusDropdownsWrapper');
if (!container) return;
if (!projectStatusesData || projectStatusesData.length === 0) {
container.innerHTML = '<div class="py-2 text-center text-slate-400 italic text-[11px]">Geen project statussen gevonden</div>';
container.innerHTML = '<span class="text-slate-400 italic text-[11px]">Geen project statussen gevonden</span>';
return;
}
const colorClasses = {
sky: {
badge: 'bg-sky-100 dark:bg-sky-900/60 text-sky-800 dark:text-sky-200 border border-sky-300 dark:border-sky-800',
hdrBg: 'bg-sky-50/60 dark:bg-sky-950/30'
badge: 'bg-sky-100 text-sky-800 dark:bg-sky-950/70 dark:text-sky-300 border border-sky-300 dark:border-sky-800',
hdrBg: 'bg-sky-50/70 dark:bg-sky-950/40'
},
amber: {
badge: 'bg-amber-100 dark:bg-amber-900/60 text-amber-800 dark:text-amber-200 border border-amber-300 dark:border-amber-800',
hdrBg: 'bg-amber-50/60 dark:bg-amber-950/30'
badge: 'bg-amber-100 text-amber-800 dark:bg-amber-950/70 dark:text-amber-300 border border-amber-300 dark:border-amber-800',
hdrBg: 'bg-amber-50/70 dark:bg-amber-950/40'
},
emerald: {
badge: 'bg-emerald-100 dark:bg-emerald-900/60 text-emerald-800 dark:text-emerald-200 border border-emerald-300 dark:border-emerald-800',
hdrBg: 'bg-emerald-50/60 dark:bg-emerald-950/30'
badge: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950/70 dark:text-emerald-300 border border-emerald-300 dark:border-emerald-800',
hdrBg: 'bg-emerald-50/70 dark:bg-emerald-950/40'
},
indigo: {
badge: 'bg-indigo-100 dark:bg-indigo-900/60 text-indigo-800 dark:text-indigo-200 border border-indigo-300 dark:border-indigo-800',
hdrBg: 'bg-indigo-50/60 dark:bg-indigo-950/30'
badge: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-950/70 dark:text-indigo-300 border border-indigo-300 dark:border-indigo-800',
hdrBg: 'bg-indigo-50/70 dark:bg-indigo-950/40'
},
slate: {
badge: 'bg-slate-100 dark:bg-slate-800 text-slate-800 dark:text-slate-200 border border-slate-300 dark:border-slate-700',
badge: 'bg-slate-100 text-slate-800 dark:bg-slate-800 dark:text-slate-200 border border-slate-300 dark:border-slate-700',
hdrBg: 'bg-slate-50 dark:bg-slate-800/40'
}
};
let html = '';
projectStatusesData.forEach((proj, pIdx) => {
const pKey = (proj.key || '').toUpperCase();
const pKey = (proj.key || '').toUpperCase().trim();
const pKeyLower = pKey.toLowerCase();
const pColor = proj.color || 'slate';
const styles = colorClasses[pColor] || colorClasses.slate;
const statuses = proj.statuses || [];
html += `
<div class="project-status-group pb-2 mb-2 border-b border-slate-100 dark:border-slate-800/80 last:border-b-0 last:pb-0 last:mb-0">
<div class="flex items-center justify-between px-2 py-1.5 mb-1.5 rounded-lg ${styles.hdrBg}">
<div class="flex items-center space-x-2 min-w-0">
<span class="px-1.5 py-0.5 rounded font-mono text-[10px] font-black ${styles.badge}">${escapeHtml(pKey)}</span>
<span class="font-bold text-slate-800 dark:text-slate-200 text-xs truncate">${escapeHtml(proj.name || pKey)}</span>
<span id="projTotal_${pKey}" class="text-[10px] text-slate-400 font-bold">(0)</span>
</div>
<div class="flex items-center space-x-1.5 text-[10px] flex-shrink-0">
<button type="button" onclick="selectProjectStatuses('${escapeHtml(pKey)}', true)" class="px-1.5 py-0.5 rounded font-semibold text-indigo-600 dark:text-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-950/60 transition cursor-pointer">Alles</button>
<span class="text-slate-300 dark:text-slate-700">•</span>
<button type="button" onclick="selectProjectStatuses('${escapeHtml(pKey)}', false)" class="px-1.5 py-0.5 rounded font-semibold text-slate-500 hover:bg-slate-200 dark:hover:bg-slate-700 transition cursor-pointer">Geen</button>
</div>
</div>
<div class="space-y-0.5 pl-1">
`;
let statusRowsHtml = '';
statuses.forEach((st, sIdx) => {
const sNorm = (st.name || '').toLowerCase().trim();
const compoundVal = `${pKeyLower}::${sNorm}`;
@@ -1253,10 +1216,10 @@ function renderStatusCheckboxes() {
}
const safeKey = `${pKey}_${sNorm.replace(/[^a-z0-9]/gi, '_')}`;
const safeId = `chkStatus_${pIdx}_${sIdx}`;
const safeId = `chkStatus_${pKey}_${sIdx}`;
html += `
<label for="${safeId}" class="flex items-center justify-between px-2 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800/70 cursor-pointer transition select-none group">
statusRowsHtml += `
<label for="${safeId}" class="flex items-center justify-between px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800/70 cursor-pointer transition select-none group">
<div class="flex items-center space-x-2.5 min-w-0 flex-1">
<input
type="checkbox"
@@ -1266,8 +1229,8 @@ function renderStatusCheckboxes() {
data-status="${escapeHtml(sNorm)}"
data-is-done="${isDone ? 1 : 0}"
${isChecked ? 'checked' : ''}
onchange="onStatusCheckboxChange()"
class="status-checkbox w-4 h-4 rounded text-indigo-600 border-slate-300 dark:border-slate-700 focus:ring-indigo-500 cursor-pointer flex-shrink-0"
onchange="onStatusCheckboxChange('${escapeHtml(pKey)}')"
class="status-checkbox status-checkbox-${escapeHtml(pKey)} w-4 h-4 rounded text-indigo-600 border-slate-300 dark:border-slate-700 focus:ring-indigo-500 cursor-pointer flex-shrink-0"
>
<span class="w-2 h-2 rounded-full ${dotColor} flex-shrink-0"></span>
<span class="font-semibold text-slate-700 dark:text-slate-300 truncate text-xs group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition">${escapeHtml(st.name)}</span>
@@ -1278,13 +1241,132 @@ function renderStatusCheckboxes() {
});
html += `
<div class="relative project-status-dropdown-item" data-project="${escapeHtml(pKey)}" id="statusDropdownWrapper_${escapeHtml(pKey)}">
<button
type="button"
onclick="toggleProjectStatusDropdown('${escapeHtml(pKey)}')"
id="statusDropdownBtn_${escapeHtml(pKey)}"
class="flex items-center space-x-1.5 px-2.5 sm:px-3 py-1.5 rounded-xl text-xs font-semibold bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 hover:border-slate-300 dark:hover:border-slate-600 text-slate-800 dark:text-slate-200 transition cursor-pointer shadow-2xs flex-shrink-0"
aria-expanded="false"
>
<span class="px-1.5 py-0.5 rounded font-mono text-[10px] font-black ${styles.badge}">${escapeHtml(pKey)}</span>
<span id="statusDropdownLabel_${escapeHtml(pKey)}" class="font-bold text-slate-700 dark:text-slate-300 truncate max-w-[130px]">Alle</span>
<span id="statusDropdownBadge_${escapeHtml(pKey)}" class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300"></span>
<i data-lucide="chevron-down" id="statusDropdownChevron_${escapeHtml(pKey)}" class="w-3.5 h-3.5 text-slate-400 transition-transform duration-200 flex-shrink-0"></i>
</button>
<div
id="statusDropdownMenu_${escapeHtml(pKey)}"
class="hidden absolute left-0 top-full mt-1.5 w-72 sm:w-80 max-w-[calc(100vw-2.5rem)] bg-white dark:bg-slate-900 rounded-2xl shadow-2xl border border-slate-200 dark:border-slate-800 py-3 px-3.5 z-50 text-xs space-y-2.5"
>
<div class="flex items-center justify-between pb-2 border-b border-slate-100 dark:border-slate-800 ${styles.hdrBg} -mx-3.5 -mt-3 p-3 rounded-t-2xl">
<div class="flex items-center space-x-1.5 min-w-0">
<span class="px-1.5 py-0.5 rounded font-mono text-[10px] font-black ${styles.badge}">${escapeHtml(pKey)}</span>
<span class="font-bold text-slate-900 dark:text-white text-xs truncate">${escapeHtml(proj.name || pKey)}</span>
<span id="projTotal_${escapeHtml(pKey)}" class="text-[10px] text-slate-400 font-bold">(0)</span>
</div>
<div class="flex items-center space-x-1 text-[10px] flex-shrink-0">
<button type="button" onclick="selectProjectStatuses('${escapeHtml(pKey)}', true)" class="px-1.5 py-0.5 rounded font-bold text-indigo-600 dark:text-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-950/60 transition cursor-pointer">
Alles
</button>
<span class="text-slate-300 dark:text-slate-700">•</span>
<button type="button" onclick="selectProjectActiveStatuses('${escapeHtml(pKey)}')" class="px-1.5 py-0.5 rounded font-bold text-emerald-600 dark:text-emerald-400 hover:bg-emerald-50 dark:hover:bg-emerald-950/60 transition cursor-pointer" title="Alleen actieve taken">
Actief
</button>
<span class="text-slate-300 dark:text-slate-700">•</span>
<button type="button" onclick="selectProjectStatuses('${escapeHtml(pKey)}', false)" class="px-1.5 py-0.5 rounded font-bold text-slate-500 hover:bg-slate-200 dark:hover:bg-slate-700 transition cursor-pointer">
Geen
</button>
</div>
</div>
<div class="max-h-60 overflow-y-auto space-y-1 pr-1 custom-scrollbar" id="statusCheckboxList_${escapeHtml(pKey)}">
${statusRowsHtml}
</div>
</div>
</div>
`;
});
container.innerHTML = html;
if (typeof lucide !== 'undefined') lucide.createIcons();
updateStatusCounts();
updateStatusDropdownLabel();
updateProjectStatusDropdownVisibility();
}
function updateProjectStatusDropdownVisibility() {
const items = document.querySelectorAll('.project-status-dropdown-item');
const curNorm = (currentProject || '').toUpperCase().trim();
items.forEach(item => {
const pKey = (item.getAttribute('data-project') || '').toUpperCase().trim();
if (!curNorm) {
// "Alle Projecten": toon alle toegewezen project dropdowns
item.classList.remove('hidden');
} else if (curNorm === pKey) {
item.classList.remove('hidden');
} else if (curNorm === 'DX' && pKey === 'SD') {
item.classList.remove('hidden');
} else {
item.classList.add('hidden');
}
});
}
function toggleProjectStatusDropdown(projectKey, force) {
const targetKey = (projectKey || '').toUpperCase().trim();
const menu = document.getElementById(`statusDropdownMenu_${targetKey}`);
const chevron = document.getElementById(`statusDropdownChevron_${targetKey}`);
const btn = document.getElementById(`statusDropdownBtn_${targetKey}`);
if (!menu) return;
const willOpen = (typeof force === 'boolean') ? force : menu.classList.contains('hidden');
// Sluit alle andere geopende status dropdowns
closeAllProjectStatusDropdowns(targetKey);
if (willOpen) {
menu.classList.remove('hidden');
if (chevron) chevron.classList.add('rotate-180');
if (btn) btn.setAttribute('aria-expanded', 'true');
updateStatusCounts();
} else {
menu.classList.add('hidden');
if (chevron) chevron.classList.remove('rotate-180');
if (btn) btn.setAttribute('aria-expanded', 'false');
}
}
function closeAllProjectStatusDropdowns(exceptKey = '') {
const exceptNorm = (exceptKey || '').toUpperCase().trim();
(projectStatusesData || []).forEach(proj => {
const pKey = (proj.key || '').toUpperCase().trim();
if (pKey === exceptNorm) return;
const menu = document.getElementById(`statusDropdownMenu_${pKey}`);
const chevron = document.getElementById(`statusDropdownChevron_${pKey}`);
const btn = document.getElementById(`statusDropdownBtn_${pKey}`);
if (menu && !menu.classList.contains('hidden')) {
menu.classList.add('hidden');
if (chevron) chevron.classList.remove('rotate-180');
if (btn) btn.setAttribute('aria-expanded', 'false');
}
});
}
// Sluit dropdowns bij klikken buiten dropdowns
document.addEventListener('click', (e) => {
const isInside = e.target.closest('.project-status-dropdown-item');
if (!isInside) {
closeAllProjectStatusDropdowns();
}
});
function toggleStatusDropdown(force) {
if (currentProject) {
toggleProjectStatusDropdown(currentProject, force);
} else if (projectStatusesData && projectStatusesData.length > 0) {
toggleProjectStatusDropdown(projectStatusesData[0].key, force);
}
}
function updateStatusCounts() {
@@ -1321,37 +1403,18 @@ function updateStatusCounts() {
});
}
function toggleStatusDropdown(force) {
const menu = document.getElementById('statusDropdownMenu');
const chevron = document.getElementById('statusDropdownChevron');
const btn = document.getElementById('statusDropdownBtn');
if (!menu) return;
function onStatusCheckboxChange(projectKey) {
const pNorm = (projectKey || '').toUpperCase().trim();
const pKeyLower = pNorm.toLowerCase();
const chks = document.querySelectorAll(`.status-checkbox-${pNorm}`);
const willOpen = (typeof force === 'boolean') ? force : menu.classList.contains('hidden');
if (willOpen) {
menu.classList.remove('hidden');
if (chevron) chevron.classList.add('rotate-180');
if (btn) btn.setAttribute('aria-expanded', 'true');
updateStatusCounts();
chks.forEach(chk => {
const val = chk.value.toLowerCase().trim();
if (chk.checked) {
selectedStatuses.add(val);
} else {
menu.classList.add('hidden');
if (chevron) chevron.classList.remove('rotate-180');
if (btn) btn.setAttribute('aria-expanded', 'false');
selectedStatuses.delete(val);
}
}
document.addEventListener('click', (e) => {
const wrapper = document.getElementById('statusDropdownWrapper');
if (wrapper && !wrapper.contains(e.target)) {
toggleStatusDropdown(false);
}
});
function onStatusCheckboxChange() {
selectedStatuses.clear();
const checked = document.querySelectorAll('.status-checkbox:checked');
checked.forEach(chk => {
if (chk.value) selectedStatuses.add(chk.value.toLowerCase().trim());
});
try {
@@ -1364,7 +1427,9 @@ function onStatusCheckboxChange() {
function selectProjectStatuses(projectKey, selectAll) {
const targetKey = (projectKey || '').toUpperCase().trim();
const pKeyLower = targetKey.toLowerCase();
const chks = document.querySelectorAll(`.status-checkbox[data-project="${targetKey}"]`);
chks.forEach(chk => {
chk.checked = !!selectAll;
const val = chk.value.toLowerCase().trim();
@@ -1383,6 +1448,29 @@ function selectProjectStatuses(projectKey, selectAll) {
applyFilters();
}
function selectProjectActiveStatuses(projectKey) {
const targetKey = (projectKey || '').toUpperCase().trim();
const chks = document.querySelectorAll(`.status-checkbox[data-project="${targetKey}"]`);
chks.forEach(chk => {
const isDone = chk.getAttribute('data-is-done') === '1';
chk.checked = !isDone;
const val = chk.value.toLowerCase().trim();
if (!isDone) {
selectedStatuses.add(val);
} else {
selectedStatuses.delete(val);
}
});
try {
localStorage.setItem('fociz_jira_selected_statuses', JSON.stringify([...selectedStatuses]));
} catch (e) {}
updateStatusDropdownLabel();
applyFilters();
}
function selectAllStatuses(selectAll) {
selectedStatuses.clear();
const chks = document.querySelectorAll('.status-checkbox');
@@ -1401,55 +1489,78 @@ function selectAllStatuses(selectAll) {
applyFilters();
}
function selectActiveStatusesOnly() {
selectedStatuses.clear();
const chks = document.querySelectorAll('.status-checkbox');
chks.forEach(chk => {
const isDone = chk.getAttribute('data-is-done') === '1';
chk.checked = !isDone;
if (!isDone && chk.value) {
selectedStatuses.add(chk.value.toLowerCase().trim());
function updateStatusDropdownLabel() {
let hasAnyCustomFilter = false;
(projectStatusesData || []).forEach(proj => {
const pKey = (proj.key || '').toUpperCase().trim();
const pKeyLower = pKey.toLowerCase();
const labelEl = document.getElementById(`statusDropdownLabel_${pKey}`);
const badgeEl = document.getElementById(`statusDropdownBadge_${pKey}`);
if (!labelEl) return;
const statuses = proj.statuses || [];
const total = statuses.length;
let selectedCount = 0;
let activeTotal = 0;
let activeSelected = 0;
let singleStatusName = '';
statuses.forEach(st => {
const sNorm = (st.name || '').toLowerCase().trim();
const compound = `${pKeyLower}::${sNorm}`;
const cat = (st.status_category || '').toLowerCase().trim();
const isDone = (cat === 'done' || isDoneStatus(sNorm));
if (!isDone) activeTotal++;
if (selectedStatuses.has(compound) || selectedStatuses.has(sNorm)) {
selectedCount++;
singleStatusName = st.name;
if (!isDone) activeSelected++;
}
});
try {
localStorage.setItem('fociz_jira_selected_statuses', JSON.stringify([...selectedStatuses]));
} catch (e) {}
if (selectedCount < total) {
hasAnyCustomFilter = true;
}
updateStatusDropdownLabel();
applyFilters();
}
function updateStatusDropdownLabel() {
const labelEl = document.getElementById('statusDropdownLabel');
const badgeEl = document.getElementById('statusDropdownBadge');
if (!labelEl) return;
const total = getTotalStatusCount();
const selected = selectedStatuses.size;
if (selected === total || (total === 0 && selected === 0)) {
if (selectedCount === total || (total === 0 && selectedCount === 0)) {
labelEl.innerText = "Alle statussen";
if (badgeEl) badgeEl.classList.add('hidden');
} else if (selected === 0) {
labelEl.innerText = "Geen geselecteerd";
if (badgeEl) {
badgeEl.innerText = total;
badgeEl.className = "px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-100 dark:bg-slate-800 text-slate-500 dark:text-slate-400";
}
} else if (selectedCount === 0) {
labelEl.innerText = "Geen";
if (badgeEl) {
badgeEl.innerText = "0";
badgeEl.classList.remove('hidden');
badgeEl.className = "px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-rose-100 dark:bg-rose-950/60 text-rose-700 dark:text-rose-300";
}
} else {
labelEl.innerText = `${selected} statussen`;
} else if (selectedCount === activeTotal && activeSelected === activeTotal && activeTotal > 0) {
labelEl.innerText = "Actief";
if (badgeEl) {
badgeEl.innerText = `${selected}/${total}`;
badgeEl.classList.remove('hidden');
badgeEl.innerText = `${activeSelected}/${total}`;
badgeEl.className = "px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-emerald-100 dark:bg-emerald-950/60 text-emerald-700 dark:text-emerald-300";
}
} else if (selectedCount === 1) {
labelEl.innerText = singleStatusName;
if (badgeEl) {
badgeEl.innerText = `1/${total}`;
badgeEl.className = "px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-indigo-100 dark:bg-indigo-950/60 text-indigo-700 dark:text-indigo-300";
}
} else {
labelEl.innerText = `${selectedCount} statussen`;
if (badgeEl) {
badgeEl.innerText = `${selectedCount}/${total}`;
badgeEl.className = "px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-indigo-100 dark:bg-indigo-950/60 text-indigo-700 dark:text-indigo-300";
}
}
});
const btnReset = document.getElementById('btnResetFiltersInline');
if (btnReset) {
const isCustom = selected < total || currentProject !== '' || document.getElementById('jiraSearchInput')?.value;
const isCustom = hasAnyCustomFilter || currentProject !== '' || document.getElementById('jiraSearchInput')?.value;
if (isCustom) btnReset.classList.remove('hidden');
else btnReset.classList.add('hidden');
}
@@ -1465,16 +1576,16 @@ function initStatusSelection() {
let validSaved = false;
if (Array.isArray(saved) && saved.length > 0) {
const hasCompound = saved.some(s => String(s).includes('::'));
if (hasCompound) {
saved.forEach(s => {
if (s) selectedStatuses.add(String(s).toLowerCase().trim());
});
if (selectedStatuses.size > 0) {
validSaved = true;
}
}
if (!validSaved || selectedStatuses.size === 0) {
selectedStatuses.clear();
if (!validSaved) {
// Standaard alle actieve statussen selecteren, gesloten uit conform gebruikerswens
(projectStatusesData || []).forEach(proj => {
const pKeyLower = (proj.key || '').toLowerCase().trim();
@@ -1509,13 +1620,15 @@ function initStatusSelection() {
}
renderStatusCheckboxes();
updateStatusDropdownLabel();
}
// Project selectie via pill tabs
function selectProject(proj) {
currentProject = (proj || '').trim();
closeAllProjectStatusDropdowns();
updateProjectPills();
updateProjectStatusDropdownVisibility();
updateStatusCounts();
applyFilters();
}
@@ -1882,6 +1995,7 @@ function clearSearch() {
function resetAllFilters() {
currentProject = '';
currentQueue = '';
closeAllProjectStatusDropdowns();
selectAllStatuses(true);
const searchInput = document.getElementById('jiraSearchInput');
@@ -1894,7 +2008,8 @@ function resetAllFilters() {
document.getElementById('clearSearchBtn')?.classList.add('hidden');
updateProjectPills();
updateQueuePills();
updateProjectStatusDropdownVisibility();
updateStatusCounts();
applyFilters();
}