Skip to content

Commit 5f7e773

Browse files
tsemachhjunie-agent
andcommitted
feat(popup): reorder table (Status 2nd, Path flex), merge hits into status, live update on replayStats
Co-authored-by: Junie <junie@jetbrains.com>
1 parent 79da93e commit 5f7e773

4 files changed

Lines changed: 34 additions & 28 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on Keep a Changelog,
66
and this project adheres to Semantic Versioning.
77

8+
## [1.0.16] - 2026-05-03
9+
### Changed
10+
- Captured Requests table column order is now **▶ | Status | Method | ● | Path**, so Status is right after the include toggle and Path expands to fill the remaining width.
11+
- Replay hit count is now shown inside the Status badge as `200 (3)` instead of as a separate column, making the table more compact and clearer.
12+
### Fixed
13+
- Per-row match indicator (●) and hit count now update live during replay. The popup listens to `chrome.storage.session` changes for `replayStats`, so each captured replay hit immediately re-renders the row (previously the table only refreshed on `recordingUpdated`/`newApiCall` messages, which the replayer doesn't send).
14+
815
## [1.0.15] - 2026-05-03
916
### Changed
1017
- Removed the Replay stats panel (Matched / Unmatched / Recent unmatched). The per-row green ● match indicator on the API requests list is now the single source of truth.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "apireplay",
3-
"version": "1.0.15",
3+
"version": "1.0.16",
44
"private": true,
55
"type": "module",
66
"scripts": {

src/popup/components/ApiPreview.ts

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,19 @@ export function renderApiPaths(
2828
<div class="border border-gray-300 dark:border-gray-600 rounded">
2929
<table class="w-full text-xs table-fixed">
3030
<colgroup>
31-
<col style="width: 2.2rem">
32-
<col style="width: 1.4rem">
33-
<col style="width: 3.2rem">
31+
<col style="width: 2rem">
32+
<col style="width: 3.4rem">
33+
<col style="width: 3rem">
34+
<col style="width: 1.2rem">
3435
<col>
35-
<col style="width: 1.6rem">
36-
<col style="width: 1.6rem">
3736
</colgroup>
3837
<thead class="bg-gray-200 dark:bg-gray-800">
3938
<tr>
4039
<th class="text-left p-1" title="Include this request when replaying">▶</th>
41-
<th class="text-left p-1" title="${isReplaying ? 'Green = matched at least once during replay; gray = not yet matched' : 'Match indicator is shown during replay'}">●</th>
40+
<th class="text-left p-1" title="HTTP response status (color-coded). Click to edit. Number in parentheses = replay hits.">Status</th>
4241
<th class="text-left p-1">Method</th>
42+
<th class="text-left p-1" title="${isReplaying ? 'Green = matched at least once during replay; gray = not yet matched' : 'Match indicator is shown during replay'}">●</th>
4343
<th class="text-left p-1">Path</th>
44-
<th class="text-left p-1" title="HTTP response status (color-coded). Click to edit.">St</th>
45-
<th class="text-left p-1" title="Replay hits for this recorded path">#</th>
4644
</tr>
4745
</thead>
4846
<tbody>
@@ -53,7 +51,8 @@ export function renderApiPaths(
5351
const pathWithoutQuery = path.split('?')[0];
5452
const replayCount = requestHitCounts[pathWithoutQuery] || 0;
5553
const statusNum = typeof request.status === 'number' ? request.status : undefined;
56-
const statusText = statusNum !== undefined ? String(statusNum) : '—';
54+
const statusBase = statusNum !== undefined ? String(statusNum) : '—';
55+
const statusText = replayCount > 0 ? `${statusBase} (${replayCount})` : statusBase;
5756
const enabled = request.enabled !== false;
5857
const matchHits = matchedKeys[key] || 0;
5958
const matchColor = !isReplaying
@@ -69,37 +68,28 @@ export function renderApiPaths(
6968
const fullUrlAttr = request.url.replace(/"/g, '&quot;');
7069
const pathAttr = path.replace(/"/g, '&quot;');
7170
const statusTitle = statusNum !== undefined
72-
? `Response status: ${statusNum} (click to edit)`
71+
? replayCount > 0
72+
? `Response status: ${statusNum}${replayCount} replay hit(s) (click to edit)`
73+
: `Response status: ${statusNum} (click to edit)`
7374
: 'No status recorded (click to set)';
74-
const hitsTitle = replayCount > 0
75-
? `${replayCount} replay hit(s) on this path`
76-
: 'No replay hits yet on this path';
77-
const hitsClass = replayCount > 0
78-
? 'bg-green-500 text-white'
79-
: 'bg-gray-300 dark:bg-gray-600 text-gray-700 dark:text-gray-300';
75+
const statusBadgeWidth = statusText.length > 3 ? 'min-w-[2.1rem] px-1' : 'w-7';
8076
return `
8177
<tr class="border-t border-gray-200 dark:border-gray-700${isReplaying && matchHits > 0 ? ' bg-green-50 dark:bg-green-900/20' : ''}">
8278
<td class="p-1">
8379
<input type="checkbox" class="request-enabled-toggle" data-request-key="${encodeURIComponent(key)}" ${enabled ? 'checked' : ''}>
8480
</td>
85-
<td class="p-1 text-center ${matchColor}" title="${matchTitle}">●</td>
86-
<td class="p-1">${request.method}</td>
87-
<td class="p-1 cursor-pointer hover:text-blue-500 truncate" data-path="${pathAttr}" title="${fullUrlAttr}">${path}</td>
88-
<td class="p-1 text-center">
81+
<td class="p-1">
8982
<button
9083
type="button"
91-
class="request-status-icon inline-flex items-center justify-center w-5 h-5 rounded-full text-[9px] font-bold text-white ${statusColorClass(statusNum)}"
84+
class="request-status-icon inline-flex items-center justify-center ${statusBadgeWidth} h-5 rounded-full text-[9px] font-bold text-white whitespace-nowrap ${statusColorClass(statusNum)}"
9285
data-request-key="${encodeURIComponent(key)}"
9386
data-status="${statusNum ?? ''}"
9487
title="${statusTitle}"
9588
>${statusText}</button>
9689
</td>
97-
<td class="p-1 text-center">
98-
<span
99-
class="inline-flex items-center justify-center min-w-[1.1rem] h-5 px-1 rounded-full text-[10px] font-semibold ${hitsClass}"
100-
title="${hitsTitle}"
101-
>${replayCount}</span>
102-
</td>
90+
<td class="p-1">${request.method}</td>
91+
<td class="p-1 text-center ${matchColor}" title="${matchTitle}">●</td>
92+
<td class="p-1 cursor-pointer hover:text-blue-500 truncate" data-path="${pathAttr}" title="${fullUrlAttr}">${path}</td>
10393
</tr>
10494
`;
10595
})

src/popup/main.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,15 @@ document.addEventListener('DOMContentLoaded', () => {
720720
}
721721
});
722722

723+
// Live-refresh the table when replay stats change in session storage so
724+
// the per-row match indicator and hit count update during replay.
725+
chrome.storage.onChanged.addListener((changes, areaName) => {
726+
if (areaName !== 'session') return;
727+
if (!changes.replayStats) return;
728+
if (!recordingSelect.value) return;
729+
updateApiPreview();
730+
});
731+
723732
initRecordingSelect(recordingSelect, document.querySelector('.select-items'), updateApiPreview);
724733

725734
requestSearchInput?.addEventListener('input', () => {

0 commit comments

Comments
 (0)