feat: add tab with all domain records
Some checks are pending
CI / lint (push) Waiting to run
Deploy / deploy (push) Waiting to run

This commit is contained in:
Adrian Miesikowski 2026-02-18 21:39:58 +01:00
parent a98291316e
commit 6b5d385463
2 changed files with 79 additions and 4 deletions

44
api.php
View File

@ -230,6 +230,50 @@ if ($action === 'live_prices') {
exit;
}
if ($action === 'all_domains') {
$q = trim($_GET['q'] ?? '');
$tld = trim($_GET['tld'] ?? '');
$limit = intval($_GET['limit'] ?? 2000);
if ($limit < 1) $limit = 1;
if ($limit > 5000) $limit = 5000;
$sql = "SELECT d.run_id, d.scanned_at, d.domain, d.tld, d.score, d.status, d.keywords_json,
ls.llm_score, ls.decision, ls.reason
FROM domains d
LEFT JOIN llm_scores ls ON ls.run_id = d.run_id AND ls.domain = d.domain
WHERE 1=1";
if ($q !== '') $sql .= " AND d.domain LIKE :q";
if ($tld !== '') $sql .= " AND d.tld = :tld";
$sql .= " ORDER BY d.scanned_at DESC, d.score DESC, d.domain ASC LIMIT :limit";
$st = $db->prepare($sql);
if ($q !== '') $st->bindValue(':q', '%' . $q . '%', SQLITE3_TEXT);
if ($tld !== '') $st->bindValue(':tld', $tld, SQLITE3_TEXT);
$st->bindValue(':limit', $limit, SQLITE3_INTEGER);
$res = $st->execute();
$rows = [];
while ($r = $res->fetchArray(SQLITE3_ASSOC)) {
$r['keywords'] = json_decode($r['keywords_json'] ?: '[]', true) ?: [];
$r['is_new'] = false;
unset($r['keywords_json']);
$rows[] = $r;
}
echo json_encode([
'ok' => true,
'meta' => [
'mode' => 'all',
'count' => count($rows),
'limit' => $limit,
],
'domains' => $rows,
], JSON_UNESCAPED_UNICODE);
exit;
}
if ($action === 'prices') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$raw = json_decode(file_get_contents('php://input'), true) ?: [];

View File

@ -24,6 +24,9 @@
.pill input{width:78px;padding:4px 6px}
.ok{color:#63db8f}.bad{color:#ff8b8b}
.chip{display:inline-block;padding:2px 8px;border-radius:999px;font-size:11px;background:#264a32;color:#9df5bc;border:1px solid #3f8b5b}
.tabbar{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 0}
.tabbtn{cursor:pointer}
.tabbtn.active{background:#2a3f86;border-color:#6e8cff;color:#fff}
.small{font-size:12px}
@media (max-width: 980px){.grid{grid-template-columns:1fr}}
@media (max-width: 700px){
@ -41,6 +44,10 @@
<div class="card">
<h2>Filtr domen</h2>
<div class="tabbar">
<button id="tabCurrent" class="tabbtn active">Bieżący skan</button>
<button id="tabAll" class="tabbtn">Wszystkie rekordy</button>
</div>
<div class="controls">
<label>Szukaj <input id="q" placeholder="np. lead, ai, crm" /></label>
<label>TLD
@ -57,7 +64,7 @@
<h2>TOP domen + porównanie cen (rejestracja / odnowienie)</h2>
<div class="table-wrap">
<table>
<thead><tr><th>Domena</th><th>TLD</th><th>Score</th><th>LLM</th><th>Status</th><th>Oferty (top 3)</th></tr></thead>
<thead><tr><th>Domena</th><th>TLD</th><th>Score</th><th>LLM</th><th>Status</th><th>Run</th><th>Skan</th><th>Oferty (top 3)</th></tr></thead>
<tbody id="rows"></tbody>
</table>
</div>
@ -67,6 +74,7 @@
<script>
let domains = [];
let livePriceByTld = {};
let viewMode = 'current';
function money(v){ return (v===null || v===undefined || Number.isNaN(Number(v))) ? '—' : `${Number(v).toFixed(2)} zł`; }
@ -126,13 +134,22 @@ async function loadDomains(){
const tld = document.getElementById('tld').value;
const onlyNew = document.getElementById('onlyNew').checked;
const u = new URL('./api.php', location.href);
u.searchParams.set('action','domains');
if(viewMode === 'all'){
u.searchParams.set('action','all_domains');
u.searchParams.set('limit','2000');
} else {
u.searchParams.set('action','domains');
if(onlyNew) u.searchParams.set('only_new', '1');
}
if(q) u.searchParams.set('q', q);
if(tld) u.searchParams.set('tld', tld);
if(onlyNew) u.searchParams.set('only_new', '1');
const d = await (await fetch(u)).json();
domains = d.domains || [];
document.getElementById('meta').textContent = `runId: ${d.meta?.runId||'—'} | prev: ${d.meta?.prevRunId||'—'} | scannedAt: ${d.meta?.scannedAt||'—'} | nowe: ${d.meta?.newCount||0} | widoczne: ${domains.length}`;
if(viewMode === 'all'){
document.getElementById('meta').textContent = `widok: wszystkie rekordy | limit: ${d.meta?.limit||'—'} | widoczne: ${domains.length}`;
} else {
document.getElementById('meta').textContent = `runId: ${d.meta?.runId||'—'} | prev: ${d.meta?.prevRunId||'—'} | scannedAt: ${d.meta?.scannedAt||'—'} | nowe: ${d.meta?.newCount||0} | widoczne: ${domains.length}`;
}
}
function renderRows(){
@ -159,6 +176,8 @@ function renderRows(){
<td>${d.score}</td>
<td>${llm}</td>
<td>${d.status || 'available'}</td>
<td class='small muted'>${d.run_id || '—'}</td>
<td class='small muted'>${d.scanned_at || '—'}</td>
<td>${offersHtml}</td>`;
rows.appendChild(tr);
}
@ -185,6 +204,18 @@ function setupAutoRefresh(){
}
}
function setTab(mode){
viewMode = mode;
const currentBtn = document.getElementById('tabCurrent');
const allBtn = document.getElementById('tabAll');
currentBtn.classList.toggle('active', mode === 'current');
allBtn.classList.toggle('active', mode === 'all');
document.getElementById('onlyNew').disabled = (mode === 'all');
refreshAll();
}
document.getElementById('tabCurrent').addEventListener('click', ()=>setTab('current'));
document.getElementById('tabAll').addEventListener('click', ()=>setTab('all'));
document.getElementById('reload').addEventListener('click', refreshAll);
document.getElementById('q').addEventListener('input', async()=>{
clearTimeout(qTimer);