feat : versionnage semver, migrations contenu, bandeau mise à jour admin
- CHANGELOG.md : structure semver (1.0.0 / 1.1.0 / 1.2.0) remplace le journal non versionné - public/version.txt : généré à chaque push depuis la première entrée CHANGELOG - scripts/push.sh : extrait la version CHANGELOG avant git add - src/UpdateChecker.php : compare version déployée vs version Gitea (raw file), cache 1 h - templates/layout.php : bandeau alerte admin (nouvelle version / migrations en attente) - templates/admin.php : dashboard moteur Folio (version déployée / disponible) - scripts/migrate_content.php + migration_001 : ajout # titre dans les articles existants - templates/maintenance.php : page HTTP 503 pendant une migration - src/helpers.php : extractMarkdownTitle(), normalisation \r\n dans lineDiff() - templates/wizard/step1.php : suppression champ titre, plan TOC dynamique - public/assets/js/wizard.js : scope titleEl, scrollToCursor, buildToc, handlers externalisés Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,55 @@ function adminStatusBadge(array $a, int $now): string
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<!-- Version Folio ──────────────────────────────────────────────────────── -->
|
||||
<?php
|
||||
$_deployedVer = trim((string) @file_get_contents(BASE_PATH . '/public/version.txt'));
|
||||
$_deployedLabel = $_deployedVer !== '' ? date('d/m/Y H:i', strtotime($_deployedVer)) : '—';
|
||||
$_notices = isset($_updateChecker) ? $_updateChecker->adminNotices() : [];
|
||||
$_remoteLabel = '—';
|
||||
foreach ($_notices as $_n) {
|
||||
if ($_n['type'] === 'info' && preg_match('/publiée le ([^)]+)/', $_n['message'], $_m)) {
|
||||
$_remoteLabel = $_m[1];
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-transparent py-2 small fw-semibold">Moteur Folio</div>
|
||||
<div class="card-body py-2">
|
||||
<table class="table table-sm table-borderless mb-0 small">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="text-muted fw-normal ps-0 pe-2 text-nowrap" style="width:160px">Version déployée</th>
|
||||
<td><?= htmlspecialchars($_deployedLabel) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-muted fw-normal ps-0 pe-2 text-nowrap">Dernière version disponible</th>
|
||||
<td><?= htmlspecialchars($_remoteLabel) ?><?= $_remoteLabel !== '—' && $_remoteLabel !== $_deployedLabel ? ' <span class="badge bg-warning text-dark ms-1">Mise à jour disponible</span>' : '' ?></td>
|
||||
</tr>
|
||||
<?php if (!empty($_notices)): ?>
|
||||
<tr>
|
||||
<th class="text-muted fw-normal ps-0 pe-2 align-top">Actions requises</th>
|
||||
<td class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<?php foreach ($_notices as $_n): ?>
|
||||
<?php if ($_n['type'] === 'warning'): ?>
|
||||
<form method="POST" action="/?action=run_content_migrations">
|
||||
<button type="submit" class="btn btn-warning btn-sm">Mettre à jour le contenu</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php if (($_GET['notice'] ?? '') === 'migrated'): ?>
|
||||
<tr><td colspan="2"><div class="alert alert-success py-1 mb-0 small">Migrations appliquées avec succès.</div></td></tr>
|
||||
<?php elseif (($_GET['notice'] ?? '') === 'migration_error'): ?>
|
||||
<tr><td colspan="2"><div class="alert alert-danger py-1 mb-0 small">Une erreur est survenue pendant la migration.</div></td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>Activité récente</h5>
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
|
||||
@@ -106,6 +106,25 @@ $_layoutCurrentCat = trim($_GET['cat'] ?? '');
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<?php if (function_exists('isAdmin') && isAdmin() && isset($_updateChecker)):
|
||||
$_adminNotices = $_updateChecker->adminNotices();
|
||||
foreach ($_adminNotices as $_notice):
|
||||
$_isWarning = $_notice['type'] === 'warning'; ?>
|
||||
<div class="alert alert-<?= $_isWarning ? 'warning' : 'info' ?> alert-dismissible rounded-0 border-0 border-bottom py-2 mb-0 small" role="alert">
|
||||
<div class="container-fluid d-flex align-items-center gap-2 flex-wrap">
|
||||
<span><?= $_notice['message'] ?></span>
|
||||
<?php if ($_isWarning): ?>
|
||||
<form method="POST" action="/?action=run_content_migrations" class="d-inline">
|
||||
<button type="submit" class="btn btn-warning btn-sm py-0">Mettre à jour</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<a href="/admin?tab=dashboard" class="btn btn-outline-primary btn-sm py-0">Voir dans l'admin</a>
|
||||
<?php endif; ?>
|
||||
<button type="button" class="btn-close ms-auto" data-bs-dismiss="alert" aria-label="Fermer"></button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; endif; ?>
|
||||
|
||||
<main class="<?= htmlspecialchars($mainClass ?? 'container') ?>" role="main">
|
||||
<?= $content ?>
|
||||
</main>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Mise à jour en cours</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:system-ui,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f8f9fa;color:#212529}
|
||||
.box{text-align:center;padding:2.5rem 2rem;max-width:420px}
|
||||
.icon{font-size:2.5rem;margin-bottom:1rem}
|
||||
h1{font-size:1.4rem;font-weight:600;margin-bottom:.6rem}
|
||||
p{color:#6c757d;line-height:1.6}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div class="icon">⚙️</div>
|
||||
<h1>Mise à jour en cours</h1>
|
||||
<p>Le site est temporairement indisponible pendant une mise à jour.<br>Merci de réessayer dans quelques instants.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -19,7 +19,8 @@ $_hasUuid = $_wizUuid !== '';
|
||||
<!-- En-tête avec boutons ────────────────────────────────────────────────── -->
|
||||
<div class="d-flex align-items-center justify-content-between gap-3 mb-4 flex-wrap">
|
||||
<div>
|
||||
<h1 class="h4 mb-0"><?= $mode === 'create' ? 'Nouvel article' : htmlspecialchars('Modifier — ' . ($article['title'] ?? '')) ?></h1>
|
||||
<h1 class="h4 mb-0" id="wz-page-title"
|
||||
data-prefix="<?= $mode === 'edit' ? 'Modifier — ' : '' ?>"><?= $mode === 'create' ? 'Nouvel article' : htmlspecialchars('Modifier — ' . ($article['title'] ?? '')) ?></h1>
|
||||
<?php if ($_hasUuid): ?>
|
||||
<span id="autosave-indicator" class="text-muted small"></span>
|
||||
<?php endif; ?>
|
||||
@@ -39,14 +40,6 @@ $_hasUuid = $_wizUuid !== '';
|
||||
<div class="row g-3 align-items-start">
|
||||
<div class="col-lg-9">
|
||||
|
||||
<!-- Titre ─────────────────────────────────────────────────────────────── -->
|
||||
<div class="mb-3">
|
||||
<label for="wz-title" class="form-label fw-semibold">Titre</label>
|
||||
<input type="text" class="form-control form-control-lg" id="wz-title" name="title" required
|
||||
value="<?= htmlspecialchars($title ?? '') ?>"
|
||||
placeholder="Titre de l'article…">
|
||||
</div>
|
||||
|
||||
<!-- Contenu ──────────────────────────────────────────────────────────── -->
|
||||
<div class="mb-3">
|
||||
<label for="wz-content" class="form-label fw-semibold">Contenu <small class="text-muted fw-normal">(Markdown)</small></label>
|
||||
|
||||
Reference in New Issue
Block a user