From 6c3098922f0ebf8ebb7ada9ff0d6ba6966b1ee29 Mon Sep 17 00:00:00 2001 From: "n.siegfried" Date: Mon, 3 Aug 2026 17:26:27 -0700 Subject: [PATCH] Field view: a package waiting on a predecessor is not "Ready" The field list judged readiness from open constraints alone, so a package whose predecessor isn't Closed showed a green Ready pill even though the server would refuse to issue it. It now shows "waits on N", matching the form, the dashboard and the navigator drawer. A deleted predecessor still doesn't block. Co-Authored-By: Claude Opus 5 (1M context) --- html/field.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/html/field.js b/html/field.js index d33182b..f81a7af 100644 --- a/html/field.js +++ b/html/field.js @@ -12,6 +12,16 @@ function esc(s) { return s == null ? '' : String(s).replace(/&/g, '&').repla function nsKey(id) { return 'wp_iwp_v1__' + id; } function stLabel(s) { return s === 'Issue' ? 'Issue (Hold)' : s; } function openCount(p) { return ((p && p.constraints) || []).filter(function (c) { return c.status === 'open'; }).length; } +// Predecessor packages that aren't Closed yet. A package waiting on upstream work +// is not release-ready either, so the field list must not call it Ready — the +// server would refuse to issue it (see enforce_release_gates). +function waitingCount(p, all) { + var preds = (p && p.predecessors) || []; + if (!preds.length) return 0; + var byId = {}; + (all || []).forEach(function (x) { byId[x.id] = x; }); + return preds.filter(function (id) { var q = byId[id]; return q && q.status !== 'Closed'; }).length; +} function fmtTs(s) { try { return wpFormatDateTime(s); } catch (e) { return s || ''; } } function me() { try { return (window.WP_USER && (window.WP_USER.full_name || window.WP_USER.username)) || ''; } catch (e) { return ''; } } function toast(m) { var t = document.getElementById('toast'); if (!t) return; t.textContent = m; t.classList.add('show'); clearTimeout(toast._t); toast._t = setTimeout(function () { t.classList.remove('show'); }, 2000); } @@ -57,8 +67,12 @@ function renderList() { if (!rows.length) { box.innerHTML = '
' + (WPS.length ? 'No packages match your search.' : 'No work packages for this project yet.') + '
'; return; } box.innerHTML = rows.map(function (p) { var open = openCount(p); - var cls = p.status === 'Issue' ? 'hold' : (open === 0 ? 'ready' : ''); - var readyPill = p.status === 'Issue' ? 'On hold' : (open ? '' + open + ' open' : 'Ready'); + var waiting = waitingCount(p, WPS); // the full set, not the filtered rows + var cls = p.status === 'Issue' ? 'hold' : ((open === 0 && !waiting) ? 'ready' : ''); + var readyPill = p.status === 'Issue' ? 'On hold' + : (open ? '' + open + ' open' + : (waiting ? 'waits on ' + waiting + '' + : 'Ready')); return '