Add auth system, fix map defaults, controls overflow, fix latest-date ref
This commit is contained in:
@@ -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())
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user