Skip to content

feat(ui): upgrade dashboard UX with filters and scan trend insights#24

Merged
root-Manas merged 1 commit intomainfrom
pr/24-web-ui-polish
Mar 29, 2026
Merged

feat(ui): upgrade dashboard UX with filters and scan trend insights#24
root-Manas merged 1 commit intomainfrom
pr/24-web-ui-polish

Conversation

@root-Manas
Copy link
Copy Markdown
Owner

Summary

  • add mode chips for fast scan filtering (all/wide/fast/narrow/deep/osint)
  • add scan health/status badges and a URL yield trend panel in overview
  • improve list empty state and keep filter state during refresh
  • add subtle fade/grow animations for a cleaner security-console feel

Validation

  • go test ./...
  • go build ./...

Copilot AI review requested due to automatic review settings March 29, 2026 07:02
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the embedded dashboard UI to make scan discovery and at-a-glance status insights faster, adding mode-based filtering and a lightweight “trend” view alongside scan overview details.

Changes:

  • Added mode “chip” filters + updated search handling to persist filter state across refreshes.
  • Added scan status badges (last finished, duration, health) and a “Recent URL Yield Trend” panel.
  • Added small UI animations (fade-in list items, grow animation for trend bars) and improved empty state messaging.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +435 to +442
function trendRows(currentId) {
const recent = scans.slice(0, 12);
const max = Math.max(...recent.map(s => s.stats.urls || 0), 1);
return recent.map(s => {
const width = Math.max(4, Math.round(((s.stats.urls || 0) / max) * 100));
const marker = s.id === currentId ? ' <b>(selected)</b>' : '';
return `<div class="trend-item"><span>${s.target}</span><span class="spark"><span class="spark-fill" style="width:${width}%"></span></span><span>${s.stats.urls || 0}${marker}</span></div>`;
}).join('');
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trendRows() injects s.target directly into innerHTML without escaping. Since target originates from stored scan data, this allows HTML/script injection into the dashboard if a scan target contains markup. Escape s.target (and any other string fields rendered here) before interpolating, or build DOM nodes with textContent instead of concatenating HTML strings.

Copilot uses AI. Check for mistakes.
Comment on lines +380 to +383
if (!items.length) {
root.innerHTML = `<div class="muted mono">No scans match current filters.</div>`;
return;
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When filters reduce the list to zero (or exclude the currently selected activeId), renderScanList() returns early without reconciling activeId/detail view. This can leave the detail panel showing a scan that isn’t present in the filtered list and no item highlighted. Consider clearing activeId (and resetting the detail panel) when items is empty, and when activeId is not found in items, auto-select the first filtered item (or keep selection only if it’s still visible).

Suggested change
if (!items.length) {
root.innerHTML = `<div class="muted mono">No scans match current filters.</div>`;
return;
}
if (!items.length) {
// No items match the current filters: clear selection and detail view.
activeId = null;
root.innerHTML = `<div class="muted mono">No scans match current filters.</div>`;
const detailRoot = document.getElementById('scanDetail');
if (detailRoot) {
detailRoot.innerHTML = '';
}
return;
}
// If there is an activeId but it is no longer in the filtered items, select the first item.
if (activeId) {
const stillVisible = items.some(s => String(s.id) === String(activeId));
if (!stillVisible && items[0]) {
activeId = items[0].id;
// Ensure detail view points to a visible item.
loadResult(activeId);
}
}

Copilot uses AI. Check for mistakes.
@root-Manas root-Manas merged commit d1d9416 into main Mar 29, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants