CI / test (push) Successful in 2m13s
- Carte compositeur : en-tête + colonne d'arrivée, champ pleine largeur, bouton primaire ; neutralise le display:flex imposé par .board-toolbar aux formulaires. - 'Ajouter une description' devient un <details> natif : aucun JS requis, insensible au cache et aux erreurs de scripts (le bouton 0.31.0 pouvait rester inerte). - Assets du board versionnés (?v=APP_VERSION) contre les mélanges de cache après redéploiement ; Ctrl+Entrée. - Vérifié en Chromium réel sur le vrai board (captures contrôlées) ; 261 tests verts.
203 lines
10 KiB
HTML
203 lines
10 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr" data-theme="dark">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="csrf-token" content="{{ csrf_token }}">
|
||
<title>{{ repo }} — Kanbante</title>
|
||
<link rel="stylesheet" href="/static/css/style.css?v={{ version }}">
|
||
<script src="/static/vendor/sortable.min.js"></script>
|
||
<script src="/static/vendor/marked.min.js"></script>
|
||
<script src="/static/vendor/purify.min.js"></script>
|
||
<script src="/static/js/board.js?v={{ version }}" defer></script>
|
||
</head>
|
||
<body>
|
||
{% include "_header.html" %}
|
||
|
||
{% if milestones %}
|
||
<div class="milestone-bar">
|
||
<span class="milestone-label">🎯 Milestone</span>
|
||
<a href="/board/{{ owner }}/{{ repo }}" class="milestone-chip{% if not milestone_param %} active{% endif %}">Toutes</a>
|
||
{% for m in milestones %}
|
||
<a href="/board/{{ owner }}/{{ repo }}?milestone={{ m.title|urlencode }}"
|
||
class="milestone-chip{% if milestone_param == m.title or milestone_param == m.id|string %} active{% endif %}">{{ m.title }}</a>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
{% if milestone_progress %}
|
||
<div class="milestone-banner">
|
||
<div class="milestone-info">
|
||
<strong>🎯 {{ milestone_progress.title }}</strong>
|
||
{% if milestone_progress.due_on %}
|
||
<span class="milestone-due">📅 échéance {{ milestone_progress.due_on[:10] }}</span>
|
||
{% endif %}
|
||
<span class="milestone-count">{{ milestone_progress.closed }}/{{ milestone_progress.total }} issues terminées</span>
|
||
{% if milestone_forecast %}
|
||
<span class="milestone-forecast">🔮 {{ milestone_forecast }}</span>
|
||
{% endif %}
|
||
<a class="milestone-sprint" href="/sprint/{{ full_name }}?milestone={{ milestone_param|urlencode }}">📖 Récit de sprint</a>
|
||
</div>
|
||
<div class="progress progress-lg"><span style="width: {{ milestone_progress.pct }}%"></span></div>
|
||
<span class="milestone-pct">{{ milestone_progress.pct }}%</span>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- Toolbar: text + label filters, and issue creation (Gitea-backed) -->
|
||
<div class="board-toolbar">
|
||
<input type="text" id="card-filter" placeholder="🔍 Filtrer les cartes... ( / )">
|
||
<select id="label-filter">
|
||
<option value="">Toutes les étiquettes</option>
|
||
{% for label in labels %}
|
||
<option value="{{ label.name }}">{{ label.name }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<button type="button" id="labels-btn" class="btn-sm">🏷️ Gérer les étiquettes</button>
|
||
<a href="/triage/{{ full_name }}" class="btn-sm" style="text-decoration:none">📥 Triage du backlog</a>
|
||
{% if is_admin or workspace_role == 'admin' %}<a href="/admin/columns" class="btn-sm" style="text-decoration:none" title="Personnaliser les colonnes de cet espace">🧱 Colonnes</a>{% endif %}
|
||
<form id="create-issue-form" class="composer">
|
||
<div class="composer-head">
|
||
<span class="composer-title">➕ Nouvelle issue</span>
|
||
<span class="composer-target">arrive dans
|
||
<strong>{{ column_labels.backlog }}</strong>
|
||
</span>
|
||
</div>
|
||
<div class="composer-main">
|
||
<input type="text" id="new-issue-title" maxlength="255"
|
||
placeholder="Titre de l'issue..." required>
|
||
<button type="submit" class="btn-save btn-inline">Créer l'issue</button>
|
||
</div>
|
||
<details class="composer-desc" id="new-issue-desc">
|
||
<summary><span class="composer-desc-label">Ajouter une description</span><span class="composer-chevron" aria-hidden="true">▾</span></summary>
|
||
<textarea id="new-issue-body" rows="5" maxlength="100000"
|
||
placeholder="Description (markdown)..."></textarea>
|
||
<p class="composer-hint">Markdown accepté · Ctrl+Entrée pour créer l'issue</p>
|
||
</details>
|
||
</form>
|
||
</div>
|
||
|
||
<main class="board-container">
|
||
<div class="kanban-board">
|
||
{% for col in column_keys %}
|
||
<div class="kanban-column"
|
||
data-column="{{ col }}">
|
||
<div class="column-header" style="border-top: 3px solid {{ column_colors[col] }}">
|
||
<span class="column-title">{{ column_labels[col] }}</span>
|
||
{% set limit = wip_limits.get(col) %}
|
||
<span class="column-count{% if limit and columns[col]|length > limit %} over{% endif %}"
|
||
{% if limit %}data-limit="{{ limit }}" title="Limite WIP : {{ limit }}"{% endif %}>{% if limit %}{{ columns[col]|length }}/{{ limit }}{% else %}{{ columns[col]|length }}{% endif %}</span>
|
||
</div>
|
||
<div class="column-cards" data-column="{{ col }}">
|
||
{% if not columns[col] %}
|
||
<p class="column-empty">Glissez une carte ici</p>
|
||
{% endif %}
|
||
{% for issue in columns[col] %}
|
||
{% include "_card.html" %}
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
<!-- Notes panel: collapsible + resizable + autosave -->
|
||
<aside class="notes-panel" id="notes-panel">
|
||
<div class="notes-resize" id="notes-resize" title="Glisser pour ajuster la largeur"></div>
|
||
<div class="notes-head">
|
||
<h3>📝 Notes du projet</h3>
|
||
<button type="button" id="notes-toggle" class="btn-sm notes-toggle"
|
||
title="Replier / déplier le panneau">⤢</button>
|
||
</div>
|
||
<div class="notes-body-wrap">
|
||
<p class="notes-hint">Contexte libre, propre à Kanbante — il ne part pas dans Gitea. Enregistrement automatique.</p>
|
||
<form id="notes-form">
|
||
<input type="hidden" name="repo_full_name" value="{{ full_name }}">
|
||
<textarea name="note" id="notes-text" rows="10"
|
||
placeholder="Notes, idées, liens...">{{ notes }}</textarea>
|
||
<div class="notes-foot">
|
||
<span id="notes-status" class="notes-status"></span>
|
||
<button type="submit" class="btn-save">💾 Sauvegarder</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</aside>
|
||
</main>
|
||
|
||
<!-- Label manager modal -->
|
||
<div id="label-modal" class="modal" hidden>
|
||
<div class="modal-box">
|
||
<div class="detail-head">
|
||
<h2>🏷️ Étiquettes de {{ full_name }}</h2>
|
||
<button id="label-modal-close" class="btn-sm" type="button">✕</button>
|
||
</div>
|
||
<p class="notes-hint">Ces étiquettes vivent dans Gitea : les créer ou les supprimer ici les modifie pour tout le dépôt.</p>
|
||
<div id="label-list" class="label-list"></div>
|
||
<form id="label-create-form" class="label-create-form">
|
||
<input type="text" id="new-label-name" maxlength="50" placeholder="Nom de la nouvelle étiquette" required>
|
||
<input type="color" id="new-label-color" value="#7c5cfc" title="Couleur">
|
||
<button type="submit" class="btn-save btn-inline">Créer</button>
|
||
</form>
|
||
<div class="label-swatches">
|
||
{% for c in ['e11d48','f59e0b','10b981','0ea5e9','7c5cfc','ec4899','64748b','84cc16'] %}
|
||
<button type="button" class="swatch" data-color="#{{ c }}" style="background: #{{ c }}" title="#{{ c }}"></button>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Card detail drawer: issue body, comments, comment form -->
|
||
<div id="detail-overlay" class="detail-overlay" hidden></div>
|
||
<aside id="card-detail" class="card-detail" hidden>
|
||
<div class="detail-head">
|
||
<span id="detail-number" class="card-id"></span>
|
||
<span id="detail-state" class="chip"></span>
|
||
<button id="detail-close" class="btn-sm" type="button">✕</button>
|
||
</div>
|
||
<h2 id="detail-title"></h2>
|
||
<div id="detail-meta" class="detail-meta"></div>
|
||
<div id="detail-labels" class="card-labels"></div>
|
||
<div class="detail-labels-manage">
|
||
<span class="notes-hint">Étiquettes de l'issue — cliquez pour ajouter / retirer :</span>
|
||
<div id="detail-label-toggles" class="label-toggles"></div>
|
||
</div>
|
||
<div id="detail-code" class="detail-code"></div>
|
||
<div id="detail-body" class="detail-body"></div>
|
||
<div class="detail-actions">
|
||
<button id="detail-edit-btn" class="btn-sm" type="button">✏️ Modifier le titre et la description</button>
|
||
</div>
|
||
<form id="detail-edit-form" hidden>
|
||
<input type="text" id="detail-title-input" maxlength="255" placeholder="Titre">
|
||
<textarea id="detail-body-input" rows="10" maxlength="100000"
|
||
placeholder="Description (markdown)..."></textarea>
|
||
<div class="detail-actions">
|
||
<button type="submit" class="btn-save btn-inline">💾 Enregistrer</button>
|
||
<button type="button" id="detail-edit-cancel" class="btn-sm">Annuler</button>
|
||
</div>
|
||
</form>
|
||
<h3 class="detail-comments-title">📎 Pièces jointes</h3>
|
||
<div id="detail-assets"></div>
|
||
<form id="asset-form" class="asset-form">
|
||
<input type="file" id="asset-file">
|
||
<button type="submit" class="btn-sm">📎 Joindre le fichier</button>
|
||
</form>
|
||
<h3 class="detail-comments-title">💬 Commentaires</h3>
|
||
<div id="detail-comments"></div>
|
||
<form id="comment-form">
|
||
<textarea id="comment-body" rows="3" maxlength="10000"
|
||
placeholder="Écrire un commentaire (markdown)..."></textarea>
|
||
<button type="submit" class="btn-save">💬 Commenter dans Gitea</button>
|
||
</form>
|
||
<p class="detail-foot"><a id="detail-gitea-link" href="#" target="_blank">Ouvrir dans Gitea ↗</a></p>
|
||
</aside>
|
||
|
||
<footer>
|
||
<span>{{ full_name }}</span>
|
||
{% if repo_info.updated_at %}
|
||
<span>Mis à jour {{ repo_info.updated_at[:10] }}</span>
|
||
{% endif %}
|
||
</footer>
|
||
<script src="/static/js/board-live.js" defer></script>
|
||
<script src="/static/js/today.js" defer></script>
|
||
{% include "_palette.html" %}
|
||
<script src="/static/js/palette.js" defer></script>
|
||
</body>
|
||
</html>
|