diff --git a/jira.php b/jira.php
index 130b401..85127b7 100644
--- a/jira.php
+++ b/jira.php
@@ -234,15 +234,42 @@ $rawProjectStatuses = $jiraData['project_statuses'] ?? [];
$projectStatusesData = [];
$allStatusesMap = [];
-foreach (array_keys($activeProjectKeys) as $pKey) {
- $pName = $coreProjects[$pKey]['name'] ?? ($allProjects[$pKey]['name'] ?? $pKey);
- $pColor = $coreProjects[$pKey]['color'] ?? 'slate';
+$allTargetKeys = array_keys($activeProjectKeys);
+if ($isCodeVisible('DX') && !in_array('DX', $allTargetKeys, true)) {
+ $allTargetKeys[] = 'DX';
+}
+if (!empty($queueFilters)) {
+ foreach ($queueFilters as $qf) {
+ $qCode = strtoupper(trim($qf['filter_code'] ?? ''));
+ if (!empty($qCode) && $isCodeVisible($qCode) && !in_array($qCode, $allTargetKeys, true)) {
+ $allTargetKeys[] = $qCode;
+ }
+ }
+}
+
+foreach ($allTargetKeys as $pKey) {
+ if ($pKey === 'DX') {
+ $pName = 'DX Koppelingen';
+ $pColor = 'amber';
+ } else {
+ $pName = $coreProjects[$pKey]['name'] ?? ($allProjects[$pKey]['name'] ?? $pKey);
+ $pColor = $coreProjects[$pKey]['color'] ?? 'slate';
+ if (!isset($coreProjects[$pKey]) && !empty($queueFilters)) {
+ foreach ($queueFilters as $qf) {
+ if (strtoupper(trim($qf['filter_code'] ?? '')) === $pKey && !empty($qf['filter_name'])) {
+ $pName = $qf['filter_name'];
+ break;
+ }
+ }
+ }
+ }
$pStatuses = [];
// 1. Statussen uit Jira API voor dit project
- if (!empty($rawProjectStatuses[$pKey])) {
- foreach ($rawProjectStatuses[$pKey] as $st) {
+ $apiPKey = ($pKey === 'DX') ? 'SD' : $pKey;
+ if (!empty($rawProjectStatuses[$apiPKey])) {
+ foreach ($rawProjectStatuses[$apiPKey] as $st) {
$sName = trim($st['name'] ?? '');
if (empty($sName)) continue;
$sKey = strtolower($sName);
@@ -256,11 +283,25 @@ foreach (array_keys($activeProjectKeys) as $pKey) {
// 2. Statussen die op de tickets van dit project voorkomen toevoegen/mergen
foreach ($allIssues as $iss) {
- $issPKey = strtoupper(trim($iss['project_key'] ?? ''));
- if (empty($issPKey) && !empty($iss['key']) && preg_match('/^([A-Z0-9]+)-/i', $iss['key'], $m)) {
- $issPKey = strtoupper($m[1]);
+ $matches = false;
+ if ($pKey === 'DX') {
+ $matches = $issueMatchesQueue($iss, 'DX');
+ } else {
+ $issPKey = strtoupper(trim($iss['project_key'] ?? ''));
+ if (empty($issPKey) && !empty($iss['key']) && preg_match('/^([A-Z0-9]+)-/i', $iss['key'], $m)) {
+ $issPKey = strtoupper($m[1]);
+ }
+ $matches = ($issPKey === $pKey);
+ if (!$matches && !empty($queueFilters)) {
+ foreach ($queueFilters as $qf) {
+ if (strtoupper(trim($qf['filter_code'] ?? '')) === $pKey) {
+ $matches = $issueMatchesQueue($iss, $pKey);
+ break;
+ }
+ }
+ }
}
- if ($issPKey === $pKey && !empty($iss['status'])) {
+ if ($matches && !empty($iss['status'])) {
$sName = trim($iss['status']);
$sKey = strtolower($sName);
if (!isset($pStatuses[$sKey])) {
@@ -1114,53 +1155,42 @@ function toggleCurrentProjectOnlyAssigned() {
}
function updateAssignedPillState() {
- const targetKey = (currentProject || 'ALL').toUpperCase().trim();
- const isAssigned = projectOnlyAssigned.has(targetKey) || (currentProject === '' && projectOnlyAssigned.has('ALL'));
- const btn = document.getElementById('btnToggleAssignedToMePill');
- const badge = document.getElementById('badgeAssignedToMeCount');
- const label = document.getElementById('labelAssignedToMePill');
- if (!btn) return;
-
- if (isAssigned) {
- btn.className = "flex items-center space-x-1.5 px-2.5 sm:px-3 py-1.5 rounded-xl text-xs font-bold border border-indigo-600 bg-indigo-600 text-white shadow-xs flex-shrink-0 cursor-pointer";
- if (badge) {
- badge.className = "px-1.5 py-0.5 rounded-full text-[10px] font-black bg-white/20 text-white";
- }
- } else {
- btn.className = "flex items-center space-x-1.5 px-2.5 sm:px-3 py-1.5 rounded-xl text-xs font-semibold border transition cursor-pointer shadow-2xs flex-shrink-0 bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:border-slate-300 dark:hover:border-slate-600";
- if (badge) {
- badge.className = "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";
- }
- }
-
- if (label) {
- if (currentProject) {
- label.innerHTML = `Toegewezen aan mij (${escapeHtml(currentProject)})`;
- } else {
- label.innerHTML = `Toegewezen aan mij (uitvoerder)`;
- }
- }
-
const all = getDeduplicatedIssues();
- let targetList = all;
- if (currentProject) {
- targetList = all.filter(iss => isIssueInQueue(iss, currentProject));
+ const myCountAll = all.filter(iss => isIssueAssignedToMe(iss)).length;
+
+ // Update 'Alle Projecten' dropdown
+ const chkAll = document.getElementById('chkOnlyAssigned_all');
+ if (chkAll) {
+ chkAll.checked = projectOnlyAssigned.has('ALL');
}
- const myCount = targetList.filter(iss => isIssueAssignedToMe(iss)).length;
- if (badge) {
- badge.innerText = myCount;
+ const cntAllEl = document.getElementById('projAssignedCount_all');
+ if (cntAllEl) {
+ cntAllEl.innerText = myCountAll;
+ }
+ const btnMijnAll = document.getElementById('btnDropdownMijn_all');
+ if (btnMijnAll) {
+ if (projectOnlyAssigned.has('ALL')) {
+ btnMijnAll.className = "px-1.5 py-0.5 rounded font-bold bg-indigo-600 text-white transition cursor-pointer";
+ } else {
+ btnMijnAll.className = "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";
+ }
}
+ // Update per-project dropdowns
(projectStatusesData || []).forEach(proj => {
const pKey = (proj.key || '').toUpperCase().trim();
const chk = document.getElementById(`chkOnlyAssigned_${pKey}`);
if (chk) {
chk.checked = projectOnlyAssigned.has(pKey) || projectOnlyAssigned.has('ALL');
}
- const cCnt = all.filter(iss => {
+ let projIssues = all.filter(iss => {
const k = getIssueProjectKey(iss);
- return (k === pKey || (!k && (iss.project || '').toUpperCase().includes(pKey))) && isIssueAssignedToMe(iss);
- }).length;
+ return (k === pKey || (!k && (iss.project || '').toUpperCase().includes(pKey)));
+ });
+ if (pKey === 'DX' || !['SD', 'IN', 'AAN', 'GEN'].includes(pKey)) {
+ projIssues = all.filter(iss => isIssueInQueue(iss, pKey));
+ }
+ const cCnt = projIssues.filter(iss => isIssueAssignedToMe(iss)).length;
const cntEl = document.getElementById(`projAssignedCount_${pKey}`);
if (cntEl) cntEl.innerText = cCnt;
@@ -1174,6 +1204,10 @@ function updateAssignedPillState() {
}
}
});
+
+ if (typeof updateProjectPills === 'function') {
+ updateProjectPills();
+ }
}
// Hulpfunctie voor deduplicatie van tickets (assigned + team)
@@ -1327,258 +1361,338 @@ function isIssueStatusSelected(iss) {
if (compound && selectedStatuses.has(compound)) return true;
if (selectedStatuses.has(issStatus)) return true;
+ if (typeof isIssueInQueue === 'function' && isIssueInQueue(iss, 'DX') && selectedStatuses.has(`dx::${issStatus}`)) return true;
return false;
}
-// Renders the per-project status dropdowns into #projectStatusDropdownsWrapper
-function renderStatusCheckboxes() {
- const container = document.getElementById('projectStatusDropdownsWrapper');
- if (!container) return;
+// Renders each project's status dropdown directly inside its anchored container (#projectDropdownMenu_${pKey})
+function buildStatusCheckboxRowHtml(pKey, st, sIdx, prefix = '') {
+ const sNorm = (st.name || '').toLowerCase().trim();
+ const pKeyUpper = (pKey || '').toUpperCase().trim();
+ const pKeyLower = (pKey || '').toLowerCase().trim();
+ const compoundVal = `${pKeyLower}::${sNorm}`;
+ const cat = (st.status_category || '').toLowerCase().trim();
+ const isDone = (cat === 'done' || isDoneStatus(sNorm));
- if (!projectStatusesData || projectStatusesData.length === 0) {
- container.innerHTML = 'Geen project statussen gevonden';
- return;
+ const isChecked = selectedStatuses.has(compoundVal) || selectedStatuses.has(sNorm);
+ if (isChecked) {
+ selectedStatuses.add(compoundVal);
}
+ let dotColor = 'bg-blue-500';
+ if (cat === 'new' || sNorm.includes('to do') || sNorm.includes('open') || sNorm.includes('nieuw')) {
+ dotColor = 'bg-slate-400';
+ } else if (isDone) {
+ dotColor = 'bg-emerald-500';
+ } else if (sNorm.includes('wacht') || sNorm.includes('klant') || sNorm.includes('pending')) {
+ dotColor = 'bg-amber-500';
+ }
+
+ const safeKey = `${pKeyUpper}_${sNorm.replace(/[^a-z0-9]/gi, '_')}`;
+ const safeId = `chkStatus_${prefix}${pKeyUpper}_${sIdx}`;
+
+ return `
+
+ `;
+}
+
+function renderStatusCheckboxes() {
const colorClasses = {
sky: {
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'
+ hdrBg: 'bg-sky-50/80 dark:bg-sky-950/40'
},
amber: {
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'
+ hdrBg: 'bg-amber-50/80 dark:bg-amber-950/40'
},
emerald: {
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'
+ hdrBg: 'bg-emerald-50/80 dark:bg-emerald-950/40'
},
indigo: {
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'
+ hdrBg: 'bg-indigo-50/80 dark:bg-indigo-950/40'
},
slate: {
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'
+ hdrBg: 'bg-slate-50/80 dark:bg-slate-800/40'
}
};
- let html = '';
- projectStatusesData.forEach((proj, pIdx) => {
+ // 1. Dropdown voor "Alle Projecten" (#projectDropdownMenu_all)
+ const menuAll = document.getElementById('projectDropdownMenu_all');
+ if (menuAll) {
+ let allStatusesGroupedHtml = '';
+ (projectStatusesData || []).forEach(proj => {
+ const pKey = (proj.key || '').toUpperCase().trim();
+ const pColor = proj.color || 'slate';
+ const styles = colorClasses[pColor] || colorClasses.slate;
+ const statuses = proj.statuses || [];
+ if (statuses.length === 0) return;
+
+ let rows = '';
+ statuses.forEach((st, sIdx) => {
+ rows += buildStatusCheckboxRowHtml(pKey, st, sIdx, 'all_');
+ });
+
+ allStatusesGroupedHtml += `
+
+
+
+ ${escapeHtml(pKey)}
+ ${escapeHtml(proj.name || pKey)}
+
+
+
+ •
+
+
+
+
+ ${rows}
+
+
+ `;
+ });
+
+ menuAll.innerHTML = `
+
+
+
+ Alle Projecten
+ (0)
+
+
+
+ •
+
+ •
+
+ •
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+ `;
+ }
+
+ // 2. Dropdown per afzonderlijk project (#projectDropdownMenu_${pKey})
+ (projectStatusesData || []).forEach(proj => {
const pKey = (proj.key || '').toUpperCase().trim();
- const pKeyLower = pKey.toLowerCase();
+ const menuEl = document.getElementById(`projectDropdownMenu_${pKey}`);
+ if (!menuEl) return;
+
const pColor = proj.color || 'slate';
const styles = colorClasses[pColor] || colorClasses.slate;
const statuses = proj.statuses || [];
let statusRowsHtml = '';
statuses.forEach((st, sIdx) => {
- const sNorm = (st.name || '').toLowerCase().trim();
- const compoundVal = `${pKeyLower}::${sNorm}`;
- const cat = (st.status_category || '').toLowerCase().trim();
- const isDone = (cat === 'done' || isDoneStatus(sNorm));
-
- const isChecked = selectedStatuses.has(compoundVal) || selectedStatuses.has(sNorm);
- if (isChecked) {
- selectedStatuses.add(compoundVal);
- }
-
- let dotColor = 'bg-blue-500';
- if (cat === 'new' || sNorm.includes('to do') || sNorm.includes('open') || sNorm.includes('nieuw')) {
- dotColor = 'bg-slate-400';
- } else if (isDone) {
- dotColor = 'bg-emerald-500';
- } else if (sNorm.includes('wacht') || sNorm.includes('klant') || sNorm.includes('pending')) {
- dotColor = 'bg-amber-500';
- }
-
- const safeKey = `${pKey}_${sNorm.replace(/[^a-z0-9]/gi, '_')}`;
- const safeId = `chkStatus_${pKey}_${sIdx}`;
-
- statusRowsHtml += `
-
- `;
+ statusRowsHtml += buildStatusCheckboxRowHtml(pKey, st, sIdx, '');
});
- html += `
-
-