Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53f54b1b79 | ||
|
|
80fc260a40 |
@@ -1,5 +1,51 @@
|
||||
# Changelog
|
||||
|
||||
## 0.37.1 — 2026-10-26
|
||||
|
||||
### Ajouté — version du service d'agents dans le panneau Spark (mode sidebar)
|
||||
|
||||
Carte fusion #64. Le pied du panneau Spark (`static/js/draco-panneau.js`)
|
||||
affiche désormais la ligne discrète et permanente « Service d'agents
|
||||
vX », comme la console pleine page. La version est lue **en direct**
|
||||
dans la santé du service (`GET /healthz` de l'origine que le panneau
|
||||
connaît déjà), à l'ouverture du panneau, avec cache de session — jamais
|
||||
une valeur codée en dur ; service injoignable ou panneau non configuré
|
||||
= rien d'affiché, aucune erreur visible.
|
||||
|
||||
## 0.37.0 — 2026-10-26
|
||||
|
||||
### Ajouté — tri « En attente de revue » sur le dashboard
|
||||
|
||||
Demande de Bruno : pouvoir ordonner les projets — section
|
||||
**Épinglés** en tête — par ce qui attend sa validation.
|
||||
|
||||
- Nouveau critère dans le sélecteur de tri du dashboard,
|
||||
en première place après « Par défaut » : **🔍 En attente
|
||||
de revue ↓** — les projets s'ordonnent par le nombre de
|
||||
cartes dans la colonne de validation (clé `review` de
|
||||
l'espace), décroissant.
|
||||
- Le compteur était déjà calculé pour les chips de
|
||||
progression des cartes : il est maintenant exposé en
|
||||
`data-review` sur chaque carte projet et consommé par le
|
||||
moteur de tri partagé — le critère s'applique à **toutes
|
||||
les grilles** (Épinglés, Actifs, Inactifs, Archivés),
|
||||
avec ou sans regroupement par propriétaire, et la
|
||||
préférence est mémorisée comme les autres tris.
|
||||
- Les critères existants (activité Gitea, activité kanban,
|
||||
issues ouvertes, nom) sont inchangés.
|
||||
|
||||
### Corrigé — sens des tris numériques du dashboard
|
||||
|
||||
Le contrôle en navigateur réel a révélé que le tri
|
||||
« Issues ouvertes ↓ » triait en réalité **croissant**
|
||||
depuis son introduction : le comparateur partagé inversait
|
||||
les clés numériques. Les modes numériques (`open` et le
|
||||
nouveau `review`) trient maintenant en soustraction de
|
||||
clés — le plus grand compteur en premier, comme l'annonce
|
||||
le « ↓ ». Vérifié sur les données réelles : Épinglés
|
||||
ordonnés 196, 95, 32, 5, 4 en attente de revue.
|
||||
|
||||
|
||||
## 0.36.0 — 2026-10-26
|
||||
|
||||
### Ajouté — outil MCP `move_issue` (suivi de la vague H3 du service d'agents)
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ from urllib.parse import urlparse
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
APP_VERSION = "0.36.0"
|
||||
APP_VERSION = "0.37.1"
|
||||
|
||||
|
||||
def _env_bool(name: str, default: bool) -> bool:
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<label class="dash-tool">Tri
|
||||
<select id="dash-sort">
|
||||
<option value="default">Par défaut</option>
|
||||
<option value="review">🔍 En attente de revue ↓</option>
|
||||
<option value="updated">Activité Gitea récente</option>
|
||||
<option value="activity">Activité kanban récente</option>
|
||||
<option value="open">Issues ouvertes ↓</option>
|
||||
@@ -85,6 +86,7 @@
|
||||
data-full="{{ full }}" data-home="{{ repo.home_tab or '' }}"
|
||||
data-name="{{ repo.name|lower }}" data-owner="{{ repo.owner.login }}"
|
||||
data-updated="{{ repo.updated_at }}" data-open="{{ repo.open_issues_count or 0 }}"
|
||||
data-review="{{ stats.get(full, {}).get('review', 0) if stats else 0 }}"
|
||||
data-activity="{{ repo.activity.last_at if repo.activity else '' }}"
|
||||
data-search="{{ (repo.name ~ ' ' ~ repo.full_name ~ ' ' ~ (repo.description or ''))|lower }}"
|
||||
x-show="search === '' || $el.dataset.search.includes(search.toLowerCase())">
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "kanbante"
|
||||
version = "0.36.0"
|
||||
version = "0.37.1"
|
||||
description = "Kanban project manager integrated with Gitea"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
function cardKey(card, mode) {
|
||||
if (mode === 'name') return (card.getAttribute('data-name') || '').toLowerCase();
|
||||
if (mode === 'open') return -(parseInt(card.getAttribute('data-open') || '0', 10));
|
||||
if (mode === 'review') return -(parseInt(card.getAttribute('data-review') || '0', 10));
|
||||
if (mode === 'updated') return card.getAttribute('data-updated') || '';
|
||||
if (mode === 'activity') return card.getAttribute('data-activity') || '';
|
||||
return null; // 'default' : ordre serveur, on ne touche à rien
|
||||
@@ -52,6 +53,13 @@
|
||||
if (isNaN(tb)) return -1;
|
||||
return tb - ta;
|
||||
}
|
||||
// Modes numériques (open, review) : les clés sont
|
||||
// des compteurs niés (-n) — ka - kb donne donc le
|
||||
// plus grand compteur en premier, comme l'annonce
|
||||
// le « ↓ » des options. (Avant 0.37.0, la
|
||||
// comparaison générique ci-dessous inversait ces
|
||||
// deux tris : ils ressortaient croissants.)
|
||||
if (mode === 'open' || mode === 'review') return ka - kb;
|
||||
if (ka < kb) return mode === 'name' ? -1 : 1;
|
||||
if (ka > kb) return mode === 'name' ? 1 : -1;
|
||||
return 0;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
var etatConnu = false;
|
||||
var root = null, msgsEl = null, etatEl = null, inputEl = null, sendBtn = null;
|
||||
var titreEl = null, tiroirEl = null;
|
||||
var versionEl = null, versionConnue = "", versionMaj = 0;
|
||||
|
||||
function domaine() {
|
||||
try { return localStorage.getItem("draco_domain") || "pro"; } catch (e) { return "pro"; }
|
||||
@@ -268,6 +269,7 @@
|
||||
' <input type="text" placeholder="Écrire à Spark…" autocomplete="off" aria-label="Message à Spark">' +
|
||||
' <button type="submit">Envoyer</button></form>' +
|
||||
' <div class="draco-panneau-note">Conversation réelle, sous-agents (J3) et missions longues (J5) vers les exécuteurs configurés ; toute écriture dans les apps passe par une approbation.</div>' +
|
||||
' <div class="draco-panneau-version" style="margin-top:6px;font-size:11.5px;opacity:.6" hidden></div>' +
|
||||
'</div>';
|
||||
document.body.appendChild(root);
|
||||
msgsEl = root.querySelector(".draco-panneau-msgs");
|
||||
@@ -276,6 +278,7 @@
|
||||
sendBtn = root.querySelector("button[type=submit]");
|
||||
titreEl = root.querySelector(".d-titre");
|
||||
tiroirEl = root.querySelector(".draco-discussions");
|
||||
versionEl = root.querySelector(".draco-panneau-version");
|
||||
root.querySelector(".fermer").addEventListener("click", fermer);
|
||||
root.querySelector('[data-disc="liste"]').addEventListener("click", basculerTiroir);
|
||||
root.querySelector('[data-disc="nouvelle"]').addEventListener("click", nouvelleDiscussion);
|
||||
@@ -330,6 +333,35 @@
|
||||
titreEl.title = titreEl.textContent;
|
||||
}
|
||||
|
||||
/* ── Version du service : lue en direct dans la santé de
|
||||
* l'agent (GET /healthz → champ « version », la même source que
|
||||
* la console) à l'origine que le panneau connaît déjà. Cache de
|
||||
* session (5 min), rafraîchie à l'ouverture du panneau, au même
|
||||
* rythme que la vérification d'identité. Jamais de valeur codée
|
||||
* en dur : source injoignable ou réponse illisible = la ligne
|
||||
* reste masquée — pas de fausse version, pas d'erreur visible. */
|
||||
function afficherVersion() {
|
||||
if (!versionEl) return;
|
||||
if (versionConnue) {
|
||||
versionEl.textContent = "Service d'agents v" + versionConnue;
|
||||
versionEl.hidden = false;
|
||||
}
|
||||
}
|
||||
function chargerVersion() {
|
||||
if (!API || !versionEl) return;
|
||||
if (versionConnue && Date.now() - versionMaj < 300000) { afficherVersion(); return; }
|
||||
fetch(API + "/healthz")
|
||||
.then(function (r) { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
|
||||
.then(function (d) {
|
||||
if (d && typeof d.version === "string" && /^[0-9]+\.[0-9]+\.[0-9]+/.test(d.version)) {
|
||||
versionConnue = d.version;
|
||||
versionMaj = Date.now();
|
||||
afficherVersion();
|
||||
}
|
||||
})
|
||||
.catch(function () { /* service injoignable : rien d'affiché */ });
|
||||
}
|
||||
|
||||
function verifierIdentite() {
|
||||
if (etatConnu) return;
|
||||
if (!API) {
|
||||
@@ -812,6 +844,7 @@
|
||||
root.classList.add("open");
|
||||
appliquerTheme();
|
||||
verifierIdentite();
|
||||
chargerVersion();
|
||||
setTimeout(function () { inputEl.focus(); }, 300);
|
||||
}
|
||||
function fermer() { if (root) root.classList.remove("open"); }
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Palier 25 (0.37.0): tri « En attente de revue » du dashboard —
|
||||
les projets (section Épinglés incluse) s'ordonnent par le nombre
|
||||
de cartes dans la colonne de validation."""
|
||||
|
||||
from app import models
|
||||
|
||||
|
||||
def test_dashboard_sort_offers_review_mode(client):
|
||||
r = client.get("/")
|
||||
assert r.status_code == 200
|
||||
assert '<option value="review">🔍 En attente de revue ↓</option>' in r.text
|
||||
|
||||
|
||||
def test_dashboard_cards_carry_review_count(client):
|
||||
# Aucune carte en révision au départ.
|
||||
r = client.get("/")
|
||||
assert 'data-review="0"' in r.text
|
||||
# Une carte passe en Révision : le compteur de SA carte monte.
|
||||
models.move_issue("Projets/demo", 5, "review")
|
||||
models.move_issue("Projets/demo", 1, "review")
|
||||
r = client.get("/")
|
||||
assert 'data-review="2"' in r.text
|
||||
|
||||
|
||||
def test_dashboard_js_knows_review_mode(client):
|
||||
# Le moteur de tri partagé est servi tel quel : le mode
|
||||
# 'review' doit y figurer (tri décroissant sur data-review).
|
||||
r = client.get("/static/js/dashboard.js")
|
||||
assert r.status_code == 200
|
||||
assert "mode === 'review'" in r.text
|
||||
assert "data-review" in r.text
|
||||
# Le sens : les modes numeriques trient en ka - kb (cles
|
||||
# niees = plus grand compteur d\'abord). Sans cette
|
||||
# branche, le comparateur generique inversait le tri :
|
||||
# bug attrape en navigateur reel sur le tri historique.
|
||||
assert "return ka - kb" in r.text
|
||||
Reference in New Issue
Block a user