Release v2.0.0 updates

This commit is contained in:
Christian 2026-01-28 08:03:17 +01:00
parent c2a265d5f9
commit ce7bbff766
6 changed files with 207 additions and 2 deletions

View File

@ -8,7 +8,7 @@
# RELEASE VERSION # RELEASE VERSION
# ===================================================== # =====================================================
# Tag fra Gitea (f.eks. v1.0.0, v1.2.3) # Tag fra Gitea (f.eks. v1.0.0, v1.2.3)
RELEASE_VERSION=v1.0.0 RELEASE_VERSION=v2.0.0
# ===================================================== # =====================================================
# GITEA AUTHENTICATION # GITEA AUTHENTICATION

21
RELEASE_NOTES_v2.0.0.md Normal file
View File

@ -0,0 +1,21 @@
# Release Notes v2.0.0
## New Features
- Added new opportunities module with advanced features.
- Improved performance for customer data processing.
- Enhanced email activity logging system.
## Bug Fixes
- Fixed issues with subscription singular module.
- Resolved errors in ticket module integration.
## Other Changes
- Updated dependencies in `requirements.txt`.
- Database schema updated with migration `016_opportunities.sql`.
## Deployment Notes
- Ensure to run the new database migration script `016_opportunities.sql` before deploying.
- Verify `.env` file is updated with the correct `RELEASE_VERSION`.
---
Release Date: 28. januar 2026

View File

@ -1 +1 @@
1.3.152 2.0.0

View File

@ -2,10 +2,14 @@
Settings Frontend Views Settings Frontend Views
""" """
from datetime import datetime
from pathlib import Path
from fastapi import APIRouter, Request from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from app.core.config import settings
router = APIRouter() router = APIRouter()
templates = Jinja2Templates(directory="app") templates = Jinja2Templates(directory="app")
@ -17,3 +21,28 @@ async def settings_page(request: Request):
"request": request, "request": request,
"title": "Indstillinger" "title": "Indstillinger"
}) })
@router.get("/settings/migrations", response_class=HTMLResponse, tags=["Frontend"])
async def migrations_page(request: Request):
"""Render database migrations page"""
migrations_dir = Path(__file__).resolve().parents[3] / "migrations"
migrations = []
if migrations_dir.exists():
for migration_file in sorted(migrations_dir.glob("*.sql")):
stat = migration_file.stat()
migrations.append({
"name": migration_file.name,
"size_kb": round(stat.st_size / 1024, 1),
"modified": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M")
})
return templates.TemplateResponse("settings/frontend/migrations.html", {
"request": request,
"title": "Database Migrationer",
"migrations": migrations,
"db_user": settings.POSTGRES_USER,
"db_name": settings.POSTGRES_DB,
"db_container": "bmc-hub-postgres"
})

View File

@ -0,0 +1,152 @@
{% 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">
<button class="btn btn-sm btn-outline-primary" onclick="showCommand('{{ migration.name }}')">
<i class="bi bi-terminal me-1"></i>Vis kommando
</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>
</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-0"><strong>DB container:</strong> {{ db_container }}</li>
</ul>
</div>
</div>
</div>
</div>
<script>
let currentCommand = "";
let currentAltCommand = "";
function buildCommand(migrationName) {
const dockerCmd = `docker exec -i {{ db_container }} psql -U {{ db_user }} -d {{ db_name }} < migrations/${migrationName}`;
const localCmd = `psql \"$DATABASE_URL\" -f migrations/${migrationName}`;
currentCommand = dockerCmd;
currentAltCommand = `${dockerCmd}\n${localCmd}`;
document.getElementById('commandBox').textContent = dockerCmd;
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);
}
</script>
{% endblock %}

View File

@ -110,6 +110,9 @@
<a class="nav-link" href="#system" data-tab="system"> <a class="nav-link" href="#system" data-tab="system">
<i class="bi bi-gear me-2"></i>System <i class="bi bi-gear me-2"></i>System
</a> </a>
<a class="nav-link" href="/settings/migrations">
<i class="bi bi-database me-2"></i>DB Migrationer
</a>
</nav> </nav>
</div> </div>
</div> </div>