v0.71.0: admin panel — users table, login/sessions, generic DB CRUD modal
CI / build + unit + e2e (pull_request) Failing after 13m35s

This commit is contained in:
2026-09-24 09:24:31 +00:00
parent 034d7a8d94
commit b89d351587
25 changed files with 2089 additions and 6 deletions
+12
View File
@@ -11,6 +11,8 @@ import type { HoverTarget } from './hoverTypes';
import { hoverRouteGeoJson, hoverTraceGeoJson, planesGeoJson, queuedRoutesGeoJson, routesGeoJson, type AirportCoord, type PlaneFeatureProps } from '../lib/mapData';
import { weatherFor } from '../lib/weather';
import { approxLocalTime } from '../lib/localTime';
import Modal from './Modal';
import AdminPanel from './AdminPanel';
// v0.70.0 default view: null island [0,0] at zoom 2 — the world is 2048 px wide there and the
// Africa+Europe bounding box (lat −35..+71, lon −18..+52) spans ~800 px vertically in Web Mercator,
@@ -89,6 +91,9 @@ export default function FlightMap({ state, hovered, applySnapshot }: MapProps) {
const airportsIndexRef = useRef<Map<string, AirportCoord> | null>(null);
const [airportCount, setAirportCount] = useState<number | null>(null);
const [styleId, setStyleId] = useState<string>(DEFAULT_STYLE_ID);
// v0.71.0: the Admin modal (top-bar button) — unmounted while closed so it re-checks the
// stored session on every open.
const [adminOpen, setAdminOpen] = useState(false);
// Push the latest planes/routes GeoJSON into whatever sources currently exist.
// No-op until the map (and for routes: the airport index) is ready — the mount
@@ -579,8 +584,15 @@ export default function FlightMap({ state, hovered, applySnapshot }: MapProps) {
<span data-testid="airport-count">
{airportCount === null ? 'loading airports…' : `${airportCount} world airports`}
</span>
{/* v0.71.0: admin panel entry point — right side of the top bar, opens a modal (no URL). */}
<button type="button" data-testid="admin-btn" className="pane-btn" onClick={() => setAdminOpen(true)}>
Admin
</button>
</header>
<div ref={containerRef} data-testid="map" className="map-container" />
<Modal open={adminOpen} onClose={() => setAdminOpen(false)} title="Admin">
<AdminPanel />
</Modal>
</div>
);
}