bmc_hub/app/settings/frontend/migrations.html
Christian ef171c7573 Fix: Migration interface now shows correct Podman commands for production servers
- Updated migrations.html to detect production environment and use podman/docker accordingly
- Added container runtime info to settings page
- Updated VERSION to 2.1.1
2026-01-29 00:47:40 +01:00

190 lines
7.8 KiB
HTML

{% extends "shared/frontend/base.html" %}
{% block title %}Database Migrationer - BMC Hub{% endblock %}
{% block extra_css %}
<style>
.migration-table td {
vertical-align: middle;
}
.command-box {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 0.85rem;
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid rgba(0,0,0,0.08);
border-radius: 8px;
padding: 0.75rem 1rem;
overflow-x: auto;
}
.command-actions .btn {
min-width: 120px;
}
</style>
{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold mb-1">Database Migrationer</h2>
<p class="text-muted mb-0">Oversigt over SQL migrations og kommandoer til manuel kørsel</p>
</div>
<a href="/settings" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-2"></i>Tilbage til indstillinger
</a>
</div>
<div class="alert alert-warning d-flex align-items-start" role="alert">
<i class="bi bi-exclamation-triangle me-2 mt-1"></i>
<div>
<strong>Vigtigt:</strong> Migrationer køres manuelt. Kør kun migrations du er sikker på, og tag altid backup først.
</div>
</div>
<div class="row g-4">
<div class="col-lg-8">
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<h6 class="mb-0 fw-bold"><i class="bi bi-database me-2"></i>Tilgængelige migrationer</h6>
</div>
<div class="card-body">
{% if migrations and migrations|length > 0 %}
<div class="table-responsive">
<table class="table table-hover migration-table">
<thead>
<tr>
<th>Fil</th>
<th>Størrelse</th>
<th>Sidst ændret</th>
<th class="text-end">Handling</th>
</tr>
</thead>
<tbody>
{% for migration in migrations %}
<tr>
<td>
<strong>{{ migration.name }}</strong>
</td>
<td>{{ migration.size_kb }} KB</td>
<td>{{ migration.modified }}</td>
<td class="text-end d-flex gap-2 justify-content-end">
<button class="btn btn-sm btn-outline-primary" onclick="showCommand('{{ migration.name }}')">
<i class="bi bi-terminal me-1"></i>Vis kommando
</button>
<button class="btn btn-sm btn-success" onclick="runMigration('{{ migration.name }}', this)">
<i class="bi bi-play-circle me-1"></i>Kør migration
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-info-circle text-muted fs-4"></i>
<p class="text-muted mb-0 mt-2">Ingen migrations fundet i mappen /migrations.</p>
</div>
{% endif %}
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white">
<h6 class="mb-0 fw-bold"><i class="bi bi-lightning-charge me-2"></i>Kommando</h6>
</div>
<div class="card-body">
<p class="text-muted mb-2">Vælg en migration for at se en klar kommando til manuel kørsel.</p>
<div id="commandBox" class="command-box">Vælg en migration fra listen.</div>
<div class="command-actions d-flex gap-2 mt-3">
<button id="copyCommandBtn" class="btn btn-primary" disabled onclick="copyCommand()">
<i class="bi bi-clipboard me-2"></i>Kopiér
</button>
<button id="copyAltBtn" class="btn btn-outline-secondary" disabled onclick="copyAltCommand()">
<i class="bi bi-clipboard-plus me-2"></i>Kopiér alt
</button>
</div>
<div id="migrationFeedback" class="alert d-none mt-3" role="alert"></div>
</div>
</div>
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<h6 class="mb-0 fw-bold"><i class="bi bi-info-circle me-2"></i>Standard opsætning</h6>
</div>
<div class="card-body">
<ul class="list-unstyled mb-0">
<li class="mb-2"><strong>DB bruger:</strong> {{ db_user }}</li>
<li class="mb-2"><strong>DB navn:</strong> {{ db_name }}</li>
<li class="mb-2"><strong>DB container:</strong> {{ db_container }}</li>
<li class="mb-0"><strong>Container runtime:</strong> {{ 'Podman' if is_production else 'Docker' }}</li>
</ul>
</div>
</div>
</div>
</div>
<script>
let currentCommand = "";
let currentAltCommand = "";
function buildCommand(migrationName) {
// Use podman for production, docker for local development
const runtime = {{ 'true' if is_production else 'false' }} ? 'podman' : 'docker';
const containerCmd = `${runtime} exec -i {{ db_container }} psql -U {{ db_user }} -d {{ db_name }} < migrations/${migrationName}`;
const localCmd = `psql \"$DATABASE_URL\" -f migrations/${migrationName}`;
currentCommand = containerCmd;
currentAltCommand = `${containerCmd}\n${localCmd}`;
document.getElementById('commandBox').textContent = containerCmd;
document.getElementById('copyCommandBtn').disabled = false;
document.getElementById('copyAltBtn').disabled = false;
}
function showCommand(migrationName) {
buildCommand(migrationName);
}
async function copyCommand() {
if (!currentCommand) return;
await navigator.clipboard.writeText(currentCommand);
}
async function copyAltCommand() {
if (!currentAltCommand) return;
await navigator.clipboard.writeText(currentAltCommand);
}
async function runMigration(migrationName, button) {
const feedback = document.getElementById('migrationFeedback');
const url = '/settings/migrations/execute';
button.disabled = true;
feedback.className = 'alert alert-info mt-3';
feedback.textContent = 'Kører migration...';
feedback.classList.remove('d-none');
try {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_name: migrationName })
});
const data = await response.json();
if (!response.ok) throw new Error(data.detail || data.message);
feedback.className = 'alert alert-success mt-3';
feedback.innerHTML = `<strong>Migration kørt</strong><br><pre class="mb-0">${data.output}</pre>`;
} catch (error) {
feedback.className = 'alert alert-danger mt-3';
feedback.innerHTML = `<strong>Fejl</strong><br>${error.message}`;
} finally {
button.disabled = false;
}
}
</script>
{% endblock %}