Files
maps-saas/apps/api/public/intel/app.js
T
2026-04-13 14:00:42 +03:00

157 lines
5.3 KiB
JavaScript

// Intaleq Intelligence Dashboard Control
// المتحكم البرمجي في لوحة ذكاء الخرائط
const API_BASE = '/api';
// Initialize
document.addEventListener('DOMContentLoaded', () => {
fetchSummary();
fetchCandidates();
fetchClosures();
// Event Listeners
document.getElementById('run-analysis-btn').addEventListener('click', runAnalysis);
document.getElementById('discover-closures-btn').addEventListener('click', discoverClosures);
});
// --- API FETCHERS ---
async function fetchSummary() {
try {
const res = await fetch(`${API_BASE}/map-refinement/summary`);
const data = await res.json();
document.getElementById('stat-telemetry').innerText = Number(data.telemetry.total).toLocaleString();
document.getElementById('stat-roads').innerText = Number(data.roads.analyzed).toLocaleString();
document.getElementById('stat-pending').innerText = Number(data.candidates.pending).toLocaleString();
document.getElementById('stat-closed').innerText = Number(data.roads.closed || 0).toLocaleString();
} catch (e) {
showToast('Failed to fetch summary');
}
}
async function fetchCandidates() {
const tableBody = document.querySelector('#candidates-table tbody');
try {
const res = await fetch(`${API_BASE}/map-refinement/candidates?status=pending`);
const data = await res.json();
if (!data || data.length === 0) {
tableBody.innerHTML = '<tr class="empty-state"><td colspan="6">No pending discoveries 🏜️</td></tr>';
return;
}
tableBody.innerHTML = data.map(c => `
<tr>
<td title="${c.id}">${c.id.substring(0,8)}...</td>
<td><i class="fas fa-user-tag"></i> ${c.uniqueDriverCount}</td>
<td>${c.totalPoints}</td>
<td>${Math.round(c.lengthMeters)}m</td>
<td><span class="badge-conf ${getConfClass(c.confidence)}">${Math.round(c.confidence * 100)}%</span></td>
<td>
<button class="btn btn-sm-success" onclick="approveCandidate('${c.id}')"><i class="fas fa-check"></i></button>
<button class="btn btn-sm-danger" onclick="rejectCandidate('${c.id}')"><i class="fas fa-times"></i></button>
</td>
</tr>
`).join('');
} catch (e) {
tableBody.innerHTML = '<tr class="error-state"><td colspan="6">Error loading candidates</td></tr>';
}
}
async function fetchClosures() {
const tableBody = document.querySelector('#closures-table tbody');
try {
const res = await fetch(`${API_BASE}/map-refinement/closures`);
const data = await res.json();
if (!data || data.length === 0) {
tableBody.innerHTML = '<tr class="empty-state"><td colspan="3">No segments flagged</td></tr>';
return;
}
tableBody.innerHTML = data.map(s => `
<tr>
<td>${s.segmentId}</td>
<td>${s.sampleCount} pts</td>
<td><span class="badge-conf low">CLOSED</span></td>
</tr>
`).join('');
} catch (e) {
tableBody.innerHTML = '<tr><td colspan="3">Error loading closures</td></tr>';
}
}
// --- ACTIONS ---
async function approveCandidate(id) {
if (!confirm('Add this path to the approved map queue?')) return;
try {
await fetch(`${API_BASE}/map-refinement/candidates/${id}/approve`, { method: 'PATCH' });
showToast('Road Approved ✅');
fetchCandidates();
fetchSummary();
} catch (e) {
showToast('Approval failed');
}
}
async function rejectCandidate(id) {
try {
await fetch(`${API_BASE}/map-refinement/candidates/${id}/reject`, { method: 'PATCH' });
showToast('Discovery Rejected ❌');
fetchCandidates();
fetchSummary();
} catch (e) {
showToast('Rejection failed');
}
}
async function runAnalysis() {
const btn = document.getElementById('run-analysis-btn');
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Analyzing...';
try {
await fetch(`${API_BASE}/telemetry/process-intelligence?days=2`, { method: 'POST' });
showToast('Deep Intelligence started 🧠. Check Telegram for report soon!');
} catch (e) {
showToast('Analysis trigger failed');
} finally {
setTimeout(() => {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-play"></i> Run Intelligence';
fetchSummary();
}, 3000);
}
}
async function discoverClosures() {
showToast('Scanning for closures... 🚧');
try {
await fetch(`${API_BASE}/map-refinement/discover-closures`, { method: 'POST' });
showToast('Closure scan complete');
fetchClosures();
fetchSummary();
} catch (e) {
showToast('Closure discovery failed');
}
}
// --- HELPERS ---
function getConfClass(conf) {
if (conf > 0.8) return 'high';
if (conf > 0.5) return 'med';
return 'low';
}
function showToast(msg) {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
toast.className = 'toast';
toast.innerText = msg;
container.appendChild(toast);
setTimeout(() => toast.remove(), 4000);
}