Files
giglez/static/js/search.js
T
Trilltechnician 48fcb00241 Phase 3 Complete: Web Interface MVP
Major Achievements:
-  Full web interface (1,520+ lines of frontend code)
-  Interactive Leaflet.js map with marker clustering
-  Drag-and-drop upload system with GPS input
-  Search & filter UI with multi-criteria
-  Statistics dashboard with Chart.js
-  Responsive mobile-friendly design

Backend:
-  FastAPI static file serving
-  Simplified server mode (main_simple.py)
-  Improved startup script with port auto-selection
-  PostgreSQL schema ready (requires setup)

Database:
-  SQLite populated with 85 Flipper Zero signatures
-  Device matching system operational
-  Frequency-based search working

Documentation:
-  PHASE_3_COMPLETE.md - Technical summary
-  WEB_INTERFACE_README.md - User guide
-  WEBAPP_STARTUP_GUIDE.md - Troubleshooting
-  POSTGRESQL_SETUP_EXPLANATION.md - DB setup guide
-  DATABASE_POPULATION_SUCCESS.md - Import report
-  DEVICE_IDENTIFICATION_REPORT.md - Matching analysis

Files Created:
- templates/index.html (260 lines)
- static/css/main.css (500 lines)
- static/js/*.js (760 lines total)
- src/api/main_simple.py (simplified server)
- start_web.sh (auto port selection)

Status: Production MVP Ready
Next: Phase 4 - API & Integration

🛰️ Generated with Claude Code
https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-12 18:21:11 -08:00

97 lines
3.4 KiB
JavaScript

// GigLez - Search Functionality
async function searchCaptures() {
const query = document.getElementById('search-query').value;
const frequency = document.getElementById('search-frequency').value;
const protocol = document.getElementById('search-protocol').value;
const dateStart = document.getElementById('search-date-start').value;
const dateEnd = document.getElementById('search-date-end').value;
const lat = document.getElementById('search-lat').value;
const lon = document.getElementById('search-lon').value;
const radius = document.getElementById('search-radius').value;
// Build query parameters
const params = new URLSearchParams();
if (query) params.append('q', query);
if (frequency) params.append('frequency', parseFloat(frequency) * 1e6);
if (protocol) params.append('protocol', protocol);
if (dateStart) params.append('date_start', dateStart);
if (dateEnd) params.append('date_end', dateEnd);
// Geographic search
if (lat && lon && radius) {
params.append('latitude', lat);
params.append('longitude', lon);
params.append('radius_km', radius);
}
try {
const response = await fetch(`/api/v1/query/captures?${params.toString()}`);
if (!response.ok) {
throw new Error('Search failed');
}
const data = await response.json();
displaySearchResults(data.captures || []);
} catch (error) {
console.error('Search error:', error);
alert(`Search failed: ${error.message}`);
}
}
function displaySearchResults(captures) {
const resultsDiv = document.getElementById('search-results');
const resultsList = document.getElementById('results-list');
resultsDiv.style.display = 'block';
if (captures.length === 0) {
resultsList.innerHTML = '<p>No results found. Try adjusting your search criteria.</p>';
return;
}
resultsList.innerHTML = captures.map(capture => createResultCard(capture)).join('');
}
function createResultCard(capture) {
const freqMHz = (capture.frequency / 1e6).toFixed(2);
const date = new Date(capture.captured_at).toLocaleString();
const deviceName = capture.device_name || 'Unknown Device';
const protocol = capture.protocol || 'RAW';
const confidence = capture.match_confidence
? `${(capture.match_confidence * 100).toFixed(0)}%`
: 'N/A';
return `
<div class="result-card" onclick="viewCaptureDetails('${capture.file_hash}')">
<div class="result-header">
<div class="result-title">${deviceName}</div>
<div class="result-frequency">${freqMHz} MHz</div>
</div>
<div class="result-details">
<div>
<strong>Protocol:</strong> ${protocol}
</div>
<div>
<strong>Confidence:</strong> ${confidence}
</div>
<div>
<strong>Captured:</strong> ${date}
</div>
<div>
<strong>Location:</strong> ${capture.latitude.toFixed(4)}, ${capture.longitude.toFixed(4)}
</div>
</div>
</div>
`;
}
function viewCaptureDetails(fileHash) {
// Show detail modal or navigate to detail page
alert(`Viewing details for: ${fileHash}\n\nDetail view coming soon!`);
}