left4me/l4d2web/templates/base.html
mwiegand 923a1840f4
feat(web): forms in modals, edit/delete on detail pages, port auto-assign
- Native <dialog> modal infra (CSS + ~30 LOC JS, no framework) used for
  create forms and delete confirmations.
- Index pages become listing-only: + Create button opens a modal; the
  broken blueprint Actions column and inline overlay edit cells are gone.
- Server detail gains a blueprint reassignment form; existing Delete
  button now opens a confirmation modal before tearing down the runtime.
- Blueprint detail gains a Delete button + confirmation modal (was
  unreachable from the UI before).
- New overlay detail page at /overlays/<id> with edit form, "Used by"
  blueprints list, and delete (admin only).
- Server create: port field is now optional; backend auto-assigns the
  next free port from LEFT4ME_PORT_RANGE_START/_END (default
  27015-27115). 409 on range exhaustion.
- New routes: POST /blueprints/<id>/delete (form sentinel matching
  overlays pattern), POST /servers/<id> (form-friendly blueprint
  reassign), GET /overlays/<id>.
- Server delete operation now redirects to /servers; overlay update
  redirects to /overlays/<id>.

Server rename remains unsupported pending an id-vs-name design pass for
l4d2host (the runtime directory is name-keyed; renaming would orphan
files).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 01:30:33 +02:00

44 lines
1.9 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ session.get('csrf_token', '') }}">
<title>{% block title %}left4me{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/tokens.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/layout.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/components.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/logs.css') }}">
</head>
<body>
<header class="site-header">
<div class="site-header-inner">
<nav class="primary-nav" aria-label="Main navigation">
<a class="brand" href="{{ '/dashboard' if g.user else '/login' }}">left4me</a>
{% if g.user %}
<a href="/servers">servers</a>
<a href="/blueprints">blueprints</a>
<a href="/overlays">overlays</a>
{% endif %}
</nav>
{% if g.user %}
<nav class="account-nav" aria-label="Account navigation">
{% if g.user.admin %}<a href="/admin">admin</a>{% endif %}
<span class="muted">{{ g.user.username }}</span>
<form method="post" action="/logout" class="inline-form">
<input type="hidden" name="csrf_token" value="{{ session.get('csrf_token', '') }}">
<button class="link-button" type="submit">logout</button>
</form>
</nav>
{% endif %}
</div>
</header>
<main class="container">
{% block content %}{% endblock %}
</main>
<script src="{{ url_for('static', filename='vendor/htmx.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/csrf.js') }}"></script>
<script src="{{ url_for('static', filename='js/sse.js') }}"></script>
<script src="{{ url_for('static', filename='js/modal.js') }}"></script>
</body>
</html>