Kanbante 0.45.9 : barre v0.3.0 — liens Hub du menu compte, Profil devient un lien Hub (branche /profile retirée), URL Hub résolue comme les sœurs

This commit is contained in:
Spark
2026-11-04 21:49:59 +00:00
parent 9bd3472b3c
commit b039657b84
5 changed files with 126 additions and 26 deletions
+11 -2
View File
@@ -181,7 +181,7 @@ from urllib.parse import urlparse
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
APP_VERSION = "0.45.7" APP_VERSION = "0.45.9"
def _env_bool(name: str, default: bool) -> bool: def _env_bool(name: str, default: bool) -> bool:
@@ -236,7 +236,7 @@ def _env_wip_limits(name: str) -> dict[str, int]:
# du service (élargie en 0.32.2) ; 4) défaut officiel. # du service (élargie en 0.32.2) ; 4) défaut officiel.
_MOTIF_HOTE_AGENT = re.compile(r"agent([a-z0-9-]*)\.dracodev\.net") _MOTIF_HOTE_AGENT = re.compile(r"agent([a-z0-9-]*)\.dracodev\.net")
_MOTIF_HOTE_PUBLIC = re.compile( _MOTIF_HOTE_PUBLIC = re.compile(
r"(?:og|flowdeck|tiktak|kanbante|shaarit|agent)([a-z0-9-]*)\.dracodev\.net" r"(?:og|flowdeck|tiktak|kanbante|shaarit|agent|hub)([a-z0-9-]*)\.dracodev\.net"
) )
@@ -311,6 +311,7 @@ class UrlsDraco:
flowdeck_url: str flowdeck_url: str
tiktak_url: str tiktak_url: str
shaarit_url: str # ShaarIt (barre v0.2.0 ; explicite = DRACO_SHAARIT_URL) shaarit_url: str # ShaarIt (barre v0.2.0 ; explicite = DRACO_SHAARIT_URL)
hub_url: str # Hub (barre v0.3.0 ; explicite = DRACO_HUB_URL)
public_url: str # Kanbante elle-même (KANBANTE_PUBLIC_URL) public_url: str # Kanbante elle-même (KANBANTE_PUBLIC_URL)
agent_url: str # base du service d'agents (panneau + CSP) agent_url: str # base du service d'agents (panneau + CSP)
@@ -352,6 +353,7 @@ def resoudre_urls_draco(
shaarit_url=resoudre( shaarit_url=resoudre(
"DRACO_SHAARIT_URL", "shaarit", base.shaarit_url "DRACO_SHAARIT_URL", "shaarit", base.shaarit_url
), ),
hub_url=resoudre("DRACO_HUB_URL", "hub", base.hub_url),
public_url=resoudre( public_url=resoudre(
"KANBANTE_PUBLIC_URL", "kanbante", base.public_url "KANBANTE_PUBLIC_URL", "kanbante", base.public_url
), ),
@@ -402,6 +404,7 @@ class Settings:
flowdeck_url: str = "https://flowdeck.dracodev.net" flowdeck_url: str = "https://flowdeck.dracodev.net"
tiktak_url: str = "https://tiktak.dracodev.net" tiktak_url: str = "https://tiktak.dracodev.net"
shaarit_url: str = "https://shaarit.dracodev.net" shaarit_url: str = "https://shaarit.dracodev.net"
hub_url: str = "https://hub.dracodev.net"
agent_url: str = "https://agent.dracodev.net" agent_url: str = "https://agent.dracodev.net"
archive_suggest_days: int = 180 archive_suggest_days: int = 180
agent_evenements_url: str = "https://agent.dracodev.net/api/v1/evenements" agent_evenements_url: str = "https://agent.dracodev.net/api/v1/evenements"
@@ -512,6 +515,12 @@ def _env_settings() -> Settings:
"https://shaarit.dracodev.net", "https://shaarit.dracodev.net",
suffixe_agent, suffixe_agent,
), ),
hub_url=_url_soeur_draco(
"DRACO_HUB_URL",
"hub",
"https://hub.dracodev.net",
suffixe_agent,
),
agent_url=agent_url, agent_url=agent_url,
archive_suggest_days=_env_int("KANBANTE_ARCHIVE_SUGGEST_DAYS", 180), archive_suggest_days=_env_int("KANBANTE_ARCHIVE_SUGGEST_DAYS", 180),
agent_evenements_url=agent_evenements_url, agent_evenements_url=agent_evenements_url,
+1
View File
@@ -2251,6 +2251,7 @@ def render(
"tiktak": _urls.tiktak_url, "tiktak": _urls.tiktak_url,
"kanbante": _urls.public_url, "kanbante": _urls.public_url,
"shaarit": _urls.shaarit_url, "shaarit": _urls.shaarit_url,
"hub": _urls.hub_url,
}, },
) )
context.setdefault("agent_url", _urls.agent_url) context.setdefault("agent_url", _urls.agent_url)
+24 -9
View File
@@ -1,13 +1,19 @@
{# Barre d'apps commune dracodev — Fusion ACC-1 (issue kanbante#28). {# Barre d'apps commune dracodev — Fusion ACC-1 (issue kanbante#28).
Snippet vendangé depuis Projets/dracodev-commons v0.2.0 Snippet vendangé depuis Projets/dracodev-commons v0.3.0
(ui/barre-apps/ @70c837a, PR commons #7) : structure du fragment (ui/barre-apps/, branche hub-menu-compte-v0-3-0 de la PR commons
#9 — HUB-1, fusion #115) : v0.3.0 = menu compte à liens Hub
(Télécharger, À Propos, Aides, Profil-lien ; base
draco_urls.hub en urls.hub ci-dessous) et branche « profil »
de onAction RETIRÉE (voir le commentaire dans la configuration —
la page /profile de Kanbante existe toujours, elle n'est plus
la cible du menu compte). Structure du fragment
commons portée ici ; seule adaptation locale (0.32.0, dev/prod) commons portée ici ; seule adaptation locale (0.32.0, dev/prod)
= les URL des apps et l'adresse du service d'agents sont = les URL des apps et l'adresse du service d'agents sont
INJECTÉES par l'hôte depuis app.config (draco_urls / agent_url, INJECTÉES par l'hôte depuis app.config (draco_urls / agent_url,
défauts = noms officiels) — aucun nom public codé en dur dans défauts = noms officiels) — aucun nom public codé en dur dans
ce gabarit ni dans draco-panneau.js. Le CSS et le JS, eux, sont ce gabarit ni dans draco-panneau.js. Le CSS et le JS, eux, sont
vendangés VERBATIM (static/css/draco-barre.css, vendangés VERBATIM (static/css/draco-barre.css,
static/js/draco-barre.js — voir CHANGELOG 0.45.6). static/js/draco-barre.js — voir CHANGELOG 0.45.9).
v0.2.0 (phase 3 ShaarIt) : nouvel onglet ShaarIt v0.2.0 (phase 3 ShaarIt) : nouvel onglet ShaarIt
(data-app="shaarit", draco_urls.shaarit), APRÈS Kanbante et (data-app="shaarit", draco_urls.shaarit), APRÈS Kanbante et
AVANT l'onglet agent ; couleur émeraude #059669, logo AVANT l'onglet agent ; couleur émeraude #059669, logo
@@ -112,6 +118,12 @@
recherche partout : page /recherche (Fusion #68). */ recherche partout : page /recherche (Fusion #68). */
window.DRACO_BAR_CONFIG = { window.DRACO_BAR_CONFIG = {
current: "kanbante", current: "kanbante",
/* Barre v0.3.0 (HUB-1) : base du Hub résolue par l'hôte
(draco_urls.hub — DRACO_HUB_URL explicite, hôte de la
requête, dérivation par l'agent, défaut officiel) ;
le Hub n'a pas d'onglet, urls.hub alimente les liens
du menu compte. */
urls: { hub: "{{ draco_urls.hub }}/" },
/* v0.1.6 : user = initiale auth_user ou K (draco_avatar). Sans /* v0.1.6 : user = initiale auth_user ou K (draco_avatar). Sans
cfg.user, le nouveau JS dériverait l'initiale du title cfg.user, le nouveau JS dériverait l'initiale du title
("Opérateur Kanbante" → "O"), qui est un libellé de rôle et ("Opérateur Kanbante" → "O"), qui est un libellé de rôle et
@@ -132,12 +144,15 @@
}; };
if (act === "domaine") { try { localStorage.setItem("draco_domain", el.dataset.dom); } catch (e) { } return; } if (act === "domaine") { try { localStorage.setItem("draco_domain", el.dataset.dom); } catch (e) { } return; }
if (act === "rail") { var b = document.getElementById("side-collapse"); if (b) b.click(); return; } if (act === "rail") { var b = document.getElementById("side-collapse"); if (b) b.click(); return; }
/* Menu compte (image 2) : ces deux actions étaient relayées /* Menu compte — barre v0.3.0 (HUB-1) : « Profil » n'est
par draco-barre.js mais jamais prises en charge ici — PLUS relayé par la barre : c'est un vrai lien vers
le menu se fermait sans rien faire. En mobile, c'est le <hub>/profil (un seul Profil, celui du Hub — décision
seul accès au profil et à la déconnexion (le pied de du plan Hub). L'ancienne branche onAction("profil")
sidebar était masqué). */ qui menait à la page /profile propre à Kanbante est
if (act === "profil") { location.href = "/profile"; return; } donc RETIRÉE : la page /profile elle-même continue
d'exister (jetons API, réglages du compte Kanbante),
mais elle n'est plus la cible du menu compte de la
barre. « Déconnexion » reste relayée, inchangée. */
if (act === "deconnexion") { location.href = "/logout"; return; } if (act === "deconnexion") { location.href = "/logout"; return; }
if (act === "palette") { location.href = "/recherche"; return; } if (act === "palette") { location.href = "/recherche"; return; }
if (act === "alertes") { if (window.DRACO_ALERTES) { window.DRACO_ALERTES.open(); } else { location.href = "/activity"; } return; } if (act === "alertes") { if (window.DRACO_ALERTES) { window.DRACO_ALERTES.open(); } else { location.href = "/activity"; } return; }
+4
View File
@@ -20,6 +20,10 @@
le clair via data-theme="light" héritait quand même du sombre le clair via data-theme="light" héritait quand même du sombre
système (piège constaté dans les copies vendangées de système (piège constaté dans les copies vendangées de
Kanbante/Flowdeck ; les re-vendanges de la v0.2.0 le corrigent). Kanbante/Flowdeck ; les re-vendanges de la v0.2.0 le corrigent).
v0.3.0 (HUB-1) : aucun style nouveau — les liens du Hub du menu
compte (Télécharger, À Propos, Aides, Profil) réutilisent
.draco-menu-item (déjà ancre-compatible : text-decoration none)
et le séparateur .draco-menu-sep du menu des applications.
Jetons repris du prototype validé Console v7.2. Jetons repris du prototype validé Console v7.2.
Thème : clair par défaut, sombre via [data-theme="dark"] sur <html> Thème : clair par défaut, sombre via [data-theme="dark"] sur <html>
ou prefers-color-scheme si l'app intégratrice ne force rien ou prefers-color-scheme si l'app intégratrice ne force rien
+86 -15
View File
@@ -14,6 +14,21 @@
* contrat que les autres apps), entrée APP_LABELS ; l'onglet * contrat que les autres apps), entrée APP_LABELS ; l'onglet
* (data-app="shaarit", après Kanbante, avant agent) est repris * (data-app="shaarit", après Kanbante, avant agent) est repris
* automatiquement par la construction du menu de la marque. * automatiquement par la construction du menu de la marque.
* v0.3.0 (carte HUB-1, fusion #115) : le Hub, point central de la
* suite — nouvelle clé d'URL « hub » (jeton {{URL_HUB}} côté hôte,
* DRACO_BAR_CONFIG.urls.hub), défaut officiel
* https://hub.dracodev.net/, dérivation -dev hub-dev comme les
* sœurs. Le menu compte gagne trois vrais liens (patron
* buildAppsMenu : <a href>, classe draco-menu-item) — Télécharger
* → <hub>/telecharger, À Propos → <hub>/a-propos, Aides →
* <hub>/aide — et « Profil » devient lui aussi un lien, vers
* <hub>/profil (il n'est plus relayé aux hôtes : un seul Profil,
* celui du Hub). « Déconnexion » reste l'action relayée
* (data-compte-act="deconnexion" / onAction), inchangée.
* refreshMenuHrefs() resynchronise aussi les liens du Hub à
* l'ouverture des menus. Le Hub n'a pas d'onglet dans la barre :
* comme spark, sa clé est résolue et exposée via DRACO_BAR.urls,
* sans étape « href rendu » (voir « URL » ci-dessous).
* *
* Aucun gestionnaire inline : un seul écouteur délégué sur le document * Aucun gestionnaire inline : un seul écouteur délégué sur le document
* (patron validé par le prototype — les onclick du HTML généré sont * (patron validé par le prototype — les onclick du HTML généré sont
@@ -33,7 +48,8 @@
* kanbante: "https://kanbante.dracodev.net/", * kanbante: "https://kanbante.dracodev.net/",
* shaarit: "https://shaarit.dracodev.net/", * shaarit: "https://shaarit.dracodev.net/",
* agent: "https://agent.dracodev.net/", * agent: "https://agent.dracodev.net/",
* spark: "https://spark.dracodev.net/" * spark: "https://spark.dracodev.net/",
* hub: "https://hub.dracodev.net/"
* }, * },
* onAction: function (act, el) { … } // l'app relaie les actions * onAction: function (act, el) { … } // l'app relaie les actions
* } // qu'elle ne connaît pas * } // qu'elle ne connaît pas
@@ -67,6 +83,12 @@
* la marque et DRACO_BAR.urls. Même résolution pour shaarit (v0.2.0) : * la marque et DRACO_BAR.urls. Même résolution pour shaarit (v0.2.0) :
* explicite > dérivation -dev shaarit-dev > href rendu * explicite > dérivation -dev shaarit-dev > href rendu
* ({{URL_SHAARIT}}) > défaut officiel. * ({{URL_SHAARIT}}) > défaut officiel.
* Cas hub (v0.3.0) : PAS d'onglet, donc pas d'étape « href rendu » —
* explicite (DRACO_BAR_CONFIG.urls.hub, alimenté par le jeton
* {{URL_HUB}} remplacé côté serveur par l'hôte) > dérivation -dev
* hub-dev sur hôte -dev > défaut officiel
* https://hub.dracodev.net/. La base résolue sert les quatre liens
* du menu compte (telecharger, a-propos, aide, profil).
* Actions émises (data-act) : rail, palette, domaine (data-dom), * Actions émises (data-act) : rail, palette, domaine (data-dom),
* alertes, spark, rappel-entete. L'app intégratrice décide de chacune * alertes, spark, rappel-entete. L'app intégratrice décide de chacune
* (ouvrir la palette, le panneau Spark, changer de domaine…). * (ouvrir la palette, le panneau Spark, changer de domaine…).
@@ -141,6 +163,14 @@
* mais le menu affiche l'identité même sans gestionnaire hôte. * mais le menu affiche l'identité même sans gestionnaire hôte.
* Accessibilité : vrais <button>, aria-haspopup / aria-expanded, * Accessibilité : vrais <button>, aria-haspopup / aria-expanded,
* role="menu" / "menuitem", fermeture par Échap et clic extérieur. * role="menu" / "menuitem", fermeture par Échap et clic extérieur.
* Menu compte (v0.3.0) — Profil n'est PLUS relayé : c'est un lien
* vers <hub>/profil, comme Télécharger / À Propos / Aides (liens
* Hub, data-hub-link, href resynchronisés à chaque ouverture via
* refreshCompteHrefs / refreshMenuHrefs). Seule « Déconnexion »
* reste relayée à l'hôte (data-compte-act="deconnexion"), inchangée.
* Les hôtes qui traitaient onAction("profil") (Kanbante → /profile)
* voient ce comportement remplacé par le lien Hub — décision du
* plan Hub : un seul Profil, celui du Hub.
*/ */
(function () { (function () {
"use strict"; "use strict";
@@ -155,7 +185,8 @@
kanbante: "https://kanbante.dracodev.net/", kanbante: "https://kanbante.dracodev.net/",
shaarit: "https://shaarit.dracodev.net/", shaarit: "https://shaarit.dracodev.net/",
agent: "https://agent.dracodev.net/", agent: "https://agent.dracodev.net/",
spark: "https://spark.dracodev.net/" spark: "https://spark.dracodev.net/",
hub: "https://hub.dracodev.net/"
}; };
/* Dérivation -dev (v0.1.6) — appliquée UNIQUEMENT quand l'hôte courant /* Dérivation -dev (v0.1.6) — appliquée UNIQUEMENT quand l'hôte courant
@@ -168,7 +199,8 @@
tiktak: "https://tiktak-dev.dracodev.net/", tiktak: "https://tiktak-dev.dracodev.net/",
kanbante: "https://kanbante-dev.dracodev.net/", kanbante: "https://kanbante-dev.dracodev.net/",
shaarit: "https://shaarit-dev.dracodev.net/", shaarit: "https://shaarit-dev.dracodev.net/",
agent: "https://agent-dev.dracodev.net/" agent: "https://agent-dev.dracodev.net/",
hub: "https://hub-dev.dracodev.net/"
}; };
var APP_LABELS = { var APP_LABELS = {
@@ -307,6 +339,28 @@
menu.querySelectorAll(".draco-apps-item").forEach(function (a) { menu.querySelectorAll(".draco-apps-item").forEach(function (a) {
if (a.dataset.app && resolvedUrls[a.dataset.app]) a.setAttribute("href", resolvedUrls[a.dataset.app]); if (a.dataset.app && resolvedUrls[a.dataset.app]) a.setAttribute("href", resolvedUrls[a.dataset.app]);
}); });
/* v0.3.0 : les liens du Hub (menu compte) sont resynchronisés
* eux aussi à l'ouverture d'un menu, pour refléter setUrls et
* la dérivation -dev même s'ils ont été construits avant. */
refreshCompteHrefs();
}
/* Liens du Hub dans le menu compte (v0.3.0) : chemin → libellé.
* « Profil » est le quatrième lien (vers <hub>/profil) ; il
* remplace l'ancien item relayé « profil ». */
var HUB_LINKS = [
["telecharger", "Télécharger"],
["a-propos", "À Propos"],
["aide", "Aides"],
["profil", "Profil"]
];
function hubHref(path) {
return withSlash(resolvedUrls.hub || DEFAULT_URLS.hub) + path;
}
function refreshCompteHrefs() {
if (!compteMenu) return;
compteMenu.querySelectorAll("[data-hub-link]").forEach(function (a) {
a.setAttribute("href", hubHref(a.getAttribute("data-hub-link")));
});
} }
function togglePopup(menu, btn, force) { function togglePopup(menu, btn, force) {
if (!menu) return; if (!menu) return;
@@ -429,10 +483,14 @@
if (!appsMenu.hidden) lastOpener = brand; if (!appsMenu.hidden) lastOpener = brand;
} }
/* Menu compte (v0.1.6) — en-tête d'identité + Profil / Déconnexion /* Menu compte (v0.1.6 ; v0.3.0 pour les liens) — en-tête
* relayés à l'hôte. L'en-tête est rafraîchi à chaque ouverture, pour * d'identité, puis les liens du Hub (Télécharger, À Propos,
* refléter un title posé après coup par l'hôte (ex. ObsiGate, qui * Aides, Profil — vrais <a href>, même patron que le menu des
* remplit l'avatar depuis /api/auth/me après chargement). */ * applications), un séparateur, puis « Déconnexion » relayée à
* l'hôte. L'en-tête et les href sont rafraîchis à chaque
* ouverture, pour refléter un title posé après coup par l'hôte
* (ex. ObsiGate, qui remplit l'avatar depuis /api/auth/me après
* chargement) et la résolution d'URL la plus récente. */
function buildCompteMenu() { function buildCompteMenu() {
if (!bar || !avatarBtn || compteMenu) return; if (!bar || !avatarBtn || compteMenu) return;
compteMenu = document.createElement("div"); compteMenu = document.createElement("div");
@@ -443,15 +501,26 @@
var head = document.createElement("div"); var head = document.createElement("div");
head.className = "draco-compte-nom"; head.className = "draco-compte-nom";
compteMenu.appendChild(head); compteMenu.appendChild(head);
[["profil", "Profil"], ["deconnexion", "Déconnexion"]].forEach(function (pair) { HUB_LINKS.forEach(function (pair) {
var b = document.createElement("button"); var a = document.createElement("a");
b.type = "button"; a.className = "draco-menu-item";
b.className = "draco-menu-item"; a.href = hubHref(pair[0]);
b.setAttribute("data-compte-act", pair[0]); a.setAttribute("data-hub-link", pair[0]);
b.setAttribute("role", "menuitem"); a.setAttribute("role", "menuitem");
b.textContent = pair[1]; a.textContent = pair[1];
compteMenu.appendChild(b); compteMenu.appendChild(a);
}); });
var sep = document.createElement("div");
sep.className = "draco-menu-sep";
sep.setAttribute("aria-hidden", "true");
compteMenu.appendChild(sep);
var b = document.createElement("button");
b.type = "button";
b.className = "draco-menu-item";
b.setAttribute("data-compte-act", "deconnexion");
b.setAttribute("role", "menuitem");
b.textContent = "Déconnexion";
compteMenu.appendChild(b);
bar.appendChild(compteMenu); bar.appendChild(compteMenu);
} }
function refreshCompteMenu() { function refreshCompteMenu() {
@@ -459,6 +528,7 @@
var head = compteMenu.querySelector(".draco-compte-nom"); var head = compteMenu.querySelector(".draco-compte-nom");
var name = displayName(); var name = displayName();
if (head) head.textContent = name || "Compte"; if (head) head.textContent = name || "Compte";
refreshCompteHrefs();
} }
function toggleCompteMenu(force) { function toggleCompteMenu(force) {
buildCompteMenu(); buildCompteMenu();
@@ -555,6 +625,7 @@
resolvedUrls = resolveUrls(); resolvedUrls = resolveUrls();
window.DRACO_BAR.urls = resolvedUrls; window.DRACO_BAR.urls = resolvedUrls;
applyUrls(resolvedUrls); applyUrls(resolvedUrls);
refreshCompteHrefs();
} }
}; };