Compare commits

...
Author SHA1 Message Date
bruno c9f7754f5f Changelog 7.84.5 : texte parasite, onglets recherche, CORS console (PR #37/#38/#40)
FlowDeck CI / lint (push) Failing after 0s
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:21:42 -04:00
bruno 43e416a889 Bump 7.84.5
FlowDeck CI / lint (push) Failing after 2s
FlowDeck CI / test (push) Failing after 1s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:21:38 -04:00
bruno fefd9b1ad3 Merge pull request 'CORS recherche : autoriser la console Spark (agent prod+dev)' (#40) from federation-recherche-console into main
FlowDeck CI / lint (push) Failing after 1s
FlowDeck CI / test (push) Failing after 1s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:17:04 -04:00
bruno 3b43be3761 Merge pull request 'Recherche : onglets visibles apres deploiement (base console explicite + purge cache SW)' (#38) from flowdeck-recherche-onglets into main
FlowDeck CI / lint (push) Failing after 1s
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:17:01 -04:00
bruno 972d40a75f Merge pull request 'Barre : supprimer le texte parasite « Chantier 5 » rendu au-dessus du header' (#37) from flowdeck-texte-parasite into main
FlowDeck CI / lint (push) Failing after 0s
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:16:59 -04:00
bruno fb942bc871 Tests CORS recherche: origines agent autorisees, tiers refuse
FlowDeck CI / lint (push) Failing after 0s
FlowDeck CI / test (push) Failing after 1s
FlowDeck CI / docker (push) Skipped
FlowDeck CI / lint (pull_request) Failing after 3s
FlowDeck CI / test (pull_request) Failing after 1s
FlowDeck CI / docker (pull_request) Skipped
2026-10-28 16:11:58 -04:00
bruno b8ebea1479 CORS recherche: autoriser les origines agent (console Spark) prod+dev
FlowDeck CI / lint (push) Failing after 2s
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:11:53 -04:00
bruno ee065978b2 Recherche onglets (defaut 6) : tests/test_recherche_onglets.py
FlowDeck CI / lint (push) Failing after 1s
FlowDeck CI / test (push) Failing after 2s
FlowDeck CI / docker (push) Skipped
FlowDeck CI / lint (pull_request) Failing after 2s
FlowDeck CI / test (pull_request) Failing after 18m37s
FlowDeck CI / docker (pull_request) Skipped
2026-10-28 16:01:30 -04:00
bruno 71c7113a8c Recherche onglets (defaut 6) : static/sw.js
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
FlowDeck CI / lint (push) Failing after 1m52s
2026-10-28 16:01:25 -04:00
bruno c0bf0e8523 Recherche onglets (defaut 6) : app/routers/search.py
FlowDeck CI / lint (push) Failing after 2s
FlowDeck CI / test (push) Failing after 1s
FlowDeck CI / docker (push) Skipped
2026-10-28 16:01:21 -04:00
bruno 9ae054d1ba Recherche onglets (defaut 6) : app/templates/recherche.html
FlowDeck CI / test (push) Failing after 1s
FlowDeck CI / docker (push) Skipped
FlowDeck CI / lint (push) Failing after 1m51s
2026-10-28 16:01:18 -04:00
bruno 1e552a55a4 Tests : aucun texte de chantier rendu par la barre, onglets intacts
FlowDeck CI / test (push) Failing after 3s
FlowDeck CI / docker (push) Skipped
FlowDeck CI / lint (push) Failing after 1s
FlowDeck CI / test (pull_request) Failing after 1s
FlowDeck CI / docker (pull_request) Skipped
FlowDeck CI / lint (pull_request) Failing after 1m53s
2026-10-28 15:59:44 -04:00
bruno fd9df60788 Barre : texte de chantier 5 hors commentaire Jinja supprime du rendu (5e onglet + menu marque intacts)
FlowDeck CI / lint (push) Failing after 0s
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
2026-10-28 15:59:41 -04:00
bruno 984e92b593 Bump Flowdeck 7.84.4 : changelog (alignement recherche console #68)
FlowDeck CI / test (push) Failing after 41m28s
FlowDeck CI / lint (push) Failing after 2s
FlowDeck CI / docker (push) Skipped
2026-10-28 15:06:59 -04:00
bruno 8ba38a69a4 Bump Flowdeck 7.84.4 (alignement recherche console #68)
FlowDeck CI / lint (push) Failing after 2s
FlowDeck CI / test (push) Failing after 0s
FlowDeck CI / docker (push) Skipped
2026-10-28 15:06:55 -04:00
bruno ee477bf2d1 Merge pull request 'recherche : onglet Console Spark sur GET /api/v1/recherche (alignement)' (#36) from align-recherche-console into main
FlowDeck CI / test (push) Failing after 1s
FlowDeck CI / docker (push) Skipped
FlowDeck CI / lint (push) Failing after 1m51s
2026-10-28 15:04:27 -04:00
10 changed files with 202 additions and 18 deletions
+10
View File
@@ -1,3 +1,13 @@
## v7.84.5 (2026-10-28) — Corrections console/recherche : texte parasite, onglets, CORS console
- **Barre (PR #37)** : suppression du texte parasite « Chantier 5 » rendu au-dessus du header.
- **Recherche (PR #38)** : onglets visibles après déploiement (base console explicite + purge cache service worker).
- **CORS recherche (PR #40)** : la recherche Flowdeck autorise désormais la console Spark (agent prod+dev) en inter-origines.
## v7.84.4 (2026-10-28) — Alignement recherche console : onglet Console Spark sur /api/v1/recherche
- **Recherche (#68)** : l'onglet Console Spark de `/recherche` appelle désormais `GET /api/v1/recherche` (au lieu de `/api/search`) et reconstruit les liens profonds console (`?section=…&objet=…`, `disc=`, `activite=`) — les résultats console réels s'affichent enfin dans la page hôte.
## v7.84.3 (2026-10-28) — Corrections recherche/alertes : CORS prod+dev, recherche en onglets, alertes en onglets
- **CORS recherche/alertes (#68/#69)** : allowlist d'origines soeurs prod+dev explicites + credentials, jamais `*` — chaque serveur n'autorisait que l'environnement resolu, d'ou les echecs inter-apps constates.
+1 -1
View File
@@ -1 +1 @@
7.84.3
7.84.5
+11 -2
View File
@@ -9,7 +9,10 @@ Ce module n'autorise donc que :
- le chemin ``/api/search`` (jamais les autres routes, jamais les
écritures) ;
- les origines sœurs : les origines officielles **prod ET dev,
listées explicitement** (``PROD_ORIGINS | DEV_ORIGINS``), **plus**
listées explicitement** (``PROD_ORIGINS | DEV_ORIGINS``), **plus
les origines de la console Spark** (``AGENT_ORIGINS`` : agent prod
ET dev — fédération de la recherche depuis la console,
2026-10-28), **plus**
celles résolues par ``app.services.draco_urls.toutes()``
(explicite > hôte > dérivation > défaut officiel) — jamais ``*``.
Correctif 2026-10-28 (fusion #68/#69, matrice constatée par
@@ -49,6 +52,12 @@ DEV_ORIGINS = frozenset({
"https://kanbante-dev.dracodev.net",
})
AGENT_ORIGINS = frozenset({
"https://agent.dracodev.net",
"https://agent-dev.dracodev.net",
})
# Clés de draco_urls.toutes() qui sont des applications sœurs.
_SOEUR_KEYS = ("obsigate", "flowdeck", "tiktak", "kanbante")
@@ -113,7 +122,7 @@ def sister_origins(resolved: dict | None = None, request_host: str | None = None
# l'environnement de la requête, désormais inclus d'office).
# ``resolved`` n'ajoute que des origines de configuration sans
# jamais retirer une origine officielle.
origins |= PROD_ORIGINS | DEV_ORIGINS
origins |= PROD_ORIGINS | DEV_ORIGINS | AGENT_ORIGINS
return frozenset(origins)
+6 -1
View File
@@ -63,7 +63,12 @@ def recherche_page(request: Request, q: str = Query(default="")):
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
bases = draco_urls.toutes()
template = ENV.get_template("recherche.html")
# Defaut 6 : la base agent est exposee explicitement (data-base-console
# dans recherche.html), comme les 3 autres hotes — recherche.js ne doit
# plus la deviner (derivation -dev / href d'onglet de barre) pour
# l'onglet Console Spark (GET /api/v1/recherche, alignement #36).
return HTMLResponse(template.render(
request=request, q=q.strip(), user=user,
bases={k: bases[k] for k in ("obsigate", "flowdeck", "tiktak", "kanbante")},
bases={k: bases[k] for k in ("obsigate", "flowdeck", "tiktak",
"kanbante", "agent")},
))
+4 -4
View File
@@ -5,10 +5,10 @@
CSS/JS : /static/css/draco-barre.css, /static/js/vendor/draco-barre.js.
v7.82.0 (dev/prod) : les href des onglets ne sont plus figés —
l'hôte les injecte depuis sa config (draco_urls(), noms officiels
par défaut, noms en -dev déclarés dans le .env de l'environnement). #}
Chantier 5 (fusion #69/#71, sans bump) : 5e onglet Console Spark
(data-app="agent", draco_urls().agent), après Kanbante ; l'entrée
« Console Spark » du menu de la marque est conservée.
par défaut, noms en -dev déclarés dans le .env de l'environnement).
5e onglet Console Spark (data-app="agent", draco_urls().agent),
après Kanbante ; l'entrée « Console Spark » du menu de la marque
est conservée (menu construit par draco-barre.js depuis les onglets). #}
<link rel="stylesheet" href="/static/css/draco-alertes.css?v={{ asset_version }}">
<header class="draco-bar" data-current="flowdeck">
<div class="draco-bar-zone draco-bar-gauche">
+13 -8
View File
@@ -1,17 +1,22 @@
{% extends "base.html" %}
{% block title_prefix %}Rechercher partout{% endblock %}
{% block content %}
<link rel="stylesheet" href="/static/css/recherche.css">
{# Console : pas de data-base-console ici — la route Flowdeck de /recherche
n'expose pas la base agent dans son contexte `bases` ; recherche.js
dérive donc la base console (hôte -dev -> agent-dev, sinon prod) ou
reprend le href d'un onglet de barre console/spark quand il existe.
Les 3 autres hôtes rendent data-base-console explicitement. #}
{# Versionnes (?v=asset_version) comme les autres feuilles/scripts de
base.html : sans version, le service worker (static/sw.js, cache-first
des .js/.css) resservait indefiniment les copies pre-#33 de ces deux
fichiers aux navigateurs les ayant deja visites — la page paraissait
donc « non corrigee » malgre les PR #33/#36. #}
<link rel="stylesheet" href="/static/css/recherche.css?v={{ asset_version }}">
{# Console : data-base-console rendu explicitement, comme les 3 autres
hotes — la route Flowdeck de /recherche expose la base agent dans
son contexte `bases` (defaut 6). recherche.js garde ses replis
(derivation -dev, href d'onglet de barre) si l'attribut est vide. #}
<main class="rp-page" id="recherche" data-host="flowdeck"
data-base-obsigate="{{ bases.obsigate }}"
data-base-flowdeck="{{ bases.flowdeck }}"
data-base-tiktak="{{ bases.tiktak }}"
data-base-kanbante="{{ bases.kanbante }}">
data-base-kanbante="{{ bases.kanbante }}"
data-base-console="{{ bases.agent }}">
<h1>Rechercher partout</h1>
<p class="rp-hint">Notes ObsiGate, pages Flowdeck, tâches TikTak, cartes Kanbante — dans l'environnement courant (dev reste dev). « / » ou Ctrl+K pour rechercher, ↑/↓ puis Entrée pour ouvrir un résultat. « Tout voir » bascule vers l'onglet de l'application, sans quitter la page.</p>
<div class="rp-form">
@@ -49,5 +54,5 @@
</main>
{% endblock %}
{% block scripts %}
<script src="/static/js/recherche.js"></script>
<script src="/static/js/recherche.js?v={{ asset_version }}"></script>
{% endblock %}
+8 -1
View File
@@ -8,7 +8,14 @@
═══════════════════════════════════════════════════════════ */
'use strict';
const CACHE_NAME = 'flowdeck-v8'; // v8 : Alpine CSP build (A20 fini)
const CACHE_NAME = 'flowdeck-v9'; // v9 : purge des caches pre-#33/#36 —
// recherche.js/recherche.css etaient servis cache-first SANS version
// (?v= absent dans recherche.html) : les navigateurs ayant visite
// Flowdeck avant les onglets gardaient les copies pre-#33 (JS sans
// onglets/compteurs/console, CSS sans .rp-tabs) malgre les deplois
// 7.84.3/7.84.4. Le bump purge ces caches a l'activation, et les
// liens versionnes (?v=asset_version) font des futurs changements
// de nouvelles cles de cache.
const DATA_CACHE = 'flowdeck-data-v7';
// App shell (assets versionnés comme référencés dans les templates).
+48
View File
@@ -0,0 +1,48 @@
"""Barre d'apps Flowdeck : aucun texte de chantier rendu hors commentaire.
Defaut 5 : les lignes « Chantier 5 (fusion #69/#71, sans bump) : ... »
etaient placees APRES la fermeture `#}` du commentaire Jinja d'en-tete
de `app/templates/_draco_bar.html` (lignes 9-11) : elles etaient donc
rendues telles quelles, juste au-dessus du <header> de la barre, sur
toutes les pages (la barre est incluse par base.html).
Test sans dependance (lecture du gabarit seul, comme
test_draco_alertes.py) : il tourne sans serveur ni base, donc aussi
en sandbox. La note documentaire peut vivre DANS le commentaire Jinja
(jamais rendu) ; elle ne doit jamais en sortir.
"""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
def _hors_commentaires(texte):
"""Texte du gabarit sans les commentaires Jinja {# ... #}."""
return re.sub(r"\{#.*?#\}", "", texte, flags=re.S)
def test_aucun_texte_chantier_rendu():
gabarit = (ROOT / "app/templates/_draco_bar.html").read_text()
rendu = _hors_commentaires(gabarit)
assert "Chantier 5 (fusion" not in rendu
assert "sans bump" not in rendu
# Aucune ligne de texte libre entre le commentaire d'en-tete et <link> :
# le rendu doit commencer (apres commentaires) par <link> ou <header>.
assert rendu.lstrip().startswith("<link")
def test_barre_intacte_apres_suppression():
"""Le 5e onglet Console Spark et la marque survivent a la suppression."""
gabarit = (ROOT / "app/templates/_draco_bar.html").read_text()
rendu = _hors_commentaires(gabarit)
nav = rendu.split('<nav class="draco-apptabs"')[1].split("</nav>")[0]
assert nav.index('data-app="kanbante"') < nav.index('data-app="agent"')
assert "Console Spark" in nav
assert 'data-app="agent"' in nav
assert 'class="draco-brand"' in rendu
# L'entree « Console Spark » du menu de la marque est construite par
# draco-barre.js depuis les onglets : l'onglet agent suffit a l'alimenter.
js_barre = (ROOT / "static/js/vendor/draco-barre.js").read_text()
assert "Console Spark" in js_barre
+16 -1
View File
@@ -38,7 +38,7 @@ def test_origin_of():
def test_sister_origins_dev():
# Correctif 2026-10-28 : 8 origines officielles, prod ET dev,
# Correctif 2026-10-28 : 10 origines officielles (8 sœurs + 2 agent), prod ET dev,
# quelle que soit la résolution.
assert sister_origins(RESOLVED_DEV) == {
"https://og.dracodev.net",
@@ -49,9 +49,24 @@ def test_sister_origins_dev():
"https://flowdeck-dev.dracodev.net",
"https://tiktak-dev.dracodev.net",
"https://kanbante-dev.dracodev.net",
"https://agent.dracodev.net",
"https://agent-dev.dracodev.net",
}
def test_cors_headers_agent_console_autorise():
# Fédération depuis la console (2026-10-28) : les origines agent
# prod ET dev passent, avec credentials ; un tiers reste refusé.
for origine in ("https://agent.dracodev.net",
"https://agent-dev.dracodev.net"):
headers = cors_headers_for(origine, RESOLVED_DEV)
assert headers is not None
assert headers["Access-Control-Allow-Origin"] == origine
assert headers["Access-Control-Allow-Credentials"] == "true"
assert cors_headers_for("https://agent.dracodev.net.evil.example",
RESOLVED_DEV) is None
def test_sister_origins_ajoute_env_de_la_requete():
# Correctif 2026-10-28 : configuration muette, quel que soit
# l'hôte de la requête, prod ET dev passent — l'hôte ne
+85
View File
@@ -0,0 +1,85 @@
"""Page /recherche Flowdeck : onglets, base console, anti-cache (defaut 6).
Audit prealable (main 7.84.4, tag v7.84.4 = 984e92b) : la route
(app/routers/search.py:51), le gabarit (app/templates/recherche.html),
le JS (static/js/recherche.js) et le CSS (static/css/recherche.css)
contenaient DEJA la page a onglets des PR #33/#36 — aucune route
fantome, aucun bloc `scripts` manquant dans base.html:869, aucune
regle CSP ne bloquant le script (script-src 'self'). Le symptome
deploie (« pas d'onglets, resultats Flowdeck seuls ») ne s'explique
donc PAS par un mauvais gabarit dans main, mais par deux causes
reelles, corrigees ici :
1. Assets recherche servis CACHE-FIRST par le service worker
(static/sw.js) SANS version (?v= absent) sous un CACHE_NAME
inchange depuis A20 ('flowdeck-v8') : un navigateur ayant visite
Flowdeck avant #33 gardait le recherche.js pre-#33 (sans onglets,
sans compteurs, sans logique console, « Tout voir » naviguant
ailleurs) et le recherche.css pre-#33 (sans .rp-tabs) — la page
paraissait donc « non corrigee » malgre les deplois 7.84.3/7.84.4,
et le repli networkFirst du HTML vers le cache couvrait aussi le
cas reseau lent. Correctif : liens versionnes (?v=asset_version,
comme tous les autres assets de base.html) + bump CACHE_NAME
(purge a l'activation du nouveau worker).
2. Flowdeck etait le seul hote a ne pas rendre data-base-console
(son propre commentaire l'admettait) : la base console de l'onglet
Console Spark etait devine (derivation -dev / href d'onglet de
barre) au lieu d'etre explicite. Correctif : la route expose
`bases.agent` et le gabarit le rend en data-base-console.
La logique d'onglets elle-meme (focus, compteurs, « Tout voir » sur
place, etats par application, liens -dev, console sur
GET /api/v1/recherche) est deja couverte par tests/recherche.test.js
(suite Node, lancee en sandbox) ; ce fichier-ci verrouille le
branchement gabarit/route/service worker, sans serveur ni base.
"""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
ONGLETS_ATTENDUS = ["all", "obsigate", "flowdeck", "tiktak", "kanbante",
"console"]
def test_gabarit_recherche_onglets_complets():
gabarit = (ROOT / "app/templates/recherche.html").read_text()
trouves = re.findall(r'data-rp-tab="([^"]+)"', gabarit)
assert trouves == ONGLETS_ATTENDUS, trouves
for section in ("obsigate", "flowdeck", "tiktak", "kanbante", "console"):
assert f'data-rp-section="{section}"' in gabarit
assert 'id="rp-q"' in gabarit and "autofocus" in gabarit
def test_gabarit_recherche_base_console_explicite():
gabarit = (ROOT / "app/templates/recherche.html").read_text()
assert 'data-base-console="{{ bases.agent }}"' in gabarit
def test_gabarit_recherche_assets_versionnes():
"""Sans ?v=, le SW cache-first ressert les copies pre-#33."""
gabarit = (ROOT / "app/templates/recherche.html").read_text()
assert "/static/css/recherche.css?v={{ asset_version }}" in gabarit
assert "/static/js/recherche.js?v={{ asset_version }}" in gabarit
def test_route_recherche_expose_base_agent():
route = (ROOT / "app/routers/search.py").read_text()
assert '"agent"' in route or "'agent'" in route
assert "bases.agent" in (ROOT / "app/templates/recherche.html").read_text()
def test_service_worker_purge_anciens_caches():
"""Le bump de CACHE_NAME purge les caches pre-#33 a l'activation."""
sw = (ROOT / "static/sw.js").read_text()
assert "const CACHE_NAME = 'flowdeck-v9'" in sw
assert "flowdeck-v8" not in sw
assert "cache-first" in sw or "cacheFirst" in sw
def test_recherche_js_branche_console_v1():
"""Rappel : l'onglet console appelle GET /api/v1/recherche (cf. #36)."""
js = (ROOT / "static/js/recherche.js").read_text()
assert 'CONSOLE_SEARCH_PATH = "api/v1/recherche"' in js
assert "CONSOLE_SEARCH_LIMIT = 20" in js