donobu 5.47.0 → 5.49.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 +120 -17
- package/dist/reporter/render.js +120 -17
- 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>
|
|
@@ -1695,7 +1722,7 @@ function renderHtml(report, triage, outputDir) {
|
|
|
1695
1722
|
</div>
|
|
1696
1723
|
</div>
|
|
1697
1724
|
${test.plan ? `<span class="inline-reason" style="color:${reasonCfg(test.plan.plan.failureReason).color}" title="${esc(test.plan.plan.failureReason)}">${esc(reasonCfg(test.plan.plan.failureReason).label)}</span>` : ''}
|
|
1698
|
-
${test.tags.map((t) => `<span class="test-tag">${esc(t)}</span>`).join('')}
|
|
1725
|
+
${test.tags.map((t) => `<span class="test-tag" data-copy-tag="${esc(t)}" title="Click to copy"><span class="tag-label">${esc(t)}</span><span class="tag-copy-glyph"><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></span></span>`).join('')}
|
|
1699
1726
|
${totalStepCount > 0 ? `<span class="test-step-count" title="${totalStepCount} steps">${totalStepCount} steps</span>` : ''}
|
|
1700
1727
|
<span class="test-duration">${fmtDuration(totalTestDuration)}</span>
|
|
1701
1728
|
</div>
|
|
@@ -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}
|
|
@@ -1842,7 +1870,13 @@ body::before{content:'';position:fixed;top:-750px;left:50%;transform:translateX(
|
|
|
1842
1870
|
.copy-flow-id .check-icon{color:#22c55e}
|
|
1843
1871
|
.inline-reason{font-size:11px;font-weight:500;flex-shrink:0;padding:1px 8px;border-radius:4px;background:var(--overlay-light)}
|
|
1844
1872
|
.test-step-count{font-size:11px;color:var(--text-dim);flex-shrink:0;font-family:var(--mono);padding:2px 8px;background:rgba(255,255,255,.04);border-radius:4px}
|
|
1845
|
-
.test-tag{font-size:11px;color:var(--accent);flex-shrink:0;font-family:var(--mono);padding:2px 8px;background:rgba(255,127,58,.08);border:1px solid rgba(255,127,58,.2);border-radius:4px}
|
|
1873
|
+
.test-tag{font-size:11px;color:var(--accent);flex-shrink:0;font-family:var(--mono);padding:2px 8px;background:rgba(255,127,58,.08);border:1px solid rgba(255,127,58,.2);border-radius:4px;cursor:pointer;display:inline-flex;align-items:center;transition:background .15s,border-color .15s}
|
|
1874
|
+
.test-tag:hover{background:rgba(255,127,58,.16);border-color:rgba(255,127,58,.45)}
|
|
1875
|
+
.tag-copy-glyph{display:inline-flex;align-items:center;width:0;margin-left:0;opacity:0;overflow:hidden;transition:width .15s,opacity .15s,margin-left .15s}
|
|
1876
|
+
.test-tag:hover .tag-copy-glyph,.test-tag.copied .tag-copy-glyph{width:11px;margin-left:4px;opacity:.75}
|
|
1877
|
+
.tag-copy-glyph svg{width:11px;height:11px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
|
|
1878
|
+
.test-tag.copied{color:#22c55e;border-color:rgba(34,197,94,.45);background:rgba(34,197,94,.12)}
|
|
1879
|
+
.test-tag.copied .tag-copy-glyph{opacity:1}
|
|
1846
1880
|
.test-duration{font-size:12px;color:var(--text-dim);flex-shrink:0;font-family:var(--mono)}
|
|
1847
1881
|
.flow-id-detail{display:flex;align-items:center;gap:10px;margin-bottom:4px;padding:8px 12px;background:var(--surface-raised);border:1px solid var(--border-subtle);border-radius:var(--radius)}
|
|
1848
1882
|
.flow-id-detail .detail-label{margin-bottom:0;font-size:10px;letter-spacing:.8px}
|
|
@@ -2163,7 +2197,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2163
2197
|
</label>
|
|
2164
2198
|
<div class="tag-filter-controls" data-tag-filter-controls hidden>
|
|
2165
2199
|
<div class="tag-filter-trigger-wrap">
|
|
2166
|
-
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag or
|
|
2200
|
+
<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
2201
|
<div class="tag-menu" data-tag-menu hidden></div>
|
|
2168
2202
|
</div>
|
|
2169
2203
|
<div class="active-tag-filters" data-active-tag-filters></div>
|
|
@@ -2191,16 +2225,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2191
2225
|
// tags — multi-select AND; card must carry every active tag.
|
|
2192
2226
|
// reasons — multi-select OR; card.data-reason must match any active reason
|
|
2193
2227
|
// (a card has at most one diagnosis, so AND would always be 0/1).
|
|
2194
|
-
//
|
|
2228
|
+
// triage — multi-select OR; card.data-triage (a comma list) must contain
|
|
2229
|
+
// any active flag (a card can carry several triage flags).
|
|
2230
|
+
// "Clear Filters" wipes all of them.
|
|
2195
2231
|
var activeStatus=null;
|
|
2196
2232
|
var activeTags=new Set();
|
|
2197
2233
|
var activeReasons=new Set();
|
|
2234
|
+
var activeTriage=new Set();
|
|
2198
2235
|
var activeSearch=''; // lowercase substring match against data-search
|
|
2199
2236
|
var allTags=[];
|
|
2200
2237
|
var allReasons=[]; // ordered list of REASON keys present in the report
|
|
2238
|
+
var allTriage=[]; // ordered list of TRIAGE keys present in the report
|
|
2201
2239
|
var REASON_LABELS=${JSON.stringify(REASON_LABELS)};
|
|
2240
|
+
var TRIAGE_LABELS=${JSON.stringify(TRIAGE_LABELS)};
|
|
2202
2241
|
|
|
2203
2242
|
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 []}}
|
|
2243
|
+
function cardTriage(card){var raw=card.getAttribute('data-triage');return raw?raw.split(','):[]}
|
|
2204
2244
|
|
|
2205
2245
|
// Faceted-search counts. Each filter option's badge shows "how many tests
|
|
2206
2246
|
// would this option contribute given the rest of the filters." The semantics
|
|
@@ -2208,8 +2248,9 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2208
2248
|
// - Status pills (single-select replace): ignore current activeStatus.
|
|
2209
2249
|
// - Tag menu items (multi-select AND): use ALL current filters.
|
|
2210
2250
|
// - Reason menu items (multi-select OR): ignore current activeReasons.
|
|
2251
|
+
// - Triage menu items (multi-select OR): ignore current activeTriage.
|
|
2211
2252
|
// Search is free-form and not counted.
|
|
2212
|
-
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons){
|
|
2253
|
+
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons,ignoreTriage){
|
|
2213
2254
|
var out=[];
|
|
2214
2255
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2215
2256
|
var statusOk=ignoreStatus||activeStatus===null||card.getAttribute('data-status')===activeStatus;
|
|
@@ -2219,19 +2260,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2219
2260
|
activeTags.forEach(function(w){if(t.indexOf(w)===-1)tagsOk=false});
|
|
2220
2261
|
}
|
|
2221
2262
|
var reasonOk=ignoreReasons||activeReasons.size===0||activeReasons.has(card.getAttribute('data-reason')||'');
|
|
2263
|
+
var triageOk=true;
|
|
2264
|
+
if(!ignoreTriage&&activeTriage.size>0){
|
|
2265
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2266
|
+
}
|
|
2222
2267
|
var searchOk=activeSearch.length===0||(card.getAttribute('data-search')||'').indexOf(activeSearch)!==-1;
|
|
2223
|
-
if(statusOk&&tagsOk&&reasonOk&&searchOk)out.push(card);
|
|
2268
|
+
if(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk)out.push(card);
|
|
2224
2269
|
});
|
|
2225
2270
|
return out;
|
|
2226
2271
|
}
|
|
2227
2272
|
function tagCount(t){
|
|
2228
|
-
var pool=cardsMatching(false,false,false);
|
|
2273
|
+
var pool=cardsMatching(false,false,false,false);
|
|
2229
2274
|
var n=0;for(var i=0;i<pool.length;i++){if(cardTags(pool[i]).indexOf(t)!==-1)n++}
|
|
2230
2275
|
return n;
|
|
2231
2276
|
}
|
|
2232
2277
|
|
|
2233
2278
|
function applyFilters(){
|
|
2234
|
-
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0;
|
|
2279
|
+
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0;
|
|
2235
2280
|
document.querySelector('.clear-filter').classList.toggle('visible',anyActive);
|
|
2236
2281
|
var visibleTests=0;
|
|
2237
2282
|
var visibleFiles=Object.create(null);
|
|
@@ -2247,12 +2292,16 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2247
2292
|
var r=card.getAttribute('data-reason')||'';
|
|
2248
2293
|
reasonOk=activeReasons.has(r);
|
|
2249
2294
|
}
|
|
2295
|
+
var triageOk=true;
|
|
2296
|
+
if(activeTriage.size>0){
|
|
2297
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2298
|
+
}
|
|
2250
2299
|
var searchOk=true;
|
|
2251
2300
|
if(activeSearch.length>0){
|
|
2252
2301
|
var hay=card.getAttribute('data-search')||'';
|
|
2253
2302
|
searchOk=hay.indexOf(activeSearch)!==-1;
|
|
2254
2303
|
}
|
|
2255
|
-
var hide=!(statusOk&&tagsOk&&reasonOk&&searchOk);
|
|
2304
|
+
var hide=!(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk);
|
|
2256
2305
|
card.classList.toggle('hidden-by-filter',hide);
|
|
2257
2306
|
if(!hide){
|
|
2258
2307
|
visibleTests++;
|
|
@@ -2295,6 +2344,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2295
2344
|
if(activeStatus)p.set('status',activeStatus);
|
|
2296
2345
|
activeTags.forEach(function(t){p.append('tag',t)});
|
|
2297
2346
|
activeReasons.forEach(function(r){p.append('reason',r)});
|
|
2347
|
+
activeTriage.forEach(function(t){p.append('triage',t)});
|
|
2298
2348
|
if(activeSearch)p.set('q',activeSearch);
|
|
2299
2349
|
var qs=p.toString();
|
|
2300
2350
|
var next=location.pathname+(qs?'?'+qs:'')+(location.hash||'');
|
|
@@ -2340,19 +2390,37 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2340
2390
|
chip.appendChild(label);chip.appendChild(btn);
|
|
2341
2391
|
c.appendChild(chip);
|
|
2342
2392
|
});
|
|
2393
|
+
activeTriage.forEach(function(t){
|
|
2394
|
+
var meta=TRIAGE_LABELS[t];if(!meta)return;
|
|
2395
|
+
var chip=document.createElement('span');chip.className='tag-chip reason-chip';
|
|
2396
|
+
chip.style.background=hexToRgba(meta.color,0.14);
|
|
2397
|
+
chip.style.borderColor=hexToRgba(meta.color,0.4);
|
|
2398
|
+
chip.style.color=meta.color;
|
|
2399
|
+
var label=document.createElement('span');label.textContent=meta.label;
|
|
2400
|
+
var btn=document.createElement('button');btn.className='tag-chip-remove';btn.setAttribute('data-remove-triage',t);btn.setAttribute('title','Remove filter');btn.textContent='×';
|
|
2401
|
+
chip.appendChild(label);chip.appendChild(btn);
|
|
2402
|
+
c.appendChild(chip);
|
|
2403
|
+
});
|
|
2343
2404
|
}
|
|
2344
2405
|
function addTag(t){if(!t||activeTags.has(t))return;activeTags.add(t);renderActiveChips();applyFilters()}
|
|
2345
2406
|
function removeTag(t){if(!activeTags.delete(t))return;renderActiveChips();applyFilters()}
|
|
2346
2407
|
function addReason(r){if(!r||activeReasons.has(r))return;activeReasons.add(r);renderActiveChips();applyFilters()}
|
|
2347
2408
|
function removeReason(r){if(!activeReasons.delete(r))return;renderActiveChips();applyFilters()}
|
|
2409
|
+
function addTriage(t){if(!t||activeTriage.has(t))return;activeTriage.add(t);renderActiveChips();applyFilters()}
|
|
2410
|
+
function removeTriage(t){if(!activeTriage.delete(t))return;renderActiveChips();applyFilters()}
|
|
2348
2411
|
|
|
2349
2412
|
function reasonCount(r){
|
|
2350
|
-
var pool=cardsMatching(false,false,true);
|
|
2413
|
+
var pool=cardsMatching(false,false,true,false);
|
|
2351
2414
|
var n=0;for(var i=0;i<pool.length;i++){if(pool[i].getAttribute('data-reason')===r)n++}
|
|
2352
2415
|
return n;
|
|
2353
2416
|
}
|
|
2417
|
+
function triageCount(t){
|
|
2418
|
+
var pool=cardsMatching(false,false,false,true);
|
|
2419
|
+
var n=0;for(var i=0;i<pool.length;i++){if(cardTriage(pool[i]).indexOf(t)!==-1)n++}
|
|
2420
|
+
return n;
|
|
2421
|
+
}
|
|
2354
2422
|
function updateStatPillCounts(){
|
|
2355
|
-
var pool=cardsMatching(true,false,false);
|
|
2423
|
+
var pool=cardsMatching(true,false,false,false);
|
|
2356
2424
|
var counts=Object.create(null);
|
|
2357
2425
|
for(var i=0;i<pool.length;i++){var s=pool[i].getAttribute('data-status');counts[s]=(counts[s]||0)+1}
|
|
2358
2426
|
document.querySelectorAll('.stat-pill[data-filter]').forEach(function(pill){
|
|
@@ -2372,9 +2440,11 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2372
2440
|
// to an empty view, so they're not useful to offer.
|
|
2373
2441
|
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
2442
|
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});
|
|
2443
|
+
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
2444
|
var added=false;
|
|
2376
2445
|
if(allTags.length>0){
|
|
2377
2446
|
var hT=document.createElement('div');hT.className='tag-menu-section';hT.textContent='Tags';menu.appendChild(hT);
|
|
2447
|
+
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
2448
|
if(tagsWithCounts.length===0){
|
|
2379
2449
|
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
2450
|
}else{
|
|
@@ -2390,6 +2460,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2390
2460
|
}
|
|
2391
2461
|
if(allReasons.length>0){
|
|
2392
2462
|
var hR=document.createElement('div');hR.className='tag-menu-section';hR.textContent='Diagnoses';menu.appendChild(hR);
|
|
2463
|
+
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
2464
|
if(reasonsWithCounts.length===0){
|
|
2394
2465
|
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
2466
|
}else{
|
|
@@ -2404,6 +2475,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2404
2475
|
}
|
|
2405
2476
|
added=true;
|
|
2406
2477
|
}
|
|
2478
|
+
if(allTriage.length>0){
|
|
2479
|
+
var hTr=document.createElement('div');hTr.className='tag-menu-section';hTr.textContent='Triage';menu.appendChild(hTr);
|
|
2480
|
+
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);
|
|
2481
|
+
if(triageWithCounts.length===0){
|
|
2482
|
+
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);
|
|
2483
|
+
}else{
|
|
2484
|
+
triageWithCounts.forEach(function(x){
|
|
2485
|
+
var meta=TRIAGE_LABELS[x.key];if(!meta)return;
|
|
2486
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-triage-menu-item',x.key);
|
|
2487
|
+
var label=document.createElement('span');label.textContent=meta.label;label.style.color=meta.color;
|
|
2488
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2489
|
+
item.appendChild(label);item.appendChild(count);
|
|
2490
|
+
menu.appendChild(item);
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
added=true;
|
|
2494
|
+
}
|
|
2407
2495
|
if(!added){
|
|
2408
2496
|
var empty=document.createElement('div');empty.className='tag-menu-empty';empty.textContent='No filters available';menu.appendChild(empty);
|
|
2409
2497
|
}
|
|
@@ -2421,6 +2509,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2421
2509
|
activeStatus=null;
|
|
2422
2510
|
activeTags.clear();
|
|
2423
2511
|
activeReasons.clear();
|
|
2512
|
+
activeTriage.clear();
|
|
2424
2513
|
activeSearch='';
|
|
2425
2514
|
document.querySelectorAll('.stat-pill').forEach(function(p){p.classList.remove('active')});
|
|
2426
2515
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
@@ -2457,6 +2546,10 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2457
2546
|
// Copy buttons (flow ID + JSON + inline text via data-copy-text)
|
|
2458
2547
|
var copyTextBtn=e.target.closest('.copy-text[data-copy-text]');
|
|
2459
2548
|
if(copyTextBtn){e.stopPropagation();e.preventDefault();navigator.clipboard.writeText(copyTextBtn.getAttribute('data-copy-text'));var copyTextSvg=copyTextBtn.innerHTML;copyTextBtn.innerHTML='<svg class="check-icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';setTimeout(function(){copyTextBtn.innerHTML=copyTextSvg},2000);return}
|
|
2549
|
+
// Tag chip: click anywhere on the chip copies its tag text. The hover glyph
|
|
2550
|
+
// briefly becomes a check; stopPropagation keeps the card from expanding.
|
|
2551
|
+
var tagChip=e.target.closest('.test-tag[data-copy-tag]');
|
|
2552
|
+
if(tagChip){e.stopPropagation();navigator.clipboard.writeText(tagChip.getAttribute('data-copy-tag'));var glyph=tagChip.querySelector('.tag-copy-glyph');if(glyph){var glyphSvg=glyph.innerHTML;glyph.innerHTML='<svg class="check-icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';tagChip.classList.add('copied');setTimeout(function(){glyph.innerHTML=glyphSvg;tagChip.classList.remove('copied')},1500)}return}
|
|
2460
2553
|
var flowBtn=e.target.closest('.copy-flow-id');
|
|
2461
2554
|
if(flowBtn){e.stopPropagation();navigator.clipboard.writeText(flowBtn.getAttribute('data-flow-id'));var copySvg=flowBtn.innerHTML;flowBtn.innerHTML='<svg class="check-icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';setTimeout(function(){flowBtn.innerHTML=copySvg},2000);return}
|
|
2462
2555
|
var jsonBtn=e.target.closest('.copy-json');
|
|
@@ -2470,10 +2563,14 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2470
2563
|
if(tagItem){addTag(tagItem.getAttribute('data-tag-menu-item'));closeTagMenu();return}
|
|
2471
2564
|
var reasonItem=e.target.closest('[data-reason-menu-item]');
|
|
2472
2565
|
if(reasonItem){addReason(reasonItem.getAttribute('data-reason-menu-item'));closeTagMenu();return}
|
|
2566
|
+
var triageItem=e.target.closest('[data-triage-menu-item]');
|
|
2567
|
+
if(triageItem){addTriage(triageItem.getAttribute('data-triage-menu-item'));closeTagMenu();return}
|
|
2473
2568
|
var tagRemove=e.target.closest('[data-remove-tag]');
|
|
2474
2569
|
if(tagRemove){removeTag(tagRemove.getAttribute('data-remove-tag'));return}
|
|
2475
2570
|
var reasonRemove=e.target.closest('[data-remove-reason]');
|
|
2476
2571
|
if(reasonRemove){removeReason(reasonRemove.getAttribute('data-remove-reason'));return}
|
|
2572
|
+
var triageRemove=e.target.closest('[data-remove-triage]');
|
|
2573
|
+
if(triageRemove){removeTriage(triageRemove.getAttribute('data-remove-triage'));return}
|
|
2477
2574
|
// Stat pill filter
|
|
2478
2575
|
var pill=e.target.closest('.stat-pill[data-filter]');
|
|
2479
2576
|
if(pill){toggleStatus(pill.getAttribute('data-filter'));return}
|
|
@@ -2523,18 +2620,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2523
2620
|
(function(){
|
|
2524
2621
|
var seenTags=Object.create(null);
|
|
2525
2622
|
var seenReasons=Object.create(null);
|
|
2623
|
+
var seenTriage=Object.create(null);
|
|
2526
2624
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2527
2625
|
var raw=card.getAttribute('data-tags');
|
|
2528
2626
|
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
2627
|
var r=card.getAttribute('data-reason');
|
|
2530
2628
|
if(r)seenReasons[r]=true;
|
|
2629
|
+
cardTriage(card).forEach(function(t){if(t)seenTriage[t]=true});
|
|
2531
2630
|
});
|
|
2532
2631
|
allTags=Object.keys(seenTags).sort();
|
|
2533
2632
|
// Preserve the REASON_LABELS declaration order rather than alphabetical —
|
|
2534
2633
|
// they're already arranged from most-frequent/specific to UNKNOWN catch-all.
|
|
2535
2634
|
allReasons=Object.keys(REASON_LABELS).filter(function(r){return seenReasons[r]});
|
|
2635
|
+
// Preserve TRIAGE_LABELS declaration order (retryable → code → product).
|
|
2636
|
+
allTriage=Object.keys(TRIAGE_LABELS).filter(function(t){return seenTriage[t]});
|
|
2536
2637
|
var controls=document.querySelector('[data-tag-filter-controls]');
|
|
2537
|
-
if(controls&&(allTags.length>0||allReasons.length>0))controls.hidden=false;
|
|
2638
|
+
if(controls&&(allTags.length>0||allReasons.length>0||allTriage.length>0))controls.hidden=false;
|
|
2538
2639
|
})();
|
|
2539
2640
|
|
|
2540
2641
|
// Seed filter state from ?status=...&tag=...&reason=... so shared URLs
|
|
@@ -2554,6 +2655,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2554
2655
|
p.getAll('tag').forEach(function(t){if(tagSet[t])activeTags.add(t)});
|
|
2555
2656
|
var reasonSet={};allReasons.forEach(function(r){reasonSet[r]=true});
|
|
2556
2657
|
p.getAll('reason').forEach(function(r){if(reasonSet[r])activeReasons.add(r)});
|
|
2658
|
+
var triageSet={};allTriage.forEach(function(t){triageSet[t]=true});
|
|
2659
|
+
p.getAll('triage').forEach(function(t){if(triageSet[t])activeTriage.add(t)});
|
|
2557
2660
|
var q=p.get('q');
|
|
2558
2661
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
2559
2662
|
if(q){
|
|
@@ -2566,8 +2669,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2566
2669
|
applyFilters();
|
|
2567
2670
|
});
|
|
2568
2671
|
}
|
|
2569
|
-
if(activeTags.size>0||activeReasons.size>0)renderActiveChips();
|
|
2570
|
-
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0)applyFilters();
|
|
2672
|
+
if(activeTags.size>0||activeReasons.size>0||activeTriage.size>0)renderActiveChips();
|
|
2673
|
+
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0)applyFilters();
|
|
2571
2674
|
})();
|
|
2572
2675
|
|
|
2573
2676
|
// 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>
|
|
@@ -1695,7 +1722,7 @@ function renderHtml(report, triage, outputDir) {
|
|
|
1695
1722
|
</div>
|
|
1696
1723
|
</div>
|
|
1697
1724
|
${test.plan ? `<span class="inline-reason" style="color:${reasonCfg(test.plan.plan.failureReason).color}" title="${esc(test.plan.plan.failureReason)}">${esc(reasonCfg(test.plan.plan.failureReason).label)}</span>` : ''}
|
|
1698
|
-
${test.tags.map((t) => `<span class="test-tag">${esc(t)}</span>`).join('')}
|
|
1725
|
+
${test.tags.map((t) => `<span class="test-tag" data-copy-tag="${esc(t)}" title="Click to copy"><span class="tag-label">${esc(t)}</span><span class="tag-copy-glyph"><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></span></span>`).join('')}
|
|
1699
1726
|
${totalStepCount > 0 ? `<span class="test-step-count" title="${totalStepCount} steps">${totalStepCount} steps</span>` : ''}
|
|
1700
1727
|
<span class="test-duration">${fmtDuration(totalTestDuration)}</span>
|
|
1701
1728
|
</div>
|
|
@@ -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}
|
|
@@ -1842,7 +1870,13 @@ body::before{content:'';position:fixed;top:-750px;left:50%;transform:translateX(
|
|
|
1842
1870
|
.copy-flow-id .check-icon{color:#22c55e}
|
|
1843
1871
|
.inline-reason{font-size:11px;font-weight:500;flex-shrink:0;padding:1px 8px;border-radius:4px;background:var(--overlay-light)}
|
|
1844
1872
|
.test-step-count{font-size:11px;color:var(--text-dim);flex-shrink:0;font-family:var(--mono);padding:2px 8px;background:rgba(255,255,255,.04);border-radius:4px}
|
|
1845
|
-
.test-tag{font-size:11px;color:var(--accent);flex-shrink:0;font-family:var(--mono);padding:2px 8px;background:rgba(255,127,58,.08);border:1px solid rgba(255,127,58,.2);border-radius:4px}
|
|
1873
|
+
.test-tag{font-size:11px;color:var(--accent);flex-shrink:0;font-family:var(--mono);padding:2px 8px;background:rgba(255,127,58,.08);border:1px solid rgba(255,127,58,.2);border-radius:4px;cursor:pointer;display:inline-flex;align-items:center;transition:background .15s,border-color .15s}
|
|
1874
|
+
.test-tag:hover{background:rgba(255,127,58,.16);border-color:rgba(255,127,58,.45)}
|
|
1875
|
+
.tag-copy-glyph{display:inline-flex;align-items:center;width:0;margin-left:0;opacity:0;overflow:hidden;transition:width .15s,opacity .15s,margin-left .15s}
|
|
1876
|
+
.test-tag:hover .tag-copy-glyph,.test-tag.copied .tag-copy-glyph{width:11px;margin-left:4px;opacity:.75}
|
|
1877
|
+
.tag-copy-glyph svg{width:11px;height:11px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
|
|
1878
|
+
.test-tag.copied{color:#22c55e;border-color:rgba(34,197,94,.45);background:rgba(34,197,94,.12)}
|
|
1879
|
+
.test-tag.copied .tag-copy-glyph{opacity:1}
|
|
1846
1880
|
.test-duration{font-size:12px;color:var(--text-dim);flex-shrink:0;font-family:var(--mono)}
|
|
1847
1881
|
.flow-id-detail{display:flex;align-items:center;gap:10px;margin-bottom:4px;padding:8px 12px;background:var(--surface-raised);border:1px solid var(--border-subtle);border-radius:var(--radius)}
|
|
1848
1882
|
.flow-id-detail .detail-label{margin-bottom:0;font-size:10px;letter-spacing:.8px}
|
|
@@ -2163,7 +2197,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2163
2197
|
</label>
|
|
2164
2198
|
<div class="tag-filter-controls" data-tag-filter-controls hidden>
|
|
2165
2199
|
<div class="tag-filter-trigger-wrap">
|
|
2166
|
-
<button class="add-tag-filter" data-add-tag-filter title="Filter by tag or
|
|
2200
|
+
<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
2201
|
<div class="tag-menu" data-tag-menu hidden></div>
|
|
2168
2202
|
</div>
|
|
2169
2203
|
<div class="active-tag-filters" data-active-tag-filters></div>
|
|
@@ -2191,16 +2225,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2191
2225
|
// tags — multi-select AND; card must carry every active tag.
|
|
2192
2226
|
// reasons — multi-select OR; card.data-reason must match any active reason
|
|
2193
2227
|
// (a card has at most one diagnosis, so AND would always be 0/1).
|
|
2194
|
-
//
|
|
2228
|
+
// triage — multi-select OR; card.data-triage (a comma list) must contain
|
|
2229
|
+
// any active flag (a card can carry several triage flags).
|
|
2230
|
+
// "Clear Filters" wipes all of them.
|
|
2195
2231
|
var activeStatus=null;
|
|
2196
2232
|
var activeTags=new Set();
|
|
2197
2233
|
var activeReasons=new Set();
|
|
2234
|
+
var activeTriage=new Set();
|
|
2198
2235
|
var activeSearch=''; // lowercase substring match against data-search
|
|
2199
2236
|
var allTags=[];
|
|
2200
2237
|
var allReasons=[]; // ordered list of REASON keys present in the report
|
|
2238
|
+
var allTriage=[]; // ordered list of TRIAGE keys present in the report
|
|
2201
2239
|
var REASON_LABELS=${JSON.stringify(REASON_LABELS)};
|
|
2240
|
+
var TRIAGE_LABELS=${JSON.stringify(TRIAGE_LABELS)};
|
|
2202
2241
|
|
|
2203
2242
|
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 []}}
|
|
2243
|
+
function cardTriage(card){var raw=card.getAttribute('data-triage');return raw?raw.split(','):[]}
|
|
2204
2244
|
|
|
2205
2245
|
// Faceted-search counts. Each filter option's badge shows "how many tests
|
|
2206
2246
|
// would this option contribute given the rest of the filters." The semantics
|
|
@@ -2208,8 +2248,9 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2208
2248
|
// - Status pills (single-select replace): ignore current activeStatus.
|
|
2209
2249
|
// - Tag menu items (multi-select AND): use ALL current filters.
|
|
2210
2250
|
// - Reason menu items (multi-select OR): ignore current activeReasons.
|
|
2251
|
+
// - Triage menu items (multi-select OR): ignore current activeTriage.
|
|
2211
2252
|
// Search is free-form and not counted.
|
|
2212
|
-
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons){
|
|
2253
|
+
function cardsMatching(ignoreStatus,ignoreTags,ignoreReasons,ignoreTriage){
|
|
2213
2254
|
var out=[];
|
|
2214
2255
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2215
2256
|
var statusOk=ignoreStatus||activeStatus===null||card.getAttribute('data-status')===activeStatus;
|
|
@@ -2219,19 +2260,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2219
2260
|
activeTags.forEach(function(w){if(t.indexOf(w)===-1)tagsOk=false});
|
|
2220
2261
|
}
|
|
2221
2262
|
var reasonOk=ignoreReasons||activeReasons.size===0||activeReasons.has(card.getAttribute('data-reason')||'');
|
|
2263
|
+
var triageOk=true;
|
|
2264
|
+
if(!ignoreTriage&&activeTriage.size>0){
|
|
2265
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2266
|
+
}
|
|
2222
2267
|
var searchOk=activeSearch.length===0||(card.getAttribute('data-search')||'').indexOf(activeSearch)!==-1;
|
|
2223
|
-
if(statusOk&&tagsOk&&reasonOk&&searchOk)out.push(card);
|
|
2268
|
+
if(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk)out.push(card);
|
|
2224
2269
|
});
|
|
2225
2270
|
return out;
|
|
2226
2271
|
}
|
|
2227
2272
|
function tagCount(t){
|
|
2228
|
-
var pool=cardsMatching(false,false,false);
|
|
2273
|
+
var pool=cardsMatching(false,false,false,false);
|
|
2229
2274
|
var n=0;for(var i=0;i<pool.length;i++){if(cardTags(pool[i]).indexOf(t)!==-1)n++}
|
|
2230
2275
|
return n;
|
|
2231
2276
|
}
|
|
2232
2277
|
|
|
2233
2278
|
function applyFilters(){
|
|
2234
|
-
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0;
|
|
2279
|
+
var anyActive=activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0;
|
|
2235
2280
|
document.querySelector('.clear-filter').classList.toggle('visible',anyActive);
|
|
2236
2281
|
var visibleTests=0;
|
|
2237
2282
|
var visibleFiles=Object.create(null);
|
|
@@ -2247,12 +2292,16 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2247
2292
|
var r=card.getAttribute('data-reason')||'';
|
|
2248
2293
|
reasonOk=activeReasons.has(r);
|
|
2249
2294
|
}
|
|
2295
|
+
var triageOk=true;
|
|
2296
|
+
if(activeTriage.size>0){
|
|
2297
|
+
var ct=cardTriage(card);triageOk=ct.some(function(k){return activeTriage.has(k)});
|
|
2298
|
+
}
|
|
2250
2299
|
var searchOk=true;
|
|
2251
2300
|
if(activeSearch.length>0){
|
|
2252
2301
|
var hay=card.getAttribute('data-search')||'';
|
|
2253
2302
|
searchOk=hay.indexOf(activeSearch)!==-1;
|
|
2254
2303
|
}
|
|
2255
|
-
var hide=!(statusOk&&tagsOk&&reasonOk&&searchOk);
|
|
2304
|
+
var hide=!(statusOk&&tagsOk&&reasonOk&&triageOk&&searchOk);
|
|
2256
2305
|
card.classList.toggle('hidden-by-filter',hide);
|
|
2257
2306
|
if(!hide){
|
|
2258
2307
|
visibleTests++;
|
|
@@ -2295,6 +2344,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2295
2344
|
if(activeStatus)p.set('status',activeStatus);
|
|
2296
2345
|
activeTags.forEach(function(t){p.append('tag',t)});
|
|
2297
2346
|
activeReasons.forEach(function(r){p.append('reason',r)});
|
|
2347
|
+
activeTriage.forEach(function(t){p.append('triage',t)});
|
|
2298
2348
|
if(activeSearch)p.set('q',activeSearch);
|
|
2299
2349
|
var qs=p.toString();
|
|
2300
2350
|
var next=location.pathname+(qs?'?'+qs:'')+(location.hash||'');
|
|
@@ -2340,19 +2390,37 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2340
2390
|
chip.appendChild(label);chip.appendChild(btn);
|
|
2341
2391
|
c.appendChild(chip);
|
|
2342
2392
|
});
|
|
2393
|
+
activeTriage.forEach(function(t){
|
|
2394
|
+
var meta=TRIAGE_LABELS[t];if(!meta)return;
|
|
2395
|
+
var chip=document.createElement('span');chip.className='tag-chip reason-chip';
|
|
2396
|
+
chip.style.background=hexToRgba(meta.color,0.14);
|
|
2397
|
+
chip.style.borderColor=hexToRgba(meta.color,0.4);
|
|
2398
|
+
chip.style.color=meta.color;
|
|
2399
|
+
var label=document.createElement('span');label.textContent=meta.label;
|
|
2400
|
+
var btn=document.createElement('button');btn.className='tag-chip-remove';btn.setAttribute('data-remove-triage',t);btn.setAttribute('title','Remove filter');btn.textContent='×';
|
|
2401
|
+
chip.appendChild(label);chip.appendChild(btn);
|
|
2402
|
+
c.appendChild(chip);
|
|
2403
|
+
});
|
|
2343
2404
|
}
|
|
2344
2405
|
function addTag(t){if(!t||activeTags.has(t))return;activeTags.add(t);renderActiveChips();applyFilters()}
|
|
2345
2406
|
function removeTag(t){if(!activeTags.delete(t))return;renderActiveChips();applyFilters()}
|
|
2346
2407
|
function addReason(r){if(!r||activeReasons.has(r))return;activeReasons.add(r);renderActiveChips();applyFilters()}
|
|
2347
2408
|
function removeReason(r){if(!activeReasons.delete(r))return;renderActiveChips();applyFilters()}
|
|
2409
|
+
function addTriage(t){if(!t||activeTriage.has(t))return;activeTriage.add(t);renderActiveChips();applyFilters()}
|
|
2410
|
+
function removeTriage(t){if(!activeTriage.delete(t))return;renderActiveChips();applyFilters()}
|
|
2348
2411
|
|
|
2349
2412
|
function reasonCount(r){
|
|
2350
|
-
var pool=cardsMatching(false,false,true);
|
|
2413
|
+
var pool=cardsMatching(false,false,true,false);
|
|
2351
2414
|
var n=0;for(var i=0;i<pool.length;i++){if(pool[i].getAttribute('data-reason')===r)n++}
|
|
2352
2415
|
return n;
|
|
2353
2416
|
}
|
|
2417
|
+
function triageCount(t){
|
|
2418
|
+
var pool=cardsMatching(false,false,false,true);
|
|
2419
|
+
var n=0;for(var i=0;i<pool.length;i++){if(cardTriage(pool[i]).indexOf(t)!==-1)n++}
|
|
2420
|
+
return n;
|
|
2421
|
+
}
|
|
2354
2422
|
function updateStatPillCounts(){
|
|
2355
|
-
var pool=cardsMatching(true,false,false);
|
|
2423
|
+
var pool=cardsMatching(true,false,false,false);
|
|
2356
2424
|
var counts=Object.create(null);
|
|
2357
2425
|
for(var i=0;i<pool.length;i++){var s=pool[i].getAttribute('data-status');counts[s]=(counts[s]||0)+1}
|
|
2358
2426
|
document.querySelectorAll('.stat-pill[data-filter]').forEach(function(pill){
|
|
@@ -2372,9 +2440,11 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2372
2440
|
// to an empty view, so they're not useful to offer.
|
|
2373
2441
|
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
2442
|
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});
|
|
2443
|
+
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
2444
|
var added=false;
|
|
2376
2445
|
if(allTags.length>0){
|
|
2377
2446
|
var hT=document.createElement('div');hT.className='tag-menu-section';hT.textContent='Tags';menu.appendChild(hT);
|
|
2447
|
+
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
2448
|
if(tagsWithCounts.length===0){
|
|
2379
2449
|
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
2450
|
}else{
|
|
@@ -2390,6 +2460,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2390
2460
|
}
|
|
2391
2461
|
if(allReasons.length>0){
|
|
2392
2462
|
var hR=document.createElement('div');hR.className='tag-menu-section';hR.textContent='Diagnoses';menu.appendChild(hR);
|
|
2463
|
+
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
2464
|
if(reasonsWithCounts.length===0){
|
|
2394
2465
|
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
2466
|
}else{
|
|
@@ -2404,6 +2475,23 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2404
2475
|
}
|
|
2405
2476
|
added=true;
|
|
2406
2477
|
}
|
|
2478
|
+
if(allTriage.length>0){
|
|
2479
|
+
var hTr=document.createElement('div');hTr.className='tag-menu-section';hTr.textContent='Triage';menu.appendChild(hTr);
|
|
2480
|
+
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);
|
|
2481
|
+
if(triageWithCounts.length===0){
|
|
2482
|
+
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);
|
|
2483
|
+
}else{
|
|
2484
|
+
triageWithCounts.forEach(function(x){
|
|
2485
|
+
var meta=TRIAGE_LABELS[x.key];if(!meta)return;
|
|
2486
|
+
var item=document.createElement('button');item.className='tag-menu-item';item.setAttribute('data-triage-menu-item',x.key);
|
|
2487
|
+
var label=document.createElement('span');label.textContent=meta.label;label.style.color=meta.color;
|
|
2488
|
+
var count=document.createElement('span');count.className='tag-menu-count';count.textContent=x.count;
|
|
2489
|
+
item.appendChild(label);item.appendChild(count);
|
|
2490
|
+
menu.appendChild(item);
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
added=true;
|
|
2494
|
+
}
|
|
2407
2495
|
if(!added){
|
|
2408
2496
|
var empty=document.createElement('div');empty.className='tag-menu-empty';empty.textContent='No filters available';menu.appendChild(empty);
|
|
2409
2497
|
}
|
|
@@ -2421,6 +2509,7 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2421
2509
|
activeStatus=null;
|
|
2422
2510
|
activeTags.clear();
|
|
2423
2511
|
activeReasons.clear();
|
|
2512
|
+
activeTriage.clear();
|
|
2424
2513
|
activeSearch='';
|
|
2425
2514
|
document.querySelectorAll('.stat-pill').forEach(function(p){p.classList.remove('active')});
|
|
2426
2515
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
@@ -2457,6 +2546,10 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2457
2546
|
// Copy buttons (flow ID + JSON + inline text via data-copy-text)
|
|
2458
2547
|
var copyTextBtn=e.target.closest('.copy-text[data-copy-text]');
|
|
2459
2548
|
if(copyTextBtn){e.stopPropagation();e.preventDefault();navigator.clipboard.writeText(copyTextBtn.getAttribute('data-copy-text'));var copyTextSvg=copyTextBtn.innerHTML;copyTextBtn.innerHTML='<svg class="check-icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';setTimeout(function(){copyTextBtn.innerHTML=copyTextSvg},2000);return}
|
|
2549
|
+
// Tag chip: click anywhere on the chip copies its tag text. The hover glyph
|
|
2550
|
+
// briefly becomes a check; stopPropagation keeps the card from expanding.
|
|
2551
|
+
var tagChip=e.target.closest('.test-tag[data-copy-tag]');
|
|
2552
|
+
if(tagChip){e.stopPropagation();navigator.clipboard.writeText(tagChip.getAttribute('data-copy-tag'));var glyph=tagChip.querySelector('.tag-copy-glyph');if(glyph){var glyphSvg=glyph.innerHTML;glyph.innerHTML='<svg class="check-icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';tagChip.classList.add('copied');setTimeout(function(){glyph.innerHTML=glyphSvg;tagChip.classList.remove('copied')},1500)}return}
|
|
2460
2553
|
var flowBtn=e.target.closest('.copy-flow-id');
|
|
2461
2554
|
if(flowBtn){e.stopPropagation();navigator.clipboard.writeText(flowBtn.getAttribute('data-flow-id'));var copySvg=flowBtn.innerHTML;flowBtn.innerHTML='<svg class="check-icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';setTimeout(function(){flowBtn.innerHTML=copySvg},2000);return}
|
|
2462
2555
|
var jsonBtn=e.target.closest('.copy-json');
|
|
@@ -2470,10 +2563,14 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2470
2563
|
if(tagItem){addTag(tagItem.getAttribute('data-tag-menu-item'));closeTagMenu();return}
|
|
2471
2564
|
var reasonItem=e.target.closest('[data-reason-menu-item]');
|
|
2472
2565
|
if(reasonItem){addReason(reasonItem.getAttribute('data-reason-menu-item'));closeTagMenu();return}
|
|
2566
|
+
var triageItem=e.target.closest('[data-triage-menu-item]');
|
|
2567
|
+
if(triageItem){addTriage(triageItem.getAttribute('data-triage-menu-item'));closeTagMenu();return}
|
|
2473
2568
|
var tagRemove=e.target.closest('[data-remove-tag]');
|
|
2474
2569
|
if(tagRemove){removeTag(tagRemove.getAttribute('data-remove-tag'));return}
|
|
2475
2570
|
var reasonRemove=e.target.closest('[data-remove-reason]');
|
|
2476
2571
|
if(reasonRemove){removeReason(reasonRemove.getAttribute('data-remove-reason'));return}
|
|
2572
|
+
var triageRemove=e.target.closest('[data-remove-triage]');
|
|
2573
|
+
if(triageRemove){removeTriage(triageRemove.getAttribute('data-remove-triage'));return}
|
|
2477
2574
|
// Stat pill filter
|
|
2478
2575
|
var pill=e.target.closest('.stat-pill[data-filter]');
|
|
2479
2576
|
if(pill){toggleStatus(pill.getAttribute('data-filter'));return}
|
|
@@ -2523,18 +2620,22 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2523
2620
|
(function(){
|
|
2524
2621
|
var seenTags=Object.create(null);
|
|
2525
2622
|
var seenReasons=Object.create(null);
|
|
2623
|
+
var seenTriage=Object.create(null);
|
|
2526
2624
|
document.querySelectorAll('.test-card').forEach(function(card){
|
|
2527
2625
|
var raw=card.getAttribute('data-tags');
|
|
2528
2626
|
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
2627
|
var r=card.getAttribute('data-reason');
|
|
2530
2628
|
if(r)seenReasons[r]=true;
|
|
2629
|
+
cardTriage(card).forEach(function(t){if(t)seenTriage[t]=true});
|
|
2531
2630
|
});
|
|
2532
2631
|
allTags=Object.keys(seenTags).sort();
|
|
2533
2632
|
// Preserve the REASON_LABELS declaration order rather than alphabetical —
|
|
2534
2633
|
// they're already arranged from most-frequent/specific to UNKNOWN catch-all.
|
|
2535
2634
|
allReasons=Object.keys(REASON_LABELS).filter(function(r){return seenReasons[r]});
|
|
2635
|
+
// Preserve TRIAGE_LABELS declaration order (retryable → code → product).
|
|
2636
|
+
allTriage=Object.keys(TRIAGE_LABELS).filter(function(t){return seenTriage[t]});
|
|
2536
2637
|
var controls=document.querySelector('[data-tag-filter-controls]');
|
|
2537
|
-
if(controls&&(allTags.length>0||allReasons.length>0))controls.hidden=false;
|
|
2638
|
+
if(controls&&(allTags.length>0||allReasons.length>0||allTriage.length>0))controls.hidden=false;
|
|
2538
2639
|
})();
|
|
2539
2640
|
|
|
2540
2641
|
// Seed filter state from ?status=...&tag=...&reason=... so shared URLs
|
|
@@ -2554,6 +2655,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2554
2655
|
p.getAll('tag').forEach(function(t){if(tagSet[t])activeTags.add(t)});
|
|
2555
2656
|
var reasonSet={};allReasons.forEach(function(r){reasonSet[r]=true});
|
|
2556
2657
|
p.getAll('reason').forEach(function(r){if(reasonSet[r])activeReasons.add(r)});
|
|
2658
|
+
var triageSet={};allTriage.forEach(function(t){triageSet[t]=true});
|
|
2659
|
+
p.getAll('triage').forEach(function(t){if(triageSet[t])activeTriage.add(t)});
|
|
2557
2660
|
var q=p.get('q');
|
|
2558
2661
|
var searchInput=document.querySelector('[data-filter-search]');
|
|
2559
2662
|
if(q){
|
|
@@ -2566,8 +2669,8 @@ details.ai-invocation[open]>summary .native-step-chevron{transform:rotate(90deg)
|
|
|
2566
2669
|
applyFilters();
|
|
2567
2670
|
});
|
|
2568
2671
|
}
|
|
2569
|
-
if(activeTags.size>0||activeReasons.size>0)renderActiveChips();
|
|
2570
|
-
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeSearch.length>0)applyFilters();
|
|
2672
|
+
if(activeTags.size>0||activeReasons.size>0||activeTriage.size>0)renderActiveChips();
|
|
2673
|
+
if(activeStatus!==null||activeTags.size>0||activeReasons.size>0||activeTriage.size>0||activeSearch.length>0)applyFilters();
|
|
2571
2674
|
})();
|
|
2572
2675
|
|
|
2573
2676
|
// Open #?testId=<id> deep links to the matching test card. Used by the
|