donobu 5.47.0 → 5.48.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 +108 -15
- package/dist/reporter/render.js +108 -15
- package/package.json +1 -1
|
@@ -449,6 +449,33 @@ const REASON_LABELS = {
|
|
|
449
449
|
function reasonCfg(reason) {
|
|
450
450
|
return REASON_LABELS[reason] ?? REASON_LABELS['UNKNOWN'];
|
|
451
451
|
}
|
|
452
|
+
// Triage-detail flags derived from a treatment plan. A test can carry several
|
|
453
|
+
// at once, so these form a multi-valued filter dimension (OR semantics).
|
|
454
|
+
// Declaration order is the display order in the filter menu and chips, and
|
|
455
|
+
// mirrors the flag order in `renderTriageCard`. Colors match `.triage-flag`.
|
|
456
|
+
const TRIAGE_LABELS = {
|
|
457
|
+
retryable: { label: 'Retryable', color: '#10b981' },
|
|
458
|
+
code: { label: 'Needs Code Change', color: '#f59e0b' },
|
|
459
|
+
product: { label: 'Needs Product Fix', color: '#ef4444' },
|
|
460
|
+
};
|
|
461
|
+
/** The triage-flag keys present on a test's treatment plan, in display order. */
|
|
462
|
+
function triageKeysOf(test) {
|
|
463
|
+
if (!test.plan) {
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
const p = test.plan.plan;
|
|
467
|
+
const keys = [];
|
|
468
|
+
if (p.shouldRetryAutomation) {
|
|
469
|
+
keys.push('retryable');
|
|
470
|
+
}
|
|
471
|
+
if (p.requiresCodeChange) {
|
|
472
|
+
keys.push('code');
|
|
473
|
+
}
|
|
474
|
+
if (p.requiresProductFix) {
|
|
475
|
+
keys.push('product');
|
|
476
|
+
}
|
|
477
|
+
return keys;
|
|
478
|
+
}
|
|
452
479
|
function renderAttachments(attachments, outputDir, stepScreenshots = []) {
|
|
453
480
|
const rendered = [];
|
|
454
481
|
for (const att of attachments) {
|
|
@@ -1680,7 +1707,7 @@ function renderHtml(report, triage, outputDir) {
|
|
|
1680
1707
|
? `<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>`
|
|
1681
1708
|
: '';
|
|
1682
1709
|
testSectionsHtml += `
|
|
1683
|
-
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-search="${esc((displayFilePath + ' ' + test.specTitle).toLowerCase())}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1710
|
+
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-search="${esc((displayFilePath + ' ' + test.specTitle).toLowerCase())}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''}${triageKeysOf(test).length ? ` data-triage="${esc(triageKeysOf(test).join(','))}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1684
1711
|
<div class="test-summary">
|
|
1685
1712
|
${chevron}
|
|
1686
1713
|
<span class="status-dot" style="background:${sc.color}" title="${sc.label}"></span>
|
|
@@ -1801,14 +1828,15 @@ body::before{content:'';position:fixed;top:-750px;left:50%;transform:translateX(
|
|
|
1801
1828
|
.add-tag-filter .add-tag-plus{font-size:15px;line-height:1}
|
|
1802
1829
|
.add-tag-filter:hover{background:var(--surface-raised);border-color:var(--text-dim);color:var(--text)}
|
|
1803
1830
|
.add-tag-filter.active{background:var(--accent);border-color:var(--accent);color:#fff}
|
|
1804
|
-
.tag-menu{position:absolute;top:calc(100% + 6px);
|
|
1831
|
+
.tag-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:200px;max-width:320px;max-height:280px;overflow-y:auto;background:var(--surface-raised);border:1px solid var(--border);border-radius:var(--radius);box-shadow:0 8px 24px rgba(0,0,0,.4);z-index:20;padding:4px;display:none}
|
|
1805
1832
|
.tag-menu:not([hidden]){display:block}
|
|
1806
1833
|
.tag-menu-item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 10px;font-size:12px;font-family:var(--mono);color:var(--text);background:transparent;border:none;border-radius:4px;cursor:pointer;text-align:left;width:100%;transition:background .15s}
|
|
1807
1834
|
.tag-menu-item:hover{background:var(--surface)}
|
|
1808
1835
|
.tag-menu-item .tag-menu-count{color:var(--text-muted);font-size:11px;font-family:var(--mono)}
|
|
1809
1836
|
.tag-menu-empty{padding:8px 10px;font-size:12px;color:var(--text-muted);font-style:italic}
|
|
1810
|
-
.tag-menu-section{padding:8px 10px
|
|
1837
|
+
.tag-menu-section{padding:8px 10px 2px;font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--text-dim);font-family:inherit}
|
|
1811
1838
|
.tag-menu-section:not(:first-child){margin-top:4px;border-top:1px solid var(--border)}
|
|
1839
|
+
.tag-menu-hint{padding:0 10px 6px;font-size:11px;line-height:1.35;color:var(--text-muted);font-family:inherit;max-width:300px}
|
|
1812
1840
|
.active-tag-filters{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
|
|
1813
1841
|
.tag-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(255,127,58,.12);border:1px solid rgba(255,127,58,.3);color:var(--accent);font-size:11px;font-family:var(--mono);padding:3px 4px 3px 8px;border-radius:4px}
|
|
1814
1842
|
.tag-chip-remove{background:transparent;border:none;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:0 4px;font-family:inherit;opacity:.7;transition:opacity .15s}
|
|
@@ -2163,7 +2191,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2163
2191
|
</label>
|
|
2164
2192
|
<div class="tag-filter-controls" data-tag-filter-controls hidden>
|
|
2165
2193
|
<div class="tag-filter-trigger-wrap">
|
|
2166
|
-
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag or
|
|
2194
|
+
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag, diagnosis, or triage"><span class="add-tag-plus">+</span> Filter</button>
|
|
2167
2195
|
<div class="tag-menu" data-tag-menu hidden></div>
|
|
2168
2196
|
</div>
|
|
2169
2197
|
<div class="active-tag-filters" data-active-tag-filters></div>
|
|
@@ -2191,16 +2219,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2191
2219
|
// tags — multi-select AND; card must carry every active tag.
|
|
2192
2220
|
// reasons — multi-select OR; card.data-reason must match any active reason
|
|
2193
2221
|
// (a card has at most one diagnosis, so AND would always be 0/1).
|
|
2194
|
-
//
|
|
2222
|
+
// triage — multi-select OR; card.data-triage (a comma list) must contain
|
|
2223
|
+
// any active flag (a card can carry several triage flags).
|
|
2224
|
+
// "Clear Filters" wipes all of them.
|
|
2195
2225
|
var activeStatus=null;
|
|
2196
2226
|
var activeTags=new Set();
|
|
2197
2227
|
var activeReasons=new Set();
|
|
2228
|
+
var activeTriage=new Set();
|
|
2198
2229
|
var activeSearch=''; // lowercase substring match against data-search
|
|
2199
2230
|
var allTags=[];
|
|
2200
2231
|
var allReasons=[]; // ordered list of REASON keys present in the report
|
|
2232
|
+
var allTriage=[]; // ordered list of TRIAGE keys present in the report
|
|
2201
2233
|
var REASON_LABELS=${JSON.stringify(REASON_LABELS)};
|
|
2234
|
+
var TRIAGE_LABELS=${JSON.stringify(TRIAGE_LABELS)};
|
|
2202
2235
|
|
|
2203
2236
|
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 []}}
|
|
2237
|
+
function cardTriage(card){var raw=card.getAttribute('data-triage');return raw?raw.split(','):[]}
|
|
2204
2238
|
|
|
2205
2239
|
// Faceted-search counts. Each filter option's badge shows "how many tests
|
|
2206
2240
|
// would this option contribute given the rest of the filters." The semantics
|
|
@@ -2208,8 +2242,9 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2208
2242
|
// - Status pills (single-select replace): ignore current activeStatus.
|
|
2209
2243
|
// - Tag menu items (multi-select AND): use ALL current filters.
|
|
2210
2244
|
// - Reason menu items (multi-select OR): ignore current activeReasons.
|
|
2245
|
+
// - Triage menu items (multi-select OR): ignore current activeTriage.
|
|
2211
2246
|
// Search is free-form and not counted.
|
|
2212
|
-
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons){
|
|
2247
|
+
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons,ignoreTriage){
|
|
2213
2248
|
var out=[];
|
|
2214
2249
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2215
2250
|
var statusOk=ignoreStatus||activeStatus===null||card.getAttribute('data-status')===activeStatus;
|
|
@@ -2219,19 +2254,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2219
2254
|
activeTags.forEach(function(w){if(t.indexOf(w)===-1)tagsOk=false});
|
|
2220
2255
|
}
|
|
2221
2256
|
var reasonOk=ignoreReasons||activeReasons.size===0||activeReasons.has(card.getAttribute('data-reason')||'');
|
|
2257
|
+
var triageOk=true;
|
|
2258
|
+
if(!ignoreTriage&&activeTriage.size>0){
|
|
2259
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2260
|
+
}
|
|
2222
2261
|
var searchOk=activeSearch.length===0||(card.getAttribute('data-search')||'').indexOf(activeSearch)!==-1;
|
|
2223
|
-
if(statusOk&&tagsOk&&reasonOk&&searchOk)out.push(card);
|
|
2262
|
+
if(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk)out.push(card);
|
|
2224
2263
|
});
|
|
2225
2264
|
return out;
|
|
2226
2265
|
}
|
|
2227
2266
|
function tagCount(t){
|
|
2228
|
-
var pool=cardsMatching(false,false,false);
|
|
2267
|
+
var pool=cardsMatching(false,false,false,false);
|
|
2229
2268
|
var n=0;for(var i=0;i<pool.length;i++){if(cardTags(pool[i]).indexOf(t)!==-1)n++}
|
|
2230
2269
|
return n;
|
|
2231
2270
|
}
|
|
2232
2271
|
|
|
2233
2272
|
function applyFilters(){
|
|
2234
|
-
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0;
|
|
2273
|
+
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0;
|
|
2235
2274
|
document.querySelector('.clear-filter').classList.toggle('visible',anyActive);
|
|
2236
2275
|
var visibleTests=0;
|
|
2237
2276
|
var visibleFiles=Object.create(null);
|
|
@@ -2247,12 +2286,16 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2247
2286
|
var r=card.getAttribute('data-reason')||'';
|
|
2248
2287
|
reasonOk=activeReasons.has(r);
|
|
2249
2288
|
}
|
|
2289
|
+
var triageOk=true;
|
|
2290
|
+
if(activeTriage.size>0){
|
|
2291
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2292
|
+
}
|
|
2250
2293
|
var searchOk=true;
|
|
2251
2294
|
if(activeSearch.length>0){
|
|
2252
2295
|
var hay=card.getAttribute('data-search')||'';
|
|
2253
2296
|
searchOk=hay.indexOf(activeSearch)!==-1;
|
|
2254
2297
|
}
|
|
2255
|
-
var hide=!(statusOk&&tagsOk&&reasonOk&&searchOk);
|
|
2298
|
+
var hide=!(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk);
|
|
2256
2299
|
card.classList.toggle('hidden-by-filter',hide);
|
|
2257
2300
|
if(!hide){
|
|
2258
2301
|
visibleTests++;
|
|
@@ -2295,6 +2338,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2295
2338
|
if(activeStatus)p.set('status',activeStatus);
|
|
2296
2339
|
activeTags.forEach(function(t){p.append('tag',t)});
|
|
2297
2340
|
activeReasons.forEach(function(r){p.append('reason',r)});
|
|
2341
|
+
activeTriage.forEach(function(t){p.append('triage',t)});
|
|
2298
2342
|
if(activeSearch)p.set('q',activeSearch);
|
|
2299
2343
|
var qs=p.toString();
|
|
2300
2344
|
var next=location.pathname+(qs?'?'+qs:'')+(location.hash||'');
|
|
@@ -2340,19 +2384,37 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2340
2384
|
chip.appendChild(label);chip.appendChild(btn);
|
|
2341
2385
|
c.appendChild(chip);
|
|
2342
2386
|
});
|
|
2387
|
+
activeTriage.forEach(function(t){
|
|
2388
|
+
var meta=TRIAGE_LABELS[t];if(!meta)return;
|
|
2389
|
+
var chip=document.createElement('span');chip.className='tag-chip reason-chip';
|
|
2390
|
+
chip.style.background=hexToRgba(meta.color,0.14);
|
|
2391
|
+
chip.style.borderColor=hexToRgba(meta.color,0.4);
|
|
2392
|
+
chip.style.color=meta.color;
|
|
2393
|
+
var label=document.createElement('span');label.textContent=meta.label;
|
|
2394
|
+
var btn=document.createElement('button');btn.className='tag-chip-remove';btn.setAttribute('data-remove-triage',t);btn.setAttribute('title','Remove filter');btn.textContent='×';
|
|
2395
|
+
chip.appendChild(label);chip.appendChild(btn);
|
|
2396
|
+
c.appendChild(chip);
|
|
2397
|
+
});
|
|
2343
2398
|
}
|
|
2344
2399
|
function addTag(t){if(!t||activeTags.has(t))return;activeTags.add(t);renderActiveChips();applyFilters()}
|
|
2345
2400
|
function removeTag(t){if(!activeTags.delete(t))return;renderActiveChips();applyFilters()}
|
|
2346
2401
|
function addReason(r){if(!r||activeReasons.has(r))return;activeReasons.add(r);renderActiveChips();applyFilters()}
|
|
2347
2402
|
function removeReason(r){if(!activeReasons.delete(r))return;renderActiveChips();applyFilters()}
|
|
2403
|
+
function addTriage(t){if(!t||activeTriage.has(t))return;activeTriage.add(t);renderActiveChips();applyFilters()}
|
|
2404
|
+
function removeTriage(t){if(!activeTriage.delete(t))return;renderActiveChips();applyFilters()}
|
|
2348
2405
|
|
|
2349
2406
|
function reasonCount(r){
|
|
2350
|
-
var pool=cardsMatching(false,false,true);
|
|
2407
|
+
var pool=cardsMatching(false,false,true,false);
|
|
2351
2408
|
var n=0;for(var i=0;i<pool.length;i++){if(pool[i].getAttribute('data-reason')===r)n++}
|
|
2352
2409
|
return n;
|
|
2353
2410
|
}
|
|
2411
|
+
function triageCount(t){
|
|
2412
|
+
var pool=cardsMatching(false,false,false,true);
|
|
2413
|
+
var n=0;for(var i=0;i<pool.length;i++){if(cardTriage(pool[i]).indexOf(t)!==-1)n++}
|
|
2414
|
+
return n;
|
|
2415
|
+
}
|
|
2354
2416
|
function updateStatPillCounts(){
|
|
2355
|
-
var pool=cardsMatching(true,false,false);
|
|
2417
|
+
var pool=cardsMatching(true,false,false,false);
|
|
2356
2418
|
var counts=Object.create(null);
|
|
2357
2419
|
for(var i=0;i<pool.length;i++){var s=pool[i].getAttribute('data-status');counts[s]=(counts[s]||0)+1}
|
|
2358
2420
|
document.querySelectorAll('.stat-pill[data-filter]').forEach(function(pill){
|
|
@@ -2372,9 +2434,11 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2372
2434
|
// to an empty view, so they're not useful to offer.
|
|
2373
2435
|
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});
|
|
2374
2436
|
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});
|
|
2437
|
+
var triageWithCounts=allTriage.filter(function(t){return !activeTriage.has(t)}).map(function(t){return {key:t,count:triageCount(t)}}).filter(function(x){return x.count>0});
|
|
2375
2438
|
var added=false;
|
|
2376
2439
|
if(allTags.length>0){
|
|
2377
2440
|
var hT=document.createElement('div');hT.className='tag-menu-section';hT.textContent='Tags';menu.appendChild(hT);
|
|
2441
|
+
var hintT=document.createElement('div');hintT.className='tag-menu-hint';hintT.textContent='Labels you put on tests in code (e.g. @smoke). Match all selected.';menu.appendChild(hintT);
|
|
2378
2442
|
if(tagsWithCounts.length===0){
|
|
2379
2443
|
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);
|
|
2380
2444
|
}else{
|
|
@@ -2390,6 +2454,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2390
2454
|
}
|
|
2391
2455
|
if(allReasons.length>0){
|
|
2392
2456
|
var hR=document.createElement('div');hR.className='tag-menu-section';hR.textContent='Diagnoses';menu.appendChild(hR);
|
|
2457
|
+
var hintR=document.createElement('div');hintR.className='tag-menu-hint';hintR.textContent='Why a test failed — the AI\\'s single root-cause assessment.';menu.appendChild(hintR);
|
|
2393
2458
|
if(reasonsWithCounts.length===0){
|
|
2394
2459
|
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);
|
|
2395
2460
|
}else{
|
|
@@ -2404,6 +2469,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2404
2469
|
}
|
|
2405
2470
|
added=true;
|
|
2406
2471
|
}
|
|
2472
|
+
if(allTriage.length>0){
|
|
2473
|
+
var hTr=document.createElement('div');hTr.className='tag-menu-section';hTr.textContent='Triage';menu.appendChild(hTr);
|
|
2474
|
+
var hintTr=document.createElement('div');hintTr.className='tag-menu-hint';hintTr.textContent='What the failure calls for — a test can need more than one.';menu.appendChild(hintTr);
|
|
2475
|
+
if(triageWithCounts.length===0){
|
|
2476
|
+
var emptyTr=document.createElement('div');emptyTr.className='tag-menu-empty';emptyTr.textContent=allTriage.length===activeTriage.size?'All triage flags selected':'No matching triage flags';menu.appendChild(emptyTr);
|
|
2477
|
+
}else{
|
|
2478
|
+
triageWithCounts.forEach(function(x){
|
|
2479
|
+
var meta=TRIAGE_LABELS[x.key];if(!meta)return;
|
|
2480
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-triage-menu-item',x.key);
|
|
2481
|
+
var label=document.createElement('span');label.textContent=meta.label;label.style.color=meta.color;
|
|
2482
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2483
|
+
item.appendChild(label);item.appendChild(count);
|
|
2484
|
+
menu.appendChild(item);
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
added=true;
|
|
2488
|
+
}
|
|
2407
2489
|
if(!added){
|
|
2408
2490
|
var empty=document.createElement('div');empty.className='tag-menu-empty';empty.textContent='No filters available';menu.appendChild(empty);
|
|
2409
2491
|
}
|
|
@@ -2421,6 +2503,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2421
2503
|
activeStatus=null;
|
|
2422
2504
|
activeTags.clear();
|
|
2423
2505
|
activeReasons.clear();
|
|
2506
|
+
activeTriage.clear();
|
|
2424
2507
|
activeSearch='';
|
|
2425
2508
|
document.querySelectorAll('.stat-pill').forEach(function(p){p.classList.remove('active')});
|
|
2426
2509
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
@@ -2470,10 +2553,14 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2470
2553
|
if(tagItem){addTag(tagItem.getAttribute('data-tag-menu-item'));closeTagMenu();return}
|
|
2471
2554
|
var reasonItem=e.target.closest('[data-reason-menu-item]');
|
|
2472
2555
|
if(reasonItem){addReason(reasonItem.getAttribute('data-reason-menu-item'));closeTagMenu();return}
|
|
2556
|
+
var triageItem=e.target.closest('[data-triage-menu-item]');
|
|
2557
|
+
if(triageItem){addTriage(triageItem.getAttribute('data-triage-menu-item'));closeTagMenu();return}
|
|
2473
2558
|
var tagRemove=e.target.closest('[data-remove-tag]');
|
|
2474
2559
|
if(tagRemove){removeTag(tagRemove.getAttribute('data-remove-tag'));return}
|
|
2475
2560
|
var reasonRemove=e.target.closest('[data-remove-reason]');
|
|
2476
2561
|
if(reasonRemove){removeReason(reasonRemove.getAttribute('data-remove-reason'));return}
|
|
2562
|
+
var triageRemove=e.target.closest('[data-remove-triage]');
|
|
2563
|
+
if(triageRemove){removeTriage(triageRemove.getAttribute('data-remove-triage'));return}
|
|
2477
2564
|
// Stat pill filter
|
|
2478
2565
|
var pill=e.target.closest('.stat-pill[data-filter]');
|
|
2479
2566
|
if(pill){toggleStatus(pill.getAttribute('data-filter'));return}
|
|
@@ -2523,18 +2610,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2523
2610
|
(function(){
|
|
2524
2611
|
var seenTags=Object.create(null);
|
|
2525
2612
|
var seenReasons=Object.create(null);
|
|
2613
|
+
var seenTriage=Object.create(null);
|
|
2526
2614
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2527
2615
|
var raw=card.getAttribute('data-tags');
|
|
2528
2616
|
if(raw){try{var tags=JSON.parse(raw);if(Array.isArray(tags)){tags.forEach(function(t){if(typeof t==='string'&&t)seenTags[t]=true})}}catch(_){}}
|
|
2529
2617
|
var r=card.getAttribute('data-reason');
|
|
2530
2618
|
if(r)seenReasons[r]=true;
|
|
2619
|
+
cardTriage(card).forEach(function(t){if(t)seenTriage[t]=true});
|
|
2531
2620
|
});
|
|
2532
2621
|
allTags=Object.keys(seenTags).sort();
|
|
2533
2622
|
// Preserve the REASON_LABELS declaration order rather than alphabetical —
|
|
2534
2623
|
// they're already arranged from most-frequent/specific to UNKNOWN catch-all.
|
|
2535
2624
|
allReasons=Object.keys(REASON_LABELS).filter(function(r){return seenReasons[r]});
|
|
2625
|
+
// Preserve TRIAGE_LABELS declaration order (retryable → code → product).
|
|
2626
|
+
allTriage=Object.keys(TRIAGE_LABELS).filter(function(t){return seenTriage[t]});
|
|
2536
2627
|
var controls=document.querySelector('[data-tag-filter-controls]');
|
|
2537
|
-
if(controls&&(allTags.length>0||allReasons.length>0))controls.hidden=false;
|
|
2628
|
+
if(controls&&(allTags.length>0||allReasons.length>0||allTriage.length>0))controls.hidden=false;
|
|
2538
2629
|
})();
|
|
2539
2630
|
|
|
2540
2631
|
// Seed filter state from ?status=...&tag=...&reason=... so shared URLs
|
|
@@ -2554,6 +2645,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2554
2645
|
p.getAll('tag').forEach(function(t){if(tagSet[t])activeTags.add(t)});
|
|
2555
2646
|
var reasonSet={};allReasons.forEach(function(r){reasonSet[r]=true});
|
|
2556
2647
|
p.getAll('reason').forEach(function(r){if(reasonSet[r])activeReasons.add(r)});
|
|
2648
|
+
var triageSet={};allTriage.forEach(function(t){triageSet[t]=true});
|
|
2649
|
+
p.getAll('triage').forEach(function(t){if(triageSet[t])activeTriage.add(t)});
|
|
2557
2650
|
var q=p.get('q');
|
|
2558
2651
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
2559
2652
|
if(q){
|
|
@@ -2566,8 +2659,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2566
2659
|
applyFilters();
|
|
2567
2660
|
});
|
|
2568
2661
|
}
|
|
2569
|
-
if(activeTags.size>0||activeReasons.size>0)renderActiveChips();
|
|
2570
|
-
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0)applyFilters();
|
|
2662
|
+
if(activeTags.size>0||activeReasons.size>0||activeTriage.size>0)renderActiveChips();
|
|
2663
|
+
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0)applyFilters();
|
|
2571
2664
|
})();
|
|
2572
2665
|
|
|
2573
2666
|
// Open #?testId=<id> deep links to the matching test card. Used by the
|
package/dist/reporter/render.js
CHANGED
|
@@ -449,6 +449,33 @@ const REASON_LABELS = {
|
|
|
449
449
|
function reasonCfg(reason) {
|
|
450
450
|
return REASON_LABELS[reason] ?? REASON_LABELS['UNKNOWN'];
|
|
451
451
|
}
|
|
452
|
+
// Triage-detail flags derived from a treatment plan. A test can carry several
|
|
453
|
+
// at once, so these form a multi-valued filter dimension (OR semantics).
|
|
454
|
+
// Declaration order is the display order in the filter menu and chips, and
|
|
455
|
+
// mirrors the flag order in `renderTriageCard`. Colors match `.triage-flag`.
|
|
456
|
+
const TRIAGE_LABELS = {
|
|
457
|
+
retryable: { label: 'Retryable', color: '#10b981' },
|
|
458
|
+
code: { label: 'Needs Code Change', color: '#f59e0b' },
|
|
459
|
+
product: { label: 'Needs Product Fix', color: '#ef4444' },
|
|
460
|
+
};
|
|
461
|
+
/** The triage-flag keys present on a test's treatment plan, in display order. */
|
|
462
|
+
function triageKeysOf(test) {
|
|
463
|
+
if (!test.plan) {
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
const p = test.plan.plan;
|
|
467
|
+
const keys = [];
|
|
468
|
+
if (p.shouldRetryAutomation) {
|
|
469
|
+
keys.push('retryable');
|
|
470
|
+
}
|
|
471
|
+
if (p.requiresCodeChange) {
|
|
472
|
+
keys.push('code');
|
|
473
|
+
}
|
|
474
|
+
if (p.requiresProductFix) {
|
|
475
|
+
keys.push('product');
|
|
476
|
+
}
|
|
477
|
+
return keys;
|
|
478
|
+
}
|
|
452
479
|
function renderAttachments(attachments, outputDir, stepScreenshots = []) {
|
|
453
480
|
const rendered = [];
|
|
454
481
|
for (const att of attachments) {
|
|
@@ -1680,7 +1707,7 @@ function renderHtml(report, triage, outputDir) {
|
|
|
1680
1707
|
? `<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>`
|
|
1681
1708
|
: '';
|
|
1682
1709
|
testSectionsHtml += `
|
|
1683
|
-
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-search="${esc((displayFilePath + ' ' + test.specTitle).toLowerCase())}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1710
|
+
<div class="test-card ${sc.label.toLowerCase().replace(/ /g, '')} ${expandableClass}" id="${testId}" data-status="${test.status}" data-file="${esc(test.file)}" data-search="${esc((displayFilePath + ' ' + test.specTitle).toLowerCase())}" data-tags="${esc(JSON.stringify(test.tags))}"${test.plan ? ` data-reason="${esc(test.plan.plan.failureReason)}"` : ''}${triageKeysOf(test).length ? ` data-triage="${esc(triageKeysOf(test).join(','))}"` : ''} ${hasDetails ? `data-detail="${testId}"` : ''}>
|
|
1684
1711
|
<div class="test-summary">
|
|
1685
1712
|
${chevron}
|
|
1686
1713
|
<span class="status-dot" style="background:${sc.color}" title="${sc.label}"></span>
|
|
@@ -1801,14 +1828,15 @@ body::before{content:'';position:fixed;top:-750px;left:50%;transform:translateX(
|
|
|
1801
1828
|
.add-tag-filter .add-tag-plus{font-size:15px;line-height:1}
|
|
1802
1829
|
.add-tag-filter:hover{background:var(--surface-raised);border-color:var(--text-dim);color:var(--text)}
|
|
1803
1830
|
.add-tag-filter.active{background:var(--accent);border-color:var(--accent);color:#fff}
|
|
1804
|
-
.tag-menu{position:absolute;top:calc(100% + 6px);
|
|
1831
|
+
.tag-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:200px;max-width:320px;max-height:280px;overflow-y:auto;background:var(--surface-raised);border:1px solid var(--border);border-radius:var(--radius);box-shadow:0 8px 24px rgba(0,0,0,.4);z-index:20;padding:4px;display:none}
|
|
1805
1832
|
.tag-menu:not([hidden]){display:block}
|
|
1806
1833
|
.tag-menu-item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 10px;font-size:12px;font-family:var(--mono);color:var(--text);background:transparent;border:none;border-radius:4px;cursor:pointer;text-align:left;width:100%;transition:background .15s}
|
|
1807
1834
|
.tag-menu-item:hover{background:var(--surface)}
|
|
1808
1835
|
.tag-menu-item .tag-menu-count{color:var(--text-muted);font-size:11px;font-family:var(--mono)}
|
|
1809
1836
|
.tag-menu-empty{padding:8px 10px;font-size:12px;color:var(--text-muted);font-style:italic}
|
|
1810
|
-
.tag-menu-section{padding:8px 10px
|
|
1837
|
+
.tag-menu-section{padding:8px 10px 2px;font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--text-dim);font-family:inherit}
|
|
1811
1838
|
.tag-menu-section:not(:first-child){margin-top:4px;border-top:1px solid var(--border)}
|
|
1839
|
+
.tag-menu-hint{padding:0 10px 6px;font-size:11px;line-height:1.35;color:var(--text-muted);font-family:inherit;max-width:300px}
|
|
1812
1840
|
.active-tag-filters{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
|
|
1813
1841
|
.tag-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(255,127,58,.12);border:1px solid rgba(255,127,58,.3);color:var(--accent);font-size:11px;font-family:var(--mono);padding:3px 4px 3px 8px;border-radius:4px}
|
|
1814
1842
|
.tag-chip-remove{background:transparent;border:none;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:0 4px;font-family:inherit;opacity:.7;transition:opacity .15s}
|
|
@@ -2163,7 +2191,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2163
2191
|
</label>
|
|
2164
2192
|
<div class="tag-filter-controls" data-tag-filter-controls hidden>
|
|
2165
2193
|
<div class="tag-filter-trigger-wrap">
|
|
2166
|
-
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag or
|
|
2194
|
+
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag, diagnosis, or triage"><span class="add-tag-plus">+</span> Filter</button>
|
|
2167
2195
|
<div class="tag-menu" data-tag-menu hidden></div>
|
|
2168
2196
|
</div>
|
|
2169
2197
|
<div class="active-tag-filters" data-active-tag-filters></div>
|
|
@@ -2191,16 +2219,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2191
2219
|
// tags — multi-select AND; card must carry every active tag.
|
|
2192
2220
|
// reasons — multi-select OR; card.data-reason must match any active reason
|
|
2193
2221
|
// (a card has at most one diagnosis, so AND would always be 0/1).
|
|
2194
|
-
//
|
|
2222
|
+
// triage — multi-select OR; card.data-triage (a comma list) must contain
|
|
2223
|
+
// any active flag (a card can carry several triage flags).
|
|
2224
|
+
// "Clear Filters" wipes all of them.
|
|
2195
2225
|
var activeStatus=null;
|
|
2196
2226
|
var activeTags=new Set();
|
|
2197
2227
|
var activeReasons=new Set();
|
|
2228
|
+
var activeTriage=new Set();
|
|
2198
2229
|
var activeSearch=''; // lowercase substring match against data-search
|
|
2199
2230
|
var allTags=[];
|
|
2200
2231
|
var allReasons=[]; // ordered list of REASON keys present in the report
|
|
2232
|
+
var allTriage=[]; // ordered list of TRIAGE keys present in the report
|
|
2201
2233
|
var REASON_LABELS=${JSON.stringify(REASON_LABELS)};
|
|
2234
|
+
var TRIAGE_LABELS=${JSON.stringify(TRIAGE_LABELS)};
|
|
2202
2235
|
|
|
2203
2236
|
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 []}}
|
|
2237
|
+
function cardTriage(card){var raw=card.getAttribute('data-triage');return raw?raw.split(','):[]}
|
|
2204
2238
|
|
|
2205
2239
|
// Faceted-search counts. Each filter option's badge shows "how many tests
|
|
2206
2240
|
// would this option contribute given the rest of the filters." The semantics
|
|
@@ -2208,8 +2242,9 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2208
2242
|
// - Status pills (single-select replace): ignore current activeStatus.
|
|
2209
2243
|
// - Tag menu items (multi-select AND): use ALL current filters.
|
|
2210
2244
|
// - Reason menu items (multi-select OR): ignore current activeReasons.
|
|
2245
|
+
// - Triage menu items (multi-select OR): ignore current activeTriage.
|
|
2211
2246
|
// Search is free-form and not counted.
|
|
2212
|
-
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons){
|
|
2247
|
+
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons,ignoreTriage){
|
|
2213
2248
|
var out=[];
|
|
2214
2249
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2215
2250
|
var statusOk=ignoreStatus||activeStatus===null||card.getAttribute('data-status')===activeStatus;
|
|
@@ -2219,19 +2254,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2219
2254
|
activeTags.forEach(function(w){if(t.indexOf(w)===-1)tagsOk=false});
|
|
2220
2255
|
}
|
|
2221
2256
|
var reasonOk=ignoreReasons||activeReasons.size===0||activeReasons.has(card.getAttribute('data-reason')||'');
|
|
2257
|
+
var triageOk=true;
|
|
2258
|
+
if(!ignoreTriage&&activeTriage.size>0){
|
|
2259
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2260
|
+
}
|
|
2222
2261
|
var searchOk=activeSearch.length===0||(card.getAttribute('data-search')||'').indexOf(activeSearch)!==-1;
|
|
2223
|
-
if(statusOk&&tagsOk&&reasonOk&&searchOk)out.push(card);
|
|
2262
|
+
if(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk)out.push(card);
|
|
2224
2263
|
});
|
|
2225
2264
|
return out;
|
|
2226
2265
|
}
|
|
2227
2266
|
function tagCount(t){
|
|
2228
|
-
var pool=cardsMatching(false,false,false);
|
|
2267
|
+
var pool=cardsMatching(false,false,false,false);
|
|
2229
2268
|
var n=0;for(var i=0;i<pool.length;i++){if(cardTags(pool[i]).indexOf(t)!==-1)n++}
|
|
2230
2269
|
return n;
|
|
2231
2270
|
}
|
|
2232
2271
|
|
|
2233
2272
|
function applyFilters(){
|
|
2234
|
-
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0;
|
|
2273
|
+
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0;
|
|
2235
2274
|
document.querySelector('.clear-filter').classList.toggle('visible',anyActive);
|
|
2236
2275
|
var visibleTests=0;
|
|
2237
2276
|
var visibleFiles=Object.create(null);
|
|
@@ -2247,12 +2286,16 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2247
2286
|
var r=card.getAttribute('data-reason')||'';
|
|
2248
2287
|
reasonOk=activeReasons.has(r);
|
|
2249
2288
|
}
|
|
2289
|
+
var triageOk=true;
|
|
2290
|
+
if(activeTriage.size>0){
|
|
2291
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2292
|
+
}
|
|
2250
2293
|
var searchOk=true;
|
|
2251
2294
|
if(activeSearch.length>0){
|
|
2252
2295
|
var hay=card.getAttribute('data-search')||'';
|
|
2253
2296
|
searchOk=hay.indexOf(activeSearch)!==-1;
|
|
2254
2297
|
}
|
|
2255
|
-
var hide=!(statusOk&&tagsOk&&reasonOk&&searchOk);
|
|
2298
|
+
var hide=!(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk);
|
|
2256
2299
|
card.classList.toggle('hidden-by-filter',hide);
|
|
2257
2300
|
if(!hide){
|
|
2258
2301
|
visibleTests++;
|
|
@@ -2295,6 +2338,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2295
2338
|
if(activeStatus)p.set('status',activeStatus);
|
|
2296
2339
|
activeTags.forEach(function(t){p.append('tag',t)});
|
|
2297
2340
|
activeReasons.forEach(function(r){p.append('reason',r)});
|
|
2341
|
+
activeTriage.forEach(function(t){p.append('triage',t)});
|
|
2298
2342
|
if(activeSearch)p.set('q',activeSearch);
|
|
2299
2343
|
var qs=p.toString();
|
|
2300
2344
|
var next=location.pathname+(qs?'?'+qs:'')+(location.hash||'');
|
|
@@ -2340,19 +2384,37 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2340
2384
|
chip.appendChild(label);chip.appendChild(btn);
|
|
2341
2385
|
c.appendChild(chip);
|
|
2342
2386
|
});
|
|
2387
|
+
activeTriage.forEach(function(t){
|
|
2388
|
+
var meta=TRIAGE_LABELS[t];if(!meta)return;
|
|
2389
|
+
var chip=document.createElement('span');chip.className='tag-chip reason-chip';
|
|
2390
|
+
chip.style.background=hexToRgba(meta.color,0.14);
|
|
2391
|
+
chip.style.borderColor=hexToRgba(meta.color,0.4);
|
|
2392
|
+
chip.style.color=meta.color;
|
|
2393
|
+
var label=document.createElement('span');label.textContent=meta.label;
|
|
2394
|
+
var btn=document.createElement('button');btn.className='tag-chip-remove';btn.setAttribute('data-remove-triage',t);btn.setAttribute('title','Remove filter');btn.textContent='×';
|
|
2395
|
+
chip.appendChild(label);chip.appendChild(btn);
|
|
2396
|
+
c.appendChild(chip);
|
|
2397
|
+
});
|
|
2343
2398
|
}
|
|
2344
2399
|
function addTag(t){if(!t||activeTags.has(t))return;activeTags.add(t);renderActiveChips();applyFilters()}
|
|
2345
2400
|
function removeTag(t){if(!activeTags.delete(t))return;renderActiveChips();applyFilters()}
|
|
2346
2401
|
function addReason(r){if(!r||activeReasons.has(r))return;activeReasons.add(r);renderActiveChips();applyFilters()}
|
|
2347
2402
|
function removeReason(r){if(!activeReasons.delete(r))return;renderActiveChips();applyFilters()}
|
|
2403
|
+
function addTriage(t){if(!t||activeTriage.has(t))return;activeTriage.add(t);renderActiveChips();applyFilters()}
|
|
2404
|
+
function removeTriage(t){if(!activeTriage.delete(t))return;renderActiveChips();applyFilters()}
|
|
2348
2405
|
|
|
2349
2406
|
function reasonCount(r){
|
|
2350
|
-
var pool=cardsMatching(false,false,true);
|
|
2407
|
+
var pool=cardsMatching(false,false,true,false);
|
|
2351
2408
|
var n=0;for(var i=0;i<pool.length;i++){if(pool[i].getAttribute('data-reason')===r)n++}
|
|
2352
2409
|
return n;
|
|
2353
2410
|
}
|
|
2411
|
+
function triageCount(t){
|
|
2412
|
+
var pool=cardsMatching(false,false,false,true);
|
|
2413
|
+
var n=0;for(var i=0;i<pool.length;i++){if(cardTriage(pool[i]).indexOf(t)!==-1)n++}
|
|
2414
|
+
return n;
|
|
2415
|
+
}
|
|
2354
2416
|
function updateStatPillCounts(){
|
|
2355
|
-
var pool=cardsMatching(true,false,false);
|
|
2417
|
+
var pool=cardsMatching(true,false,false,false);
|
|
2356
2418
|
var counts=Object.create(null);
|
|
2357
2419
|
for(var i=0;i<pool.length;i++){var s=pool[i].getAttribute('data-status');counts[s]=(counts[s]||0)+1}
|
|
2358
2420
|
document.querySelectorAll('.stat-pill[data-filter]').forEach(function(pill){
|
|
@@ -2372,9 +2434,11 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2372
2434
|
// to an empty view, so they're not useful to offer.
|
|
2373
2435
|
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});
|
|
2374
2436
|
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});
|
|
2437
|
+
var triageWithCounts=allTriage.filter(function(t){return !activeTriage.has(t)}).map(function(t){return {key:t,count:triageCount(t)}}).filter(function(x){return x.count>0});
|
|
2375
2438
|
var added=false;
|
|
2376
2439
|
if(allTags.length>0){
|
|
2377
2440
|
var hT=document.createElement('div');hT.className='tag-menu-section';hT.textContent='Tags';menu.appendChild(hT);
|
|
2441
|
+
var hintT=document.createElement('div');hintT.className='tag-menu-hint';hintT.textContent='Labels you put on tests in code (e.g. @smoke). Match all selected.';menu.appendChild(hintT);
|
|
2378
2442
|
if(tagsWithCounts.length===0){
|
|
2379
2443
|
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);
|
|
2380
2444
|
}else{
|
|
@@ -2390,6 +2454,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2390
2454
|
}
|
|
2391
2455
|
if(allReasons.length>0){
|
|
2392
2456
|
var hR=document.createElement('div');hR.className='tag-menu-section';hR.textContent='Diagnoses';menu.appendChild(hR);
|
|
2457
|
+
var hintR=document.createElement('div');hintR.className='tag-menu-hint';hintR.textContent='Why a test failed — the AI\\'s single root-cause assessment.';menu.appendChild(hintR);
|
|
2393
2458
|
if(reasonsWithCounts.length===0){
|
|
2394
2459
|
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);
|
|
2395
2460
|
}else{
|
|
@@ -2404,6 +2469,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2404
2469
|
}
|
|
2405
2470
|
added=true;
|
|
2406
2471
|
}
|
|
2472
|
+
if(allTriage.length>0){
|
|
2473
|
+
var hTr=document.createElement('div');hTr.className='tag-menu-section';hTr.textContent='Triage';menu.appendChild(hTr);
|
|
2474
|
+
var hintTr=document.createElement('div');hintTr.className='tag-menu-hint';hintTr.textContent='What the failure calls for — a test can need more than one.';menu.appendChild(hintTr);
|
|
2475
|
+
if(triageWithCounts.length===0){
|
|
2476
|
+
var emptyTr=document.createElement('div');emptyTr.className='tag-menu-empty';emptyTr.textContent=allTriage.length===activeTriage.size?'All triage flags selected':'No matching triage flags';menu.appendChild(emptyTr);
|
|
2477
|
+
}else{
|
|
2478
|
+
triageWithCounts.forEach(function(x){
|
|
2479
|
+
var meta=TRIAGE_LABELS[x.key];if(!meta)return;
|
|
2480
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-triage-menu-item',x.key);
|
|
2481
|
+
var label=document.createElement('span');label.textContent=meta.label;label.style.color=meta.color;
|
|
2482
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2483
|
+
item.appendChild(label);item.appendChild(count);
|
|
2484
|
+
menu.appendChild(item);
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
added=true;
|
|
2488
|
+
}
|
|
2407
2489
|
if(!added){
|
|
2408
2490
|
var empty=document.createElement('div');empty.className='tag-menu-empty';empty.textContent='No filters available';menu.appendChild(empty);
|
|
2409
2491
|
}
|
|
@@ -2421,6 +2503,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2421
2503
|
activeStatus=null;
|
|
2422
2504
|
activeTags.clear();
|
|
2423
2505
|
activeReasons.clear();
|
|
2506
|
+
activeTriage.clear();
|
|
2424
2507
|
activeSearch='';
|
|
2425
2508
|
document.querySelectorAll('.stat-pill').forEach(function(p){p.classList.remove('active')});
|
|
2426
2509
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
@@ -2470,10 +2553,14 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2470
2553
|
if(tagItem){addTag(tagItem.getAttribute('data-tag-menu-item'));closeTagMenu();return}
|
|
2471
2554
|
var reasonItem=e.target.closest('[data-reason-menu-item]');
|
|
2472
2555
|
if(reasonItem){addReason(reasonItem.getAttribute('data-reason-menu-item'));closeTagMenu();return}
|
|
2556
|
+
var triageItem=e.target.closest('[data-triage-menu-item]');
|
|
2557
|
+
if(triageItem){addTriage(triageItem.getAttribute('data-triage-menu-item'));closeTagMenu();return}
|
|
2473
2558
|
var tagRemove=e.target.closest('[data-remove-tag]');
|
|
2474
2559
|
if(tagRemove){removeTag(tagRemove.getAttribute('data-remove-tag'));return}
|
|
2475
2560
|
var reasonRemove=e.target.closest('[data-remove-reason]');
|
|
2476
2561
|
if(reasonRemove){removeReason(reasonRemove.getAttribute('data-remove-reason'));return}
|
|
2562
|
+
var triageRemove=e.target.closest('[data-remove-triage]');
|
|
2563
|
+
if(triageRemove){removeTriage(triageRemove.getAttribute('data-remove-triage'));return}
|
|
2477
2564
|
// Stat pill filter
|
|
2478
2565
|
var pill=e.target.closest('.stat-pill[data-filter]');
|
|
2479
2566
|
if(pill){toggleStatus(pill.getAttribute('data-filter'));return}
|
|
@@ -2523,18 +2610,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2523
2610
|
(function(){
|
|
2524
2611
|
var seenTags=Object.create(null);
|
|
2525
2612
|
var seenReasons=Object.create(null);
|
|
2613
|
+
var seenTriage=Object.create(null);
|
|
2526
2614
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2527
2615
|
var raw=card.getAttribute('data-tags');
|
|
2528
2616
|
if(raw){try{var tags=JSON.parse(raw);if(Array.isArray(tags)){tags.forEach(function(t){if(typeof t==='string'&&t)seenTags[t]=true})}}catch(_){}}
|
|
2529
2617
|
var r=card.getAttribute('data-reason');
|
|
2530
2618
|
if(r)seenReasons[r]=true;
|
|
2619
|
+
cardTriage(card).forEach(function(t){if(t)seenTriage[t]=true});
|
|
2531
2620
|
});
|
|
2532
2621
|
allTags=Object.keys(seenTags).sort();
|
|
2533
2622
|
// Preserve the REASON_LABELS declaration order rather than alphabetical —
|
|
2534
2623
|
// they're already arranged from most-frequent/specific to UNKNOWN catch-all.
|
|
2535
2624
|
allReasons=Object.keys(REASON_LABELS).filter(function(r){return seenReasons[r]});
|
|
2625
|
+
// Preserve TRIAGE_LABELS declaration order (retryable → code → product).
|
|
2626
|
+
allTriage=Object.keys(TRIAGE_LABELS).filter(function(t){return seenTriage[t]});
|
|
2536
2627
|
var controls=document.querySelector('[data-tag-filter-controls]');
|
|
2537
|
-
if(controls&&(allTags.length>0||allReasons.length>0))controls.hidden=false;
|
|
2628
|
+
if(controls&&(allTags.length>0||allReasons.length>0||allTriage.length>0))controls.hidden=false;
|
|
2538
2629
|
})();
|
|
2539
2630
|
|
|
2540
2631
|
// Seed filter state from ?status=...&tag=...&reason=... so shared URLs
|
|
@@ -2554,6 +2645,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2554
2645
|
p.getAll('tag').forEach(function(t){if(tagSet[t])activeTags.add(t)});
|
|
2555
2646
|
var reasonSet={};allReasons.forEach(function(r){reasonSet[r]=true});
|
|
2556
2647
|
p.getAll('reason').forEach(function(r){if(reasonSet[r])activeReasons.add(r)});
|
|
2648
|
+
var triageSet={};allTriage.forEach(function(t){triageSet[t]=true});
|
|
2649
|
+
p.getAll('triage').forEach(function(t){if(triageSet[t])activeTriage.add(t)});
|
|
2557
2650
|
var q=p.get('q');
|
|
2558
2651
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
2559
2652
|
if(q){
|
|
@@ -2566,8 +2659,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2566
2659
|
applyFilters();
|
|
2567
2660
|
});
|
|
2568
2661
|
}
|
|
2569
|
-
if(activeTags.size>0||activeReasons.size>0)renderActiveChips();
|
|
2570
|
-
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0)applyFilters();
|
|
2662
|
+
if(activeTags.size>0||activeReasons.size>0||activeTriage.size>0)renderActiveChips();
|
|
2663
|
+
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0)applyFilters();
|
|
2571
2664
|
})();
|
|
2572
2665
|
|
|
2573
2666
|
// Open #?testId=<id> deep links to the matching test card. Used by the
|