Skip to content

Commit a68fa19

Browse files
authored
Merge pull request #9 from knktc:feature-add-purge-button
add clear requests functionality with confirmation prompt
2 parents 13ba7c8 + bd4d269 commit a68fa19

2 files changed

Lines changed: 115 additions & 45 deletions

File tree

main.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ func handler(w http.ResponseWriter, r *http.Request) {
108108
return
109109
}
110110

111+
if r.URL.Path == "/api/requests/clear" {
112+
clearRequestsHandler(w, r)
113+
return
114+
}
115+
111116
// If it's the root path, display the main panel.
112117
if r.URL.Path == "/" {
113118
mainPageHandler(w, r)
@@ -214,6 +219,22 @@ func apiRequestsHandler(w http.ResponseWriter, r *http.Request) {
214219
}
215220
}
216221

222+
// clearRequestsHandler clears all captured requests.
223+
func clearRequestsHandler(w http.ResponseWriter, r *http.Request) {
224+
if r.Method != http.MethodPost {
225+
w.Header().Set("Allow", http.MethodPost)
226+
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
227+
return
228+
}
229+
230+
mutex.Lock()
231+
requestsStore = make(map[int]RequestInfo)
232+
requestIDs = nil
233+
mutex.Unlock()
234+
235+
w.WriteHeader(http.StatusNoContent)
236+
}
237+
217238
// captureRequestHandler captures the details of the incoming request and stores it.
218239
func captureRequestHandler(w http.ResponseWriter, r *http.Request) {
219240
// Read the request body.

templates/main.tmpl

Lines changed: 94 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
'auto_refresh': 'Auto Refresh',
1515
'seconds': 'seconds',
1616
'refresh': 'Refresh',
17+
'clear_requests': 'Clear',
18+
'confirm': 'Confirm',
19+
'clear_confirm': 'Clear all captured requests?',
1720
'captured_requests': 'Captured Requests',
1821
'no_requests': 'No requests captured yet.',
1922
'welcome_title': 'Welcome!',
@@ -36,6 +39,9 @@
3639
'auto_refresh': '自动刷新',
3740
'seconds': '秒',
3841
'refresh': '刷新',
42+
'clear_requests': '清空',
43+
'confirm': '确定',
44+
'clear_confirm': '确定清空所有已捕获的请求?',
3945
'captured_requests': '已捕获的请求',
4046
'no_requests': '尚未捕获任何请求。',
4147
'welcome_title': '欢迎!',
@@ -108,12 +114,6 @@
108114
</div>
109115
<div class="w-1/3 flex justify-end items-center pr-4">
110116
<div class="flex items-center space-x-2">
111-
<button id="manualRefreshButton" class="hidden px-3 py-1 text-sm bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors" data-i18n-title="refresh_requests">
112-
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
113-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
114-
</svg>
115-
<span data-i18n="refresh">刷新</span>
116-
</button>
117117
<input type="checkbox" id="autoRefreshCheckbox" class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
118118
<label for="autoRefreshCheckbox" class="text-sm text-gray-600" data-i18n="auto_refresh">自动刷新</label>
119119
<input type="number" id="refreshIntervalInput" class="w-16 text-sm border-gray-300 rounded-md shadow-sm" min="1" value="5">
@@ -125,8 +125,23 @@
125125
<div class="flex flex-1 overflow-hidden">
126126
<!-- Left Column: Request List -->
127127
<aside class="w-1/3 bg-white border-r flex flex-col">
128-
<div class="p-4 border-b">
128+
<div class="p-4 border-b flex items-center justify-between gap-3">
129129
<h2 class="text-lg font-semibold" data-i18n="captured_requests">已捕获的请求</h2>
130+
<div class="flex items-center gap-2">
131+
<button id="clearRequestsButton" class="px-3 py-1.5 text-xs font-semibold text-red-700 bg-red-50 border border-red-200 rounded-md hover:bg-red-100 hover:border-red-300 transition-colors flex items-center gap-1.5">
132+
<svg class="w-3.5 h-3.5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
133+
<path d="M8.5 2a1 1 0 00-1 1v1H4.75a.75.75 0 000 1.5h10.5a.75.75 0 000-1.5H12.5V3a1 1 0 00-1-1h-3z" />
134+
<path d="M6 7.25a.75.75 0 01.75-.75h6.5a.75.75 0 01.75.75v7.25a2 2 0 01-2 2h-4a2 2 0 01-2-2V7.25z" />
135+
</svg>
136+
<span data-i18n="clear_requests">清理</span>
137+
</button>
138+
<button id="listRefreshButton" class="px-3 py-1.5 text-xs font-semibold text-white bg-blue-600 border border-blue-600 rounded-md hover:bg-blue-700 transition-colors flex items-center gap-1.5">
139+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
140+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
141+
</svg>
142+
<span data-i18n="refresh">刷新</span>
143+
</button>
144+
</div>
130145
</div>
131146
<div class="overflow-y-auto flex-1">
132147
{{if .AllRequests}}
@@ -268,7 +283,8 @@
268283
// --- Auto-refresh logic ---
269284
const checkbox = document.getElementById('autoRefreshCheckbox');
270285
const intervalInput = document.getElementById('refreshIntervalInput');
271-
const manualRefreshButton = document.getElementById('manualRefreshButton');
286+
const clearRequestsButton = document.getElementById('clearRequestsButton');
287+
const listRefreshButton = document.getElementById('listRefreshButton');
272288
let refreshInterval;
273289

274290
// --- Pagination controls ---
@@ -292,13 +308,6 @@
292308
refreshInterval = null;
293309
}
294310

295-
function toggleManualRefreshButton() {
296-
if (checkbox.checked) {
297-
manualRefreshButton.classList.add('hidden');
298-
} else {
299-
manualRefreshButton.classList.remove('hidden');
300-
}
301-
}
302311

303312
// Function to update pagination info
304313
function updatePaginationInfo(data) {
@@ -430,36 +439,77 @@
430439
toggleManualRefreshButton();
431440
});
432441

433-
// Manual refresh button click handler
434-
let isRefreshing = false;
435-
const originalButtonContent = `
436-
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
437-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
438-
</svg>
439-
<span data-i18n="refresh">${translations[currentLang]['refresh']}</span>
440-
`;
441-
442-
function resetButtonState() {
443-
manualRefreshButton.innerHTML = originalButtonContent;
444-
isRefreshing = false;
442+
443+
if (clearRequestsButton) {
444+
let isConfirmingClear = false;
445+
let clearConfirmTimer = null;
446+
const clearOriginalClasses = clearRequestsButton.className;
447+
const clearOriginalLabel = clearRequestsButton.innerHTML;
448+
449+
const resetClearButton = () => {
450+
isConfirmingClear = false;
451+
clearRequestsButton.className = clearOriginalClasses;
452+
clearRequestsButton.innerHTML = clearOriginalLabel;
453+
if (clearConfirmTimer) {
454+
clearTimeout(clearConfirmTimer);
455+
clearConfirmTimer = null;
456+
}
457+
};
458+
459+
clearRequestsButton.addEventListener('click', async () => {
460+
if (clearRequestsButton.disabled) return;
461+
462+
if (!isConfirmingClear) {
463+
isConfirmingClear = true;
464+
clearRequestsButton.className = 'px-3 py-1.5 text-xs font-semibold text-white bg-red-600 border border-red-600 rounded-md hover:bg-red-700 transition-colors flex items-center gap-1.5';
465+
clearRequestsButton.innerHTML = `
466+
<svg class="w-3.5 h-3.5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
467+
<path fill-rule="evenodd" d="M16.704 6.29a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0l-3.25-3.25a.75.75 0 111.06-1.06l2.72 2.72 6.72-6.72a.75.75 0 011.06 0z" clip-rule="evenodd" />
468+
</svg>
469+
<span data-i18n="confirm">${translations[currentLang]['confirm']}</span>
470+
`;
471+
clearConfirmTimer = setTimeout(resetClearButton, 2500);
472+
return;
473+
}
474+
475+
clearRequestsButton.disabled = true;
476+
clearRequestsButton.classList.add('opacity-60', 'cursor-not-allowed');
477+
478+
try {
479+
const response = await fetch('/api/requests/clear', { method: 'POST' });
480+
if (!response.ok) {
481+
throw new Error('clear_failed');
482+
}
483+
window.location.href = '/';
484+
} catch (error) {
485+
console.error('Error clearing requests:', error);
486+
clearRequestsButton.disabled = false;
487+
clearRequestsButton.classList.remove('opacity-60', 'cursor-not-allowed');
488+
resetClearButton();
489+
}
490+
});
491+
}
492+
493+
if (listRefreshButton) {
494+
listRefreshButton.addEventListener('click', () => {
495+
if (isUpdating) return;
496+
const refreshIcon = listRefreshButton.querySelector('svg');
497+
listRefreshButton.disabled = true;
498+
listRefreshButton.classList.add('opacity-70', 'cursor-not-allowed');
499+
if (refreshIcon) {
500+
refreshIcon.classList.add('animate-spin');
501+
}
502+
Promise.resolve(updateRequestList())
503+
.catch(() => {})
504+
.finally(() => {
505+
if (refreshIcon) {
506+
refreshIcon.classList.remove('animate-spin');
507+
}
508+
listRefreshButton.disabled = false;
509+
listRefreshButton.classList.remove('opacity-70', 'cursor-not-allowed');
510+
});
511+
});
445512
}
446-
447-
manualRefreshButton.addEventListener('click', () => {
448-
if (isRefreshing) return; // Prevent multiple clicks
449-
450-
isRefreshing = true;
451-
updateRequestList();
452-
453-
// Add visual feedback
454-
manualRefreshButton.innerHTML = `
455-
<svg class="w-4 h-4 inline mr-1 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
456-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
457-
</svg>
458-
<span data-i18n="refresh">${translations[currentLang]['refresh']}</span>
459-
`;
460-
461-
setTimeout(resetButtonState, 500);
462-
});
463513

464514
intervalInput.addEventListener('change', () => {
465515
let interval = parseInt(intervalInput.value, 10);
@@ -480,7 +530,6 @@
480530
if (isEnabled) {
481531
startRefresh();
482532
}
483-
toggleManualRefreshButton(); // Initialize manual refresh button visibility
484533

485534
// Initialize pagination and request list
486535
updateRequestList();

0 commit comments

Comments
 (0)