feat: remove scrape cap; not-found people require explicit confirm-to-remove

This commit is contained in:
James 2026-03-20 00:24:57 -04:00
parent 41d3844a18
commit 5291edfa94
2 changed files with 38 additions and 16 deletions

View File

@ -1643,13 +1643,8 @@ func (h *Handlers) RescrapeOrg(w http.ResponseWriter, r *http.Request) {
return return
} }
const maxPeople = 20
truncated := false
people := scraped.People people := scraped.People
if len(people) > maxPeople { truncated := false // no hard cap — return all found
people = people[:maxPeople]
truncated = true
}
// Diff: existing members keyed by email (lowercased) or name // Diff: existing members keyed by email (lowercased) or name
type MemberStatus struct { type MemberStatus struct {
@ -1704,7 +1699,7 @@ func (h *Handlers) RescrapeOrg(w http.ResponseWriter, r *http.Request) {
"new_people": newPeople, "new_people": newPeople,
"not_found": notFound, "not_found": notFound,
"truncated": truncated, "truncated": truncated,
"total_found": len(scraped.People), "total_found": len(people),
}) })
} }

View File

@ -386,12 +386,10 @@
let title = ''; let title = '';
if (newPeople.length > 0) title = newPeople.length + ' new person' + (newPeople.length !== 1 ? 's' : '') + ' found on website'; if (newPeople.length > 0) title = newPeople.length + ' new person' + (newPeople.length !== 1 ? 's' : '') + ' found on website';
else title = 'No new people found'; else title = 'No new people found';
if (truncated) title += ' (showing first 20 of ' + total + ' — rescrape again for more)';
document.getElementById('rescrapeTitle').textContent = title; document.getElementById('rescrapeTitle').textContent = title;
let html = ''; let html = '';
if (truncated) {
html += '<p class="text-xs text-[#c9a84c] mb-3">⚠️ Only the first 20 results were pulled. You can rescrape again to get additional people.</p>';
}
if (newPeople.length > 0) { if (newPeople.length > 0) {
html += '<div class="mb-3">' html += '<div class="mb-3">'
+ '<div class="flex items-center justify-between mb-2">' + '<div class="flex items-center justify-between mb-2">'
@ -414,13 +412,22 @@
+ '</div>'; + '</div>';
} }
if (notFound.length > 0) { if (notFound.length > 0) {
html += '<div class="pt-3 border-t" style="border-color:var(--ds-bd)"><p class="text-xs font-medium mb-2 text-amber-400">⚠️ These people are in your database but not found on the website — possibly inactive:</p><div class="space-y-1">'; html += '<div class="pt-3 border-t" style="border-color:var(--ds-bd)">'
notFound.forEach(p => { + '<p class="text-xs font-medium mb-1 text-amber-400">⚠️ ' + notFound.length + ' person' + (notFound.length !== 1 ? 's' : '') + ' in your database not found on the website:</p>'
html += '<div class="flex items-center gap-2 text-xs px-3 py-1.5 rounded-lg" style="background:rgba(245,158,11,0.05);border:1px solid rgba(245,158,11,0.15)">' + '<p class="text-xs mb-2" style="color:var(--ds-tx3)">They may have left the organization. Review and remove individually if confirmed.</p>'
+ '<span class="text-[#b0bec5] flex-1 truncate">' + escHtml(p.name || p.email) + (p.title ? ' · ' + escHtml(p.title) : '') + '</span>' + '<div class="space-y-1.5">';
+ '<span class="text-amber-400 shrink-0">Not on site</span></div>'; notFound.forEach((p, i) => {
html += '<div class="flex items-center gap-3 px-3 py-2 rounded-lg" style="background:rgba(245,158,11,0.05);border:1px solid rgba(245,158,11,0.15)">'
+ '<div class="flex-1 min-w-0">'
+ '<div class="text-sm truncate" style="color:var(--ds-tx)">' + escHtml(p.name || p.email) + '</div>'
+ (p.title ? '<div class="text-xs truncate text-amber-400">' + escHtml(p.title) + '</div>' : '')
+ '</div>'
+ '<span class="text-xs text-amber-400 shrink-0 mr-2">Not on site</span>'
+ '<button onclick="confirmRemoveInactive(' + i + ')" class="shrink-0 px-2 py-1 rounded text-xs transition hover:opacity-80" style="background:rgba(239,68,68,0.1);color:#ef4444;border:1px solid rgba(239,68,68,0.2)">Remove</button>'
+ '</div>';
}); });
html += '</div></div>'; html += '</div></div>';
window._rescrapeNotFound = notFound;
} }
if (!html) html = '<p class="text-sm text-[#94a3b8]">Everyone in your database was found on the website. No suggestions.</p>'; if (!html) html = '<p class="text-sm text-[#94a3b8]">Everyone in your database was found on the website. No suggestions.</p>';
document.getElementById('rescrapeContent').innerHTML = html; document.getElementById('rescrapeContent').innerHTML = html;
@ -438,6 +445,26 @@
const sa = document.getElementById('rescrapeSelectAll'); const sa = document.getElementById('rescrapeSelectAll');
if (sa) sa.checked = all.length > 0 && checked.length === all.length; if (sa) sa.checked = all.length > 0 && checked.length === all.length;
} }
function confirmRemoveInactive(idx) {
const people = window._rescrapeNotFound || [];
const p = people[idx];
if (!p) return;
const name = p.name || p.email || 'this person';
if (!confirm('Remove ' + name + ' from the organization? This cannot be undone.')) return;
// Remove from editingMembers by matching email or name
editingMembers = editingMembers.filter(m => {
if (p.email && m.email && m.email.toLowerCase() === p.email.toLowerCase()) return false;
if (p.name && m.name && m.name.toLowerCase() === p.name.toLowerCase()) return false;
return true;
});
// Remove from notFound list and re-render
window._rescrapeNotFound = people.filter((_, i) => i !== idx);
renderMemberList();
// Re-render the not-found section
const nfEl = document.querySelector('#rescrapeContent .border-t');
if (window._rescrapeNotFound.length === 0 && nfEl) nfEl.remove();
}
function addRescrapeSelected() { function addRescrapeSelected() {
const people = window._rescrapeNewPeople || []; const people = window._rescrapeNewPeople || [];
const checked = document.querySelectorAll('.rescrape-cb:checked'); const checked = document.querySelectorAll('.rescrape-cb:checked');