donobu 5.43.2 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/reporter/render.js +106 -20
- package/dist/reporter/render.js +106 -20
- package/package.json +1 -1
|
@@ -1678,7 +1678,7 @@ function renderHtml(report, triage, outputDir) {
|
|
|
1678
1678
|
? `<div class="flow-id-detail"><span class="detail-label">Flow ID</span><span class="flow-id-value">${esc(test.flowId)}<button class="copy-flow-id" data-flow-id="${esc(test.flowId)}" title="Copy flow ID"><svg viewBox="0 0 24 24"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></button></span></div>`
|
|
1679
1679
|
: '';
|
|
1680
1680
|
testSectionsHtml += `
|
|
1681
|
-
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1681
|
+
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-search="${esc((displayFileName + ' ' + test.specTitle).toLowerCase())}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1682
1682
|
<div class="test-summary">
|
|
1683
1683
|
${chevron}
|
|
1684
1684
|
<span class="status-dot" style="background:${sc.color}" title="${sc.label}"></span>
|
|
@@ -1769,6 +1769,17 @@ body::before{content:'';position:fixed;top:-750px;left:50%;transform:translateX(
|
|
|
1769
1769
|
.stat-pill.active{background:var(--accent);border-color:var(--accent);color:#fff}
|
|
1770
1770
|
.stat-pill.active .pill-count{background:rgba(255,255,255,.25);color:#fff}
|
|
1771
1771
|
.pill-count{font-size:11px;font-weight:700;background:var(--overlay-light-active);color:var(--text-dim);padding:1px 7px;border-radius:calc(var(--radius) - 2px);min-width:20px;text-align:center;transition:all .2s}
|
|
1772
|
+
/* Substring search across test filename + spec title. Lives in the same row
|
|
1773
|
+
* as the stat pills and tag/diagnosis filter. */
|
|
1774
|
+
.filter-search-wrap{position:relative;display:inline-flex;align-items:center;flex-shrink:0}
|
|
1775
|
+
.filter-search-icon{position:absolute;left:8px;width:14px;height:14px;color:var(--text-muted);fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;pointer-events:none}
|
|
1776
|
+
.filter-search{background:var(--surface);border:1px solid var(--border);color:var(--text);font:inherit;font-size:12px;height:28px;padding:0 10px 0 28px;border-radius:var(--radius);width:200px;outline:none;transition:border-color .15s,background .15s}
|
|
1777
|
+
.filter-search::placeholder{color:var(--text-dim)}
|
|
1778
|
+
.filter-search:hover{border-color:var(--text-dim)}
|
|
1779
|
+
.filter-search:focus{border-color:var(--accent);background:var(--surface-raised)}
|
|
1780
|
+
/* Hide the WebKit search clear "x" — Clear Filters wipes it via the same UI. */
|
|
1781
|
+
.filter-search::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
|
|
1782
|
+
|
|
1772
1783
|
.clear-filter{background:var(--surface);border:1px solid var(--border);color:var(--text-muted);padding:6px 14px;border-radius:var(--radius);cursor:pointer;font-size:12px;font-weight:500;font-family:inherit;display:none;align-items:center;gap:5px;flex-shrink:0;transition:all .2s}
|
|
1773
1784
|
.clear-filter:hover{background:var(--surface-raised);border-color:var(--text-dim);color:var(--text)}
|
|
1774
1785
|
.clear-filter.visible{display:flex}
|
|
@@ -2131,6 +2142,10 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2131
2142
|
<div class="test-bar">${testBarHtml}</div>
|
|
2132
2143
|
<div class="summary-stats">
|
|
2133
2144
|
<div class="stat-pills">${statPillsHtml}</div>
|
|
2145
|
+
<label class="filter-search-wrap" title="Search test titles">
|
|
2146
|
+
<svg class="filter-search-icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
|
|
2147
|
+
<input type="search" class="filter-search" data-filter-search placeholder="Search tests…" autocomplete="off" spellcheck="false" />
|
|
2148
|
+
</label>
|
|
2134
2149
|
<div class="tag-filter-controls" data-tag-filter-controls hidden>
|
|
2135
2150
|
<div class="tag-filter-trigger-wrap">
|
|
2136
2151
|
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag or diagnosis"><span class="add-tag-plus">+</span> Filter</button>
|
|
@@ -2165,15 +2180,43 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2165
2180
|
var activeStatus=null;
|
|
2166
2181
|
var activeTags=new Set();
|
|
2167
2182
|
var activeReasons=new Set();
|
|
2183
|
+
var activeSearch=''; // lowercase substring match against data-search
|
|
2168
2184
|
var allTags=[];
|
|
2169
2185
|
var allReasons=[]; // ordered list of REASON keys present in the report
|
|
2170
2186
|
var REASON_LABELS=${JSON.stringify(REASON_LABELS)};
|
|
2171
2187
|
|
|
2172
2188
|
function cardTags(card){var raw=card.getAttribute('data-tags');if(!raw)return [];try{var v=JSON.parse(raw);return Array.isArray(v)?v:[]}catch(_){return []}}
|
|
2173
|
-
|
|
2189
|
+
|
|
2190
|
+
// Faceted-search counts. Each filter option's badge shows "how many tests
|
|
2191
|
+
// would this option contribute given the rest of the filters." The semantics
|
|
2192
|
+
// per dimension match how clicking interacts:
|
|
2193
|
+
// - Status pills (single-select replace): ignore current activeStatus.
|
|
2194
|
+
// - Tag menu items (multi-select AND): use ALL current filters.
|
|
2195
|
+
// - Reason menu items (multi-select OR): ignore current activeReasons.
|
|
2196
|
+
// Search is free-form and not counted.
|
|
2197
|
+
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons){
|
|
2198
|
+
var out=[];
|
|
2199
|
+
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2200
|
+
var statusOk=ignoreStatus||activeStatus===null||card.getAttribute('data-status')===activeStatus;
|
|
2201
|
+
var tagsOk=true;
|
|
2202
|
+
if(!ignoreTags&&activeTags.size>0){
|
|
2203
|
+
var t=cardTags(card);
|
|
2204
|
+
activeTags.forEach(function(w){if(t.indexOf(w)===-1)tagsOk=false});
|
|
2205
|
+
}
|
|
2206
|
+
var reasonOk=ignoreReasons||activeReasons.size===0||activeReasons.has(card.getAttribute('data-reason')||'');
|
|
2207
|
+
var searchOk=activeSearch.length===0||(card.getAttribute('data-search')||'').indexOf(activeSearch)!==-1;
|
|
2208
|
+
if(statusOk&&tagsOk&&reasonOk&&searchOk)out.push(card);
|
|
2209
|
+
});
|
|
2210
|
+
return out;
|
|
2211
|
+
}
|
|
2212
|
+
function tagCount(t){
|
|
2213
|
+
var pool=cardsMatching(false,false,false);
|
|
2214
|
+
var n=0;for(var i=0;i<pool.length;i++){if(cardTags(pool[i]).indexOf(t)!==-1)n++}
|
|
2215
|
+
return n;
|
|
2216
|
+
}
|
|
2174
2217
|
|
|
2175
2218
|
function applyFilters(){
|
|
2176
|
-
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0;
|
|
2219
|
+
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0;
|
|
2177
2220
|
document.querySelector('.clear-filter').classList.toggle('visible',anyActive);
|
|
2178
2221
|
var visibleTests=0;
|
|
2179
2222
|
var visibleFiles=Object.create(null);
|
|
@@ -2189,7 +2232,12 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2189
2232
|
var r=card.getAttribute('data-reason')||'';
|
|
2190
2233
|
reasonOk=activeReasons.has(r);
|
|
2191
2234
|
}
|
|
2192
|
-
var
|
|
2235
|
+
var searchOk=true;
|
|
2236
|
+
if(activeSearch.length>0){
|
|
2237
|
+
var hay=card.getAttribute('data-search')||'';
|
|
2238
|
+
searchOk=hay.indexOf(activeSearch)!==-1;
|
|
2239
|
+
}
|
|
2240
|
+
var hide=!(statusOk&&tagsOk&&reasonOk&&searchOk);
|
|
2193
2241
|
card.classList.toggle('hidden-by-filter',hide);
|
|
2194
2242
|
if(!hide){
|
|
2195
2243
|
visibleTests++;
|
|
@@ -2203,6 +2251,11 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2203
2251
|
var card=document.getElementById(block.getAttribute('data-target'));
|
|
2204
2252
|
block.classList.toggle('hidden-by-filter',!!(card&&card.classList.contains('hidden-by-filter')));
|
|
2205
2253
|
});
|
|
2254
|
+
// Faceted-search live counts: status pills, and the tag/diagnosis menu
|
|
2255
|
+
// (refreshed if currently open) all reflect "given the other filters,
|
|
2256
|
+
// how many tests would this option contribute".
|
|
2257
|
+
updateStatPillCounts();
|
|
2258
|
+
if(tagMenuOpen())openTagMenu(); // re-render menu items with fresh counts
|
|
2206
2259
|
// "X tests across Y files" subtitle reflects the current filter result.
|
|
2207
2260
|
// When no filter is active the form matches the original (no "of Y").
|
|
2208
2261
|
var sub=document.querySelector('[data-summary-sub]');
|
|
@@ -2227,6 +2280,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2227
2280
|
if(activeStatus)p.set('status',activeStatus);
|
|
2228
2281
|
activeTags.forEach(function(t){p.append('tag',t)});
|
|
2229
2282
|
activeReasons.forEach(function(r){p.append('reason',r)});
|
|
2283
|
+
if(activeSearch)p.set('q',activeSearch);
|
|
2230
2284
|
var qs=p.toString();
|
|
2231
2285
|
var next=location.pathname+(qs?'?'+qs:'')+(location.hash||'');
|
|
2232
2286
|
if(next!==location.pathname+location.search+location.hash){
|
|
@@ -2277,25 +2331,42 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2277
2331
|
function addReason(r){if(!r||activeReasons.has(r))return;activeReasons.add(r);renderActiveChips();applyFilters()}
|
|
2278
2332
|
function removeReason(r){if(!activeReasons.delete(r))return;renderActiveChips();applyFilters()}
|
|
2279
2333
|
|
|
2280
|
-
function reasonCount(r){
|
|
2334
|
+
function reasonCount(r){
|
|
2335
|
+
var pool=cardsMatching(false,false,true);
|
|
2336
|
+
var n=0;for(var i=0;i<pool.length;i++){if(pool[i].getAttribute('data-reason')===r)n++}
|
|
2337
|
+
return n;
|
|
2338
|
+
}
|
|
2339
|
+
function updateStatPillCounts(){
|
|
2340
|
+
var pool=cardsMatching(true,false,false);
|
|
2341
|
+
var counts=Object.create(null);
|
|
2342
|
+
for(var i=0;i<pool.length;i++){var s=pool[i].getAttribute('data-status');counts[s]=(counts[s]||0)+1}
|
|
2343
|
+
document.querySelectorAll('.stat-pill[data-filter]').forEach(function(pill){
|
|
2344
|
+
var key=pill.getAttribute('data-filter');
|
|
2345
|
+
var span=pill.querySelector('.pill-count');
|
|
2346
|
+
if(span)span.textContent=counts[key]||0;
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2281
2349
|
|
|
2282
2350
|
function openTagMenu(){
|
|
2283
2351
|
var menu=document.querySelector('[data-tag-menu]');
|
|
2284
2352
|
if(!menu)return;
|
|
2285
2353
|
var trigger=document.querySelector('[data-add-tag-filter]');
|
|
2286
2354
|
menu.innerHTML='';
|
|
2287
|
-
|
|
2288
|
-
|
|
2355
|
+
// For each available tag/reason, compute its preview count under the
|
|
2356
|
+
// current other filters. Options with count 0 are hidden — they'd lead
|
|
2357
|
+
// to an empty view, so they're not useful to offer.
|
|
2358
|
+
var tagsWithCounts=allTags.filter(function(t){return !activeTags.has(t)}).map(function(t){return {key:t,count:tagCount(t)}}).filter(function(x){return x.count>0});
|
|
2359
|
+
var reasonsWithCounts=allReasons.filter(function(r){return !activeReasons.has(r)}).map(function(r){return {key:r,count:reasonCount(r)}}).filter(function(x){return x.count>0});
|
|
2289
2360
|
var added=false;
|
|
2290
2361
|
if(allTags.length>0){
|
|
2291
2362
|
var hT=document.createElement('div');hT.className='tag-menu-section';hT.textContent='Tags';menu.appendChild(hT);
|
|
2292
|
-
if(
|
|
2293
|
-
var emptyT=document.createElement('div');emptyT.className='tag-menu-empty';emptyT.textContent='All tags selected';menu.appendChild(emptyT);
|
|
2363
|
+
if(tagsWithCounts.length===0){
|
|
2364
|
+
var emptyT=document.createElement('div');emptyT.className='tag-menu-empty';emptyT.textContent=allTags.length===activeTags.size?'All tags selected':'No matching tags';menu.appendChild(emptyT);
|
|
2294
2365
|
}else{
|
|
2295
|
-
|
|
2296
|
-
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-tag-menu-item',
|
|
2297
|
-
var label=document.createElement('span');label.textContent=
|
|
2298
|
-
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=
|
|
2366
|
+
tagsWithCounts.forEach(function(x){
|
|
2367
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-tag-menu-item',x.key);
|
|
2368
|
+
var label=document.createElement('span');label.textContent=x.key;
|
|
2369
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2299
2370
|
item.appendChild(label);item.appendChild(count);
|
|
2300
2371
|
menu.appendChild(item);
|
|
2301
2372
|
});
|
|
@@ -2304,14 +2375,14 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2304
2375
|
}
|
|
2305
2376
|
if(allReasons.length>0){
|
|
2306
2377
|
var hR=document.createElement('div');hR.className='tag-menu-section';hR.textContent='Diagnoses';menu.appendChild(hR);
|
|
2307
|
-
if(
|
|
2308
|
-
var emptyR=document.createElement('div');emptyR.className='tag-menu-empty';emptyR.textContent='All diagnoses selected';menu.appendChild(emptyR);
|
|
2378
|
+
if(reasonsWithCounts.length===0){
|
|
2379
|
+
var emptyR=document.createElement('div');emptyR.className='tag-menu-empty';emptyR.textContent=allReasons.length===activeReasons.size?'All diagnoses selected':'No matching diagnoses';menu.appendChild(emptyR);
|
|
2309
2380
|
}else{
|
|
2310
|
-
|
|
2311
|
-
var meta=REASON_LABELS[
|
|
2312
|
-
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-reason-menu-item',
|
|
2381
|
+
reasonsWithCounts.forEach(function(x){
|
|
2382
|
+
var meta=REASON_LABELS[x.key]||REASON_LABELS['UNKNOWN'];
|
|
2383
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-reason-menu-item',x.key);
|
|
2313
2384
|
var label=document.createElement('span');label.textContent=meta.label;label.style.color=meta.color;
|
|
2314
|
-
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=
|
|
2385
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2315
2386
|
item.appendChild(label);item.appendChild(count);
|
|
2316
2387
|
menu.appendChild(item);
|
|
2317
2388
|
});
|
|
@@ -2335,7 +2406,10 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2335
2406
|
activeStatus=null;
|
|
2336
2407
|
activeTags.clear();
|
|
2337
2408
|
activeReasons.clear();
|
|
2409
|
+
activeSearch='';
|
|
2338
2410
|
document.querySelectorAll('.stat-pill').forEach(function(p){p.classList.remove('active')});
|
|
2411
|
+
var searchInput=document.querySelector('[data-filter-search]');
|
|
2412
|
+
if(searchInput)searchInput.value='';
|
|
2339
2413
|
renderActiveChips();
|
|
2340
2414
|
closeTagMenu();
|
|
2341
2415
|
applyFilters();
|
|
@@ -2463,8 +2537,20 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2463
2537
|
p.getAll('tag').forEach(function(t){if(tagSet[t])activeTags.add(t)});
|
|
2464
2538
|
var reasonSet={};allReasons.forEach(function(r){reasonSet[r]=true});
|
|
2465
2539
|
p.getAll('reason').forEach(function(r){if(reasonSet[r])activeReasons.add(r)});
|
|
2540
|
+
var q=p.get('q');
|
|
2541
|
+
var searchInput=document.querySelector('[data-filter-search]');
|
|
2542
|
+
if(q){
|
|
2543
|
+
activeSearch=q.toLowerCase();
|
|
2544
|
+
if(searchInput)searchInput.value=q;
|
|
2545
|
+
}
|
|
2546
|
+
if(searchInput){
|
|
2547
|
+
searchInput.addEventListener('input',function(){
|
|
2548
|
+
activeSearch=searchInput.value.trim().toLowerCase();
|
|
2549
|
+
applyFilters();
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2466
2552
|
if(activeTags.size>0||activeReasons.size>0)renderActiveChips();
|
|
2467
|
-
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0)applyFilters();
|
|
2553
|
+
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0)applyFilters();
|
|
2468
2554
|
})();
|
|
2469
2555
|
|
|
2470
2556
|
// Open #?testId=<id> deep links to the matching test card. Used by the
|
package/dist/reporter/render.js
CHANGED
|
@@ -1678,7 +1678,7 @@ function renderHtml(report, triage, outputDir) {
|
|
|
1678
1678
|
? `<div class="flow-id-detail"><span class="detail-label">Flow ID</span><span class="flow-id-value">${esc(test.flowId)}<button class="copy-flow-id" data-flow-id="${esc(test.flowId)}" title="Copy flow ID"><svg viewBox="0 0 24 24"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></button></span></div>`
|
|
1679
1679
|
: '';
|
|
1680
1680
|
testSectionsHtml += `
|
|
1681
|
-
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1681
|
+
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-search="${esc((displayFileName + ' ' + test.specTitle).toLowerCase())}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1682
1682
|
<div class="test-summary">
|
|
1683
1683
|
${chevron}
|
|
1684
1684
|
<span class="status-dot" style="background:${sc.color}" title="${sc.label}"></span>
|
|
@@ -1769,6 +1769,17 @@ body::before{content:'';position:fixed;top:-750px;left:50%;transform:translateX(
|
|
|
1769
1769
|
.stat-pill.active{background:var(--accent);border-color:var(--accent);color:#fff}
|
|
1770
1770
|
.stat-pill.active .pill-count{background:rgba(255,255,255,.25);color:#fff}
|
|
1771
1771
|
.pill-count{font-size:11px;font-weight:700;background:var(--overlay-light-active);color:var(--text-dim);padding:1px 7px;border-radius:calc(var(--radius) - 2px);min-width:20px;text-align:center;transition:all .2s}
|
|
1772
|
+
/* Substring search across test filename + spec title. Lives in the same row
|
|
1773
|
+
* as the stat pills and tag/diagnosis filter. */
|
|
1774
|
+
.filter-search-wrap{position:relative;display:inline-flex;align-items:center;flex-shrink:0}
|
|
1775
|
+
.filter-search-icon{position:absolute;left:8px;width:14px;height:14px;color:var(--text-muted);fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;pointer-events:none}
|
|
1776
|
+
.filter-search{background:var(--surface);border:1px solid var(--border);color:var(--text);font:inherit;font-size:12px;height:28px;padding:0 10px 0 28px;border-radius:var(--radius);width:200px;outline:none;transition:border-color .15s,background .15s}
|
|
1777
|
+
.filter-search::placeholder{color:var(--text-dim)}
|
|
1778
|
+
.filter-search:hover{border-color:var(--text-dim)}
|
|
1779
|
+
.filter-search:focus{border-color:var(--accent);background:var(--surface-raised)}
|
|
1780
|
+
/* Hide the WebKit search clear "x" — Clear Filters wipes it via the same UI. */
|
|
1781
|
+
.filter-search::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
|
|
1782
|
+
|
|
1772
1783
|
.clear-filter{background:var(--surface);border:1px solid var(--border);color:var(--text-muted);padding:6px 14px;border-radius:var(--radius);cursor:pointer;font-size:12px;font-weight:500;font-family:inherit;display:none;align-items:center;gap:5px;flex-shrink:0;transition:all .2s}
|
|
1773
1784
|
.clear-filter:hover{background:var(--surface-raised);border-color:var(--text-dim);color:var(--text)}
|
|
1774
1785
|
.clear-filter.visible{display:flex}
|
|
@@ -2131,6 +2142,10 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2131
2142
|
<div class="test-bar">${testBarHtml}</div>
|
|
2132
2143
|
<div class="summary-stats">
|
|
2133
2144
|
<div class="stat-pills">${statPillsHtml}</div>
|
|
2145
|
+
<label class="filter-search-wrap" title="Search test titles">
|
|
2146
|
+
<svg class="filter-search-icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
|
|
2147
|
+
<input type="search" class="filter-search" data-filter-search placeholder="Search tests…" autocomplete="off" spellcheck="false" />
|
|
2148
|
+
</label>
|
|
2134
2149
|
<div class="tag-filter-controls" data-tag-filter-controls hidden>
|
|
2135
2150
|
<div class="tag-filter-trigger-wrap">
|
|
2136
2151
|
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag or diagnosis"><span class="add-tag-plus">+</span> Filter</button>
|
|
@@ -2165,15 +2180,43 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2165
2180
|
var activeStatus=null;
|
|
2166
2181
|
var activeTags=new Set();
|
|
2167
2182
|
var activeReasons=new Set();
|
|
2183
|
+
var activeSearch=''; // lowercase substring match against data-search
|
|
2168
2184
|
var allTags=[];
|
|
2169
2185
|
var allReasons=[]; // ordered list of REASON keys present in the report
|
|
2170
2186
|
var REASON_LABELS=${JSON.stringify(REASON_LABELS)};
|
|
2171
2187
|
|
|
2172
2188
|
function cardTags(card){var raw=card.getAttribute('data-tags');if(!raw)return [];try{var v=JSON.parse(raw);return Array.isArray(v)?v:[]}catch(_){return []}}
|
|
2173
|
-
|
|
2189
|
+
|
|
2190
|
+
// Faceted-search counts. Each filter option's badge shows "how many tests
|
|
2191
|
+
// would this option contribute given the rest of the filters." The semantics
|
|
2192
|
+
// per dimension match how clicking interacts:
|
|
2193
|
+
// - Status pills (single-select replace): ignore current activeStatus.
|
|
2194
|
+
// - Tag menu items (multi-select AND): use ALL current filters.
|
|
2195
|
+
// - Reason menu items (multi-select OR): ignore current activeReasons.
|
|
2196
|
+
// Search is free-form and not counted.
|
|
2197
|
+
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons){
|
|
2198
|
+
var out=[];
|
|
2199
|
+
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2200
|
+
var statusOk=ignoreStatus||activeStatus===null||card.getAttribute('data-status')===activeStatus;
|
|
2201
|
+
var tagsOk=true;
|
|
2202
|
+
if(!ignoreTags&&activeTags.size>0){
|
|
2203
|
+
var t=cardTags(card);
|
|
2204
|
+
activeTags.forEach(function(w){if(t.indexOf(w)===-1)tagsOk=false});
|
|
2205
|
+
}
|
|
2206
|
+
var reasonOk=ignoreReasons||activeReasons.size===0||activeReasons.has(card.getAttribute('data-reason')||'');
|
|
2207
|
+
var searchOk=activeSearch.length===0||(card.getAttribute('data-search')||'').indexOf(activeSearch)!==-1;
|
|
2208
|
+
if(statusOk&&tagsOk&&reasonOk&&searchOk)out.push(card);
|
|
2209
|
+
});
|
|
2210
|
+
return out;
|
|
2211
|
+
}
|
|
2212
|
+
function tagCount(t){
|
|
2213
|
+
var pool=cardsMatching(false,false,false);
|
|
2214
|
+
var n=0;for(var i=0;i<pool.length;i++){if(cardTags(pool[i]).indexOf(t)!==-1)n++}
|
|
2215
|
+
return n;
|
|
2216
|
+
}
|
|
2174
2217
|
|
|
2175
2218
|
function applyFilters(){
|
|
2176
|
-
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0;
|
|
2219
|
+
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0;
|
|
2177
2220
|
document.querySelector('.clear-filter').classList.toggle('visible',anyActive);
|
|
2178
2221
|
var visibleTests=0;
|
|
2179
2222
|
var visibleFiles=Object.create(null);
|
|
@@ -2189,7 +2232,12 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2189
2232
|
var r=card.getAttribute('data-reason')||'';
|
|
2190
2233
|
reasonOk=activeReasons.has(r);
|
|
2191
2234
|
}
|
|
2192
|
-
var
|
|
2235
|
+
var searchOk=true;
|
|
2236
|
+
if(activeSearch.length>0){
|
|
2237
|
+
var hay=card.getAttribute('data-search')||'';
|
|
2238
|
+
searchOk=hay.indexOf(activeSearch)!==-1;
|
|
2239
|
+
}
|
|
2240
|
+
var hide=!(statusOk&&tagsOk&&reasonOk&&searchOk);
|
|
2193
2241
|
card.classList.toggle('hidden-by-filter',hide);
|
|
2194
2242
|
if(!hide){
|
|
2195
2243
|
visibleTests++;
|
|
@@ -2203,6 +2251,11 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2203
2251
|
var card=document.getElementById(block.getAttribute('data-target'));
|
|
2204
2252
|
block.classList.toggle('hidden-by-filter',!!(card&&card.classList.contains('hidden-by-filter')));
|
|
2205
2253
|
});
|
|
2254
|
+
// Faceted-search live counts: status pills, and the tag/diagnosis menu
|
|
2255
|
+
// (refreshed if currently open) all reflect "given the other filters,
|
|
2256
|
+
// how many tests would this option contribute".
|
|
2257
|
+
updateStatPillCounts();
|
|
2258
|
+
if(tagMenuOpen())openTagMenu(); // re-render menu items with fresh counts
|
|
2206
2259
|
// "X tests across Y files" subtitle reflects the current filter result.
|
|
2207
2260
|
// When no filter is active the form matches the original (no "of Y").
|
|
2208
2261
|
var sub=document.querySelector('[data-summary-sub]');
|
|
@@ -2227,6 +2280,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2227
2280
|
if(activeStatus)p.set('status',activeStatus);
|
|
2228
2281
|
activeTags.forEach(function(t){p.append('tag',t)});
|
|
2229
2282
|
activeReasons.forEach(function(r){p.append('reason',r)});
|
|
2283
|
+
if(activeSearch)p.set('q',activeSearch);
|
|
2230
2284
|
var qs=p.toString();
|
|
2231
2285
|
var next=location.pathname+(qs?'?'+qs:'')+(location.hash||'');
|
|
2232
2286
|
if(next!==location.pathname+location.search+location.hash){
|
|
@@ -2277,25 +2331,42 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2277
2331
|
function addReason(r){if(!r||activeReasons.has(r))return;activeReasons.add(r);renderActiveChips();applyFilters()}
|
|
2278
2332
|
function removeReason(r){if(!activeReasons.delete(r))return;renderActiveChips();applyFilters()}
|
|
2279
2333
|
|
|
2280
|
-
function reasonCount(r){
|
|
2334
|
+
function reasonCount(r){
|
|
2335
|
+
var pool=cardsMatching(false,false,true);
|
|
2336
|
+
var n=0;for(var i=0;i<pool.length;i++){if(pool[i].getAttribute('data-reason')===r)n++}
|
|
2337
|
+
return n;
|
|
2338
|
+
}
|
|
2339
|
+
function updateStatPillCounts(){
|
|
2340
|
+
var pool=cardsMatching(true,false,false);
|
|
2341
|
+
var counts=Object.create(null);
|
|
2342
|
+
for(var i=0;i<pool.length;i++){var s=pool[i].getAttribute('data-status');counts[s]=(counts[s]||0)+1}
|
|
2343
|
+
document.querySelectorAll('.stat-pill[data-filter]').forEach(function(pill){
|
|
2344
|
+
var key=pill.getAttribute('data-filter');
|
|
2345
|
+
var span=pill.querySelector('.pill-count');
|
|
2346
|
+
if(span)span.textContent=counts[key]||0;
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2281
2349
|
|
|
2282
2350
|
function openTagMenu(){
|
|
2283
2351
|
var menu=document.querySelector('[data-tag-menu]');
|
|
2284
2352
|
if(!menu)return;
|
|
2285
2353
|
var trigger=document.querySelector('[data-add-tag-filter]');
|
|
2286
2354
|
menu.innerHTML='';
|
|
2287
|
-
|
|
2288
|
-
|
|
2355
|
+
// For each available tag/reason, compute its preview count under the
|
|
2356
|
+
// current other filters. Options with count 0 are hidden — they'd lead
|
|
2357
|
+
// to an empty view, so they're not useful to offer.
|
|
2358
|
+
var tagsWithCounts=allTags.filter(function(t){return !activeTags.has(t)}).map(function(t){return {key:t,count:tagCount(t)}}).filter(function(x){return x.count>0});
|
|
2359
|
+
var reasonsWithCounts=allReasons.filter(function(r){return !activeReasons.has(r)}).map(function(r){return {key:r,count:reasonCount(r)}}).filter(function(x){return x.count>0});
|
|
2289
2360
|
var added=false;
|
|
2290
2361
|
if(allTags.length>0){
|
|
2291
2362
|
var hT=document.createElement('div');hT.className='tag-menu-section';hT.textContent='Tags';menu.appendChild(hT);
|
|
2292
|
-
if(
|
|
2293
|
-
var emptyT=document.createElement('div');emptyT.className='tag-menu-empty';emptyT.textContent='All tags selected';menu.appendChild(emptyT);
|
|
2363
|
+
if(tagsWithCounts.length===0){
|
|
2364
|
+
var emptyT=document.createElement('div');emptyT.className='tag-menu-empty';emptyT.textContent=allTags.length===activeTags.size?'All tags selected':'No matching tags';menu.appendChild(emptyT);
|
|
2294
2365
|
}else{
|
|
2295
|
-
|
|
2296
|
-
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-tag-menu-item',
|
|
2297
|
-
var label=document.createElement('span');label.textContent=
|
|
2298
|
-
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=
|
|
2366
|
+
tagsWithCounts.forEach(function(x){
|
|
2367
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-tag-menu-item',x.key);
|
|
2368
|
+
var label=document.createElement('span');label.textContent=x.key;
|
|
2369
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2299
2370
|
item.appendChild(label);item.appendChild(count);
|
|
2300
2371
|
menu.appendChild(item);
|
|
2301
2372
|
});
|
|
@@ -2304,14 +2375,14 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2304
2375
|
}
|
|
2305
2376
|
if(allReasons.length>0){
|
|
2306
2377
|
var hR=document.createElement('div');hR.className='tag-menu-section';hR.textContent='Diagnoses';menu.appendChild(hR);
|
|
2307
|
-
if(
|
|
2308
|
-
var emptyR=document.createElement('div');emptyR.className='tag-menu-empty';emptyR.textContent='All diagnoses selected';menu.appendChild(emptyR);
|
|
2378
|
+
if(reasonsWithCounts.length===0){
|
|
2379
|
+
var emptyR=document.createElement('div');emptyR.className='tag-menu-empty';emptyR.textContent=allReasons.length===activeReasons.size?'All diagnoses selected':'No matching diagnoses';menu.appendChild(emptyR);
|
|
2309
2380
|
}else{
|
|
2310
|
-
|
|
2311
|
-
var meta=REASON_LABELS[
|
|
2312
|
-
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-reason-menu-item',
|
|
2381
|
+
reasonsWithCounts.forEach(function(x){
|
|
2382
|
+
var meta=REASON_LABELS[x.key]||REASON_LABELS['UNKNOWN'];
|
|
2383
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-reason-menu-item',x.key);
|
|
2313
2384
|
var label=document.createElement('span');label.textContent=meta.label;label.style.color=meta.color;
|
|
2314
|
-
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=
|
|
2385
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2315
2386
|
item.appendChild(label);item.appendChild(count);
|
|
2316
2387
|
menu.appendChild(item);
|
|
2317
2388
|
});
|
|
@@ -2335,7 +2406,10 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2335
2406
|
activeStatus=null;
|
|
2336
2407
|
activeTags.clear();
|
|
2337
2408
|
activeReasons.clear();
|
|
2409
|
+
activeSearch='';
|
|
2338
2410
|
document.querySelectorAll('.stat-pill').forEach(function(p){p.classList.remove('active')});
|
|
2411
|
+
var searchInput=document.querySelector('[data-filter-search]');
|
|
2412
|
+
if(searchInput)searchInput.value='';
|
|
2339
2413
|
renderActiveChips();
|
|
2340
2414
|
closeTagMenu();
|
|
2341
2415
|
applyFilters();
|
|
@@ -2463,8 +2537,20 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2463
2537
|
p.getAll('tag').forEach(function(t){if(tagSet[t])activeTags.add(t)});
|
|
2464
2538
|
var reasonSet={};allReasons.forEach(function(r){reasonSet[r]=true});
|
|
2465
2539
|
p.getAll('reason').forEach(function(r){if(reasonSet[r])activeReasons.add(r)});
|
|
2540
|
+
var q=p.get('q');
|
|
2541
|
+
var searchInput=document.querySelector('[data-filter-search]');
|
|
2542
|
+
if(q){
|
|
2543
|
+
activeSearch=q.toLowerCase();
|
|
2544
|
+
if(searchInput)searchInput.value=q;
|
|
2545
|
+
}
|
|
2546
|
+
if(searchInput){
|
|
2547
|
+
searchInput.addEventListener('input',function(){
|
|
2548
|
+
activeSearch=searchInput.value.trim().toLowerCase();
|
|
2549
|
+
applyFilters();
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2466
2552
|
if(activeTags.size>0||activeReasons.size>0)renderActiveChips();
|
|
2467
|
-
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0)applyFilters();
|
|
2553
|
+
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0)applyFilters();
|
|
2468
2554
|
})();
|
|
2469
2555
|
|
|
2470
2556
|
// Open #?testId=<id> deep links to the matching test card. Used by the
|