← back to Rentv 2026

public/admin/pr-intelligence/sources.html

46 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>CRE PR Intelligence — Sources</title>
<link rel="stylesheet" href="/admin/pr-intelligence/pr-shared.css">
</head>
<body>
<script src="/admin/pr-intelligence/pr-shared.js"></script>
<script>
(async function () {
  const c = PR.frame('sources', 'Sources & Evidence', 'Every important fact points at a source row: URL, limited excerpt, retrieval date, usage note. Full page copies are never stored.');
  let offset = 0; const limit = 50;
  const { bar, state } = PR.filters([
    { key: 'q', placeholder: 'Search source name / URL…' },
    { key: 'type', type: 'select', options: [['', 'Type: all'], ['org_website', 'org website'], ['gov_registry', 'gov registry'], ['sec_edgar', 'SEC EDGAR'], ['press_release', 'press release'], ['news_article', 'news article'], ['association', 'association'], ['search_api', 'search API'], ['user_import', 'user import'], ['manual', 'manual']] },
  ], () => { offset = 0; load(); });
  c.appendChild(bar);
  const actions = document.createElement('div'); actions.className = 'filters';
  actions.innerHTML = `<a class="btn" href="/api/pr/export/evidence">⬇ Export all field evidence CSV</a>`;
  c.appendChild(actions);

  const tbl = PR.table([
    { key: 'name', label: 'Source', render: (r) => `<b>${PR.esc(r.source_name)}</b><br>${r.url ? `<a href="${PR.esc(r.url)}" target="_blank" rel="noopener noreferrer" style="font-size:12px">${PR.esc(r.url.slice(0, 80))}</a>` : ''}` },
    { key: 'type', label: 'Type', render: (r) => PR.badge(r.source_type, r.is_primary_source ? 'green' : 'gray') + (r.is_primary_source ? ' ' + PR.badge('primary', 'green') : '') },
    { key: 'excerpt', label: 'Excerpt', render: (r) => `<span style="font-size:12px;color:var(--muted)">${PR.esc((r.short_excerpt || '').slice(0, 120))}</span>` },
    { key: 'evidence', label: 'Evidence rows', render: (r) => String(r.evidence_count) },
    { key: 'terms', label: 'Terms', render: (r) => r.license_or_usage_note ? `<span title="${PR.esc(r.license_or_usage_note)}" style="cursor:help">ⓘ</span>` : '—' },
    { key: 'retrieved', label: 'Retrieved', render: (r) => `<span title="${PR.esc(r.retrieved_at)}">🕓 ${PR.date(r.retrieved_at)}</span>` },
    { key: 'status', label: 'Status', render: (r) => PR.badge(r.status, r.status === 'active' ? 'green' : 'amber') },
  ]);
  c.appendChild(tbl.el);
  const pagerBox = document.createElement('div'); c.appendChild(pagerBox);

  async function load() {
    const q = new URLSearchParams({ ...Object.fromEntries(Object.entries(state).filter(([, v]) => v)), limit, offset });
    const j = await PR.api('/sources?' + q);
    tbl.render(j.rows);
    pagerBox.innerHTML = ''; pagerBox.appendChild(PR.pager(j.total, limit, offset, (o) => { offset = o; load(); }));
  }
  load();
})();
</script>
</body>
</html>