249 lines
11 KiB
HTML
249 lines
11 KiB
HTML
<!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 <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>
|