Initial commit

This commit is contained in:
monoadmin
2026-04-10 15:36:34 -07:00
commit 82e3146ec5
9 changed files with 1916 additions and 0 deletions

248
templates/index.html Normal file
View File

@@ -0,0 +1,248 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WISP Access Point Map</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<link rel="stylesheet" href="/static/css/style.css"/>
</head>
<body>
<header>
<h1>WISP <span>AP Map</span></h1>
<div class="header-filters">
<span style="font-size:0.75rem;color:#718096;margin-right:4px">Filter:</span>
<button class="filter-btn freq-900 active" data-freq="900">900 MHz</button>
<button class="filter-btn freq-2400 active" data-freq="2400">2.4 GHz</button>
<button class="filter-btn freq-5800 active" data-freq="5800">5 GHz</button>
<button class="filter-btn freq-6000 active" data-freq="6000">6 GHz</button>
<button class="filter-btn freq-other active" data-freq="other">Other</button>
</div>
<div class="header-actions">
<div class="dropdown">
<button class="btn-import" id="btn-import-toggle">Import ▾</button>
<div class="dropdown-menu" id="import-menu">
<button class="dropdown-item" id="btn-open-sheets">Google Sheets</button>
<button class="dropdown-item" id="btn-open-snmp">SNMP Poll</button>
</div>
</div>
<button id="btn-add-ap">+ Add AP</button>
</div>
</header>
<div class="main">
<div id="sidebar">
<div id="sidebar-header">
Access Points &nbsp;<span id="ap-count">0</span>
</div>
<div id="ap-list"></div>
</div>
<div id="map"></div>
</div>
<!-- Legend -->
<div id="legend">
<h3>Frequency Bands</h3>
<div class="legend-row"><div class="legend-dot" style="background:#805ad5"></div> 900 MHz</div>
<div class="legend-row"><div class="legend-dot" style="background:#4299e1"></div> 2.4 GHz</div>
<div class="legend-row"><div class="legend-dot" style="background:#48bb78"></div> 5 GHz</div>
<div class="legend-row"><div class="legend-dot" style="background:#f6ad55"></div> 6 GHz</div>
<div class="legend-row"><div class="legend-dot" style="background:#a0aec0"></div> Other</div>
<div style="margin-top:8px;border-top:1px solid #2d3748;padding-top:8px;font-size:0.72rem;color:#718096">
Click map to pre-fill location<br>when adding a new AP
</div>
</div>
<!-- ═══════════════════════════════════════════════════════
Add / Edit AP Modal
═══════════════════════════════════════════════════════ -->
<div class="modal-overlay" id="modal-overlay">
<div class="modal">
<h2 id="modal-title">Add Access Point</h2>
<form id="ap-form">
<div class="form-grid">
<div class="form-group full">
<label>Tower / AP Name *</label>
<input id="f-name" type="text" required placeholder="e.g. Tower-Alpha">
</div>
<div class="form-group full">
<label>SSID</label>
<input id="f-ssid" type="text" placeholder="e.g. WISPNet">
</div>
<div class="form-group">
<label>Latitude *</label>
<input id="f-lat" type="number" step="any" required placeholder="46.7324">
</div>
<div class="form-group">
<label>Longitude *</label>
<input id="f-lon" type="number" step="any" required placeholder="-117.0002">
</div>
<div class="form-group">
<label>Frequency (MHz) *</label>
<input id="f-freq" type="number" step="any" required placeholder="5800">
</div>
<div class="form-group">
<label>Channel</label>
<input id="f-channel" type="number" placeholder="149">
</div>
<div class="form-group full">
<label>Antenna Type</label>
<select id="f-antenna">
<option value="omni">Omni-directional</option>
<option value="sector">Sector / Directional</option>
</select>
</div>
<div id="sector-fields" style="display:none;grid-column:1/-1">
<div class="form-grid">
<div class="form-group">
<label>Azimuth (°)</label>
<input id="f-azimuth" type="number" min="0" max="359" placeholder="180">
</div>
<div class="form-group">
<label>Beamwidth (°)</label>
<input id="f-beamwidth" type="number" min="1" max="360" placeholder="90">
</div>
</div>
</div>
<div class="form-group">
<label>Coverage Radius (m)</label>
<input id="f-radius" type="number" min="100" max="50000" placeholder="2000">
</div>
<div class="form-group">
<label>Signal Strength (dBm)</label>
<input id="f-signal" type="number" min="-120" max="-20" placeholder="-65">
</div>
<div class="form-group full">
<label>Tower Height (m)</label>
<input id="f-height" type="number" min="1" max="500" placeholder="30">
</div>
<div class="form-group full">
<label>Notes</label>
<textarea id="f-notes" placeholder="Optional notes..."></textarea>
</div>
</div>
<div class="modal-actions">
<button type="button" class="btn-delete" id="btn-delete-ap" style="display:none">Delete</button>
<button type="button" class="btn-cancel" id="btn-cancel">Cancel</button>
<button type="submit" class="btn-save">Save</button>
</div>
</form>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════
Google Sheets Import Modal
═══════════════════════════════════════════════════════ -->
<div class="modal-overlay" id="sheets-overlay">
<div class="modal modal-wide">
<h2>Import from Google Sheets</h2>
<div class="info-box" style="margin-bottom:1rem">
<strong>Required sheet columns:</strong> <code>name</code>, <code>lat</code>, <code>lon</code>, <code>frequency</code> (MHz)<br>
<strong>Optional:</strong> <code>ssid</code>, <code>channel</code>, <code>antenna_type</code>, <code>azimuth</code>,
<code>beamwidth</code>, <code>coverage_radius</code>, <code>signal_strength</code>, <code>height</code>, <code>notes</code><br>
<strong>Public sheets:</strong> share as "Anyone with the link can view" — no credentials needed.
</div>
<div class="form-group" style="margin-bottom:0.8rem">
<label>Google Sheets URL *</label>
<input id="sheets-url" type="url" placeholder="https://docs.google.com/spreadsheets/d/…">
</div>
<div style="margin-bottom:0.5rem">
<button class="btn-link" id="btn-show-sa" type="button">+ Use service account (private sheet)</button>
</div>
<div id="sa-section" style="display:none;margin-bottom:0.8rem">
<div class="form-group">
<label>Service Account JSON (paste credentials)</label>
<textarea id="sheets-sa-json" rows="5" placeholder='{"type":"service_account","project_id":…}'></textarea>
</div>
</div>
<!-- Preview table -->
<div id="sheets-preview" style="display:none;margin-bottom:0.8rem">
<div class="section-label">Preview (first 5 rows)</div>
<div id="preview-table-wrap" style="overflow-x:auto"></div>
<div id="col-mapping" style="margin-top:0.5rem;font-size:0.75rem;color:#718096"></div>
</div>
<!-- Result -->
<div id="sheets-result" style="display:none"></div>
<div class="modal-actions">
<button type="button" class="btn-cancel" id="sheets-cancel">Cancel</button>
<button type="button" class="btn-secondary" id="btn-sheets-preview">Preview</button>
<button type="button" class="btn-save" id="btn-sheets-import">Import All</button>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════
SNMP Poll Modal
═══════════════════════════════════════════════════════ -->
<div class="modal-overlay" id="snmp-overlay">
<div class="modal modal-wide">
<h2>SNMP Device Poll</h2>
<div class="info-box" style="margin-bottom:1rem">
Polls a device via SNMPv1/v2c for system info, frequency, SSID, and signal strength.
Vendor auto-detection: <strong>Ubiquiti AirMax</strong>, <strong>MikroTik RouterOS</strong>, <strong>Cambium</strong>.
</div>
<div class="form-grid" style="margin-bottom:0.8rem">
<div class="form-group">
<label>Device IP / Hostname *</label>
<input id="snmp-host" type="text" placeholder="192.168.1.1">
</div>
<div class="form-group">
<label>Community String</label>
<input id="snmp-community" type="text" value="public" placeholder="public">
</div>
<div class="form-group">
<label>Port</label>
<input id="snmp-port" type="number" value="161" min="1" max="65535">
</div>
<div class="form-group">
<label>SNMP Version</label>
<select id="snmp-version">
<option value="2c" selected>v2c</option>
<option value="1">v1</option>
</select>
</div>
</div>
<!-- Raw results table -->
<div id="snmp-raw-section" style="display:none;margin-bottom:0.8rem">
<div class="section-label">Polled Data</div>
<div id="snmp-raw-table"></div>
</div>
<!-- Suggested AP pre-fill -->
<div id="snmp-suggested" style="display:none;margin-bottom:0.8rem">
<div class="section-label">Suggested AP values <span style="color:#718096;font-weight:400">(edit before saving)</span></div>
<div class="form-grid">
<div class="form-group"><label>Name</label><input id="snmp-f-name" type="text"></div>
<div class="form-group"><label>SSID</label><input id="snmp-f-ssid" type="text"></div>
<div class="form-group"><label>Latitude *</label><input id="snmp-f-lat" type="number" step="any" placeholder="Required"></div>
<div class="form-group"><label>Longitude *</label><input id="snmp-f-lon" type="number" step="any" placeholder="Required"></div>
<div class="form-group"><label>Frequency (MHz)</label><input id="snmp-f-freq" type="number" step="any"></div>
<div class="form-group"><label>Signal (dBm)</label><input id="snmp-f-signal" type="number" step="any"></div>
<div class="form-group full"><label>Notes</label><input id="snmp-f-notes" type="text"></div>
</div>
</div>
<div id="snmp-error" style="display:none" class="error-box"></div>
<div class="modal-actions">
<button type="button" class="btn-cancel" id="snmp-cancel">Cancel</button>
<button type="button" class="btn-secondary" id="btn-snmp-poll">Poll Device</button>
<button type="button" class="btn-save" id="btn-snmp-add" style="display:none">Add to Map</button>
</div>
</div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="/static/js/app.js"></script>
</body>
</html>