Add auth system, fix map defaults, controls overflow, fix latest-date ref

This commit is contained in:
zyphlar
2026-04-22 17:03:15 -07:00
parent 6880382011
commit 24c27767ec
8 changed files with 288 additions and 55 deletions
+21
View File
@@ -378,6 +378,7 @@
<button class="btn-topbar" onclick="runScript('ls', '')">List Files</button>
<button class="btn-topbar" onclick="clearData()" style="color:#f88;">Clear Data</button>
<div style="flex:1"></div>
{% if current_user %}
<div class="config-group">
<a href="/api/config/counties.yml" class="btn-topbar-icon" title="Download counties.yml">↓ counties.yml</a>
<label class="btn-topbar-icon" title="Upload counties.yml" style="cursor:pointer"><input type="file" style="display:none" accept=".yml,.yaml" onchange="uploadConfig('counties.yml', this)"></label>
@@ -387,9 +388,19 @@
<label class="btn-topbar-icon" title="Upload exceptions.yml" style="cursor:pointer"><input type="file" style="display:none" accept=".yml,.yaml" onchange="uploadConfig('exceptions.yml', this)"></label>
</div>
<div class="topbar-sep"></div>
{% endif %}
<a href="/counties" class="btn-topbar">Counties</a>
<a href="/exceptions" class="btn-topbar">Street Exceptions</a>
<a href="/map" class="btn-topbar purple">Open Map Viewer</a>
<div class="topbar-sep"></div>
{% if current_user %}
<span style="font-size:11px;color:#888;">{{ current_user }}</span>
<form method="POST" action="/logout" style="display:inline;margin:0">
<button type="submit" class="btn-topbar">Logout</button>
</form>
{% else %}
<a href="/login" class="btn-topbar" style="color:#f0a830;">Login</a>
{% endif %}
</div>
<div class="main">
@@ -564,10 +575,17 @@
<script>
const COUNTY_CONFIG = {{ counties_json | safe }};
const IS_AUTHENTICATED = {{ 'true' if current_user else 'false' }};
let activeCounty = COUNTY_CONFIG.length ? COUNTY_CONFIG[0].id : '';
let currentJobId = null;
let logCheckInterval = null;
function requireLogin() {
showStatus('Not authenticated please log in.', 'error');
setTimeout(() => { window.location.href = '/login?next=' + encodeURIComponent(window.location.pathname); }, 1200);
return false;
}
function selectCounty(county) {
activeCounty = county;
const config = COUNTY_CONFIG.find(c => c.id === county);
@@ -619,6 +637,7 @@
/* ── Script runner ── */
function runScript(scriptName) {
if (!IS_AUTHENTICATED) return requireLogin();
const logsEl = document.getElementById('logs');
logsEl.textContent = '';
showStatus(`Running: ${scriptName} (${activeCounty})`, 'info');
@@ -699,6 +718,7 @@
}
function uploadFile(inputId, dest) {
if (!IS_AUTHENTICATED) return requireLogin();
const input = document.getElementById(inputId);
if (!input || !input.files.length) {
showStatus('Please select a file first.', 'error');
@@ -727,6 +747,7 @@
}
function clearData() {
if (!IS_AUTHENTICATED) return requireLogin();
if (!confirm('Delete all downloaded and processed files from all county folders?')) return;
fetch('/api/clear-data', { method: 'POST' })
.then(r => r.json())
+113
View File
@@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login OSM Import Tools</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #0f0f1a;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.login-box {
background: #1a1a2e;
border-radius: 10px;
padding: 36px 32px;
width: 320px;
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
}
.login-box h1 {
font-size: 18px;
font-weight: 700;
color: #fff;
margin-bottom: 6px;
}
.login-box .subtitle {
font-size: 12px;
color: #666;
margin-bottom: 28px;
}
.error-msg {
background: #3a1e1e;
color: #e07070;
border-radius: 5px;
padding: 8px 12px;
font-size: 13px;
margin-bottom: 16px;
}
label {
display: block;
font-size: 11px;
font-weight: 600;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 5px;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 9px 12px;
border: 1px solid #333;
border-radius: 5px;
background: #0f0f1a;
color: #ddd;
font-size: 14px;
margin-bottom: 16px;
outline: none;
transition: border-color 0.15s;
}
input[type="text"]:focus,
input[type="password"]:focus {
border-color: #6f42c1;
}
button[type="submit"] {
width: 100%;
padding: 10px;
background: #6f42c1;
color: white;
border: none;
border-radius: 5px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s;
}
button[type="submit"]:hover { background: #5a32a3; }
</style>
</head>
<body>
<div class="login-box">
<h1>OSM Import Tools</h1>
<div class="subtitle">Sign in to continue</div>
{% if error %}
<div class="error-msg">{{ error }}</div>
{% endif %}
<form method="POST" action="/login">
<input type="hidden" name="next" value="{{ next }}">
<label for="username">Username</label>
<input type="text" id="username" name="username" autofocus autocomplete="username" required>
<label for="password">Password</label>
<input type="password" id="password" name="password" autocomplete="current-password" required>
<button type="submit">Log in</button>
</form>
</div>
</body>
</html>
+4 -2
View File
@@ -34,6 +34,8 @@
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
min-width: 200px;
max-height: calc(100vh - 20px);
overflow-y: auto;
}
.controls h3 {
@@ -291,7 +293,7 @@
<span>Diff Layer</span>
</div>
<div class="layer-item" draggable="true" data-layer="osm">
<input type="checkbox" id="osmToggle" checked>
<input type="checkbox" id="osmToggle">
<span>OSM Layer (Gray)</span>
</div>
<div class="layer-item" draggable="true" data-layer="county">
@@ -306,7 +308,7 @@
Show Added (Green)
</label>
<label>
<input type="checkbox" id="showRemoved" checked>
<input type="checkbox" id="showRemoved">
Show Removed (Red)
</label>
<label>