From f543c19d9c7218cd69d7f1fdf67da0e66d6650e6 Mon Sep 17 00:00:00 2001 From: Greg Date: Sun, 24 May 2026 11:45:29 -0500 Subject: [PATCH] Filter panel by primary muter's matchColors scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User color-codes sub-groups (e.g. gold 'Flux Klein Workflow' inside a larger blue 'Place an image' workflow) and routes them through a separate Fast Groups Muter via matchColors. The intent: sub-groups aren't top-level navigation targets, they're implementation details of their parent workflow. New getNavigableGroups(): if any muter exists, pick the one with the most managed widgets as the 'primary navigation muter' and show only its groups in the panel. Sub-groups managed by smaller scoped muters get filtered out. No muter present → show every group (previous behavior). Header count now shows 'N / M' when filtering, with tooltip explaining how many sub-groups were hidden. Keyboard 1-9 follows the same filtered list. --- web/index.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/web/index.js b/web/index.js index 885dca7..ec609a8 100644 --- a/web/index.js +++ b/web/index.js @@ -90,6 +90,19 @@ function getGroups() { return (app.graph?._groups || []).filter(Boolean); } +/** The groups the panel actually navigates between. If the workflow has any + * Fast Groups Muter, we mirror the *primary* one (= the muter with the most + * managed widgets). That respects the user's matchColors partition: a sub- + * group with a different color belongs to a smaller muter and gets filtered + * out of the nav list. If no muter exists, fall back to every group. */ +function getNavigableGroups() { + const all = getGroups(); + const muters = getMutersAndWidgets(); + if (muters.length === 0) return all; + const primary = muters.reduce((a, b) => (a.widgets.size >= b.widgets.size ? a : b)); + return all.filter((g, i) => primary.widgets.has(groupTitle(g, i))); +} + function groupBounds(g) { // LiteGraph stores bounding as [x, y, w, h] const b = g._bounding || g.bounding; @@ -360,9 +373,16 @@ function applyCollapsed() { function renderList() { const panel = ensurePanel(); - const groups = getGroups(); + const allGroupCount = getGroups().length; + const groups = getNavigableGroups(); const countEl = panel.querySelector(".cnv-panel__header-count"); - countEl.textContent = String(groups.length); + const filteredOut = allGroupCount - groups.length; + countEl.textContent = filteredOut > 0 + ? `${groups.length} / ${allGroupCount}` + : String(groups.length); + countEl.title = filteredOut > 0 + ? `Showing ${groups.length} groups (${filteredOut} sub-group${filteredOut === 1 ? "" : "s"} hidden via matchColors)` + : `${groups.length} groups`; // Hide panel entirely if fewer than 2 groups (nothing to navigate between) if (groups.length < 2) { @@ -410,10 +430,10 @@ function isTypingTarget(el) { function onKeyDown(e) { if (isTypingTarget(document.activeElement)) return; - // 1..9 → jump + // 1..9 → jump (same filtered list the panel shows) if (e.key >= "1" && e.key <= "9" && !e.ctrlKey && !e.metaKey && !e.altKey) { const idx = parseInt(e.key, 10) - 1; - const g = getGroups()[idx]; + const g = getNavigableGroups()[idx]; if (g) { e.preventDefault(); jumpToGroup(g);