0.45.7 — recherche fédérée : ShaarIt, 5e source de « Rechercher partout »
- static/js/recherche.js re-vendangé depuis commons v0.2.1 : source
ShaarIt (bases, onglet, normaliseur — lien profond
{base}shaare/<shorturl>).
- Gabarit /recherche : data-base-shaarit (draco_urls.shaarit),
onglet et section « ShaarIt — bookmarks ».
- app/recherche.py : origines ShaarIt prod/dev, clé sœur et
dictionnaire résolu (urls.shaarit_url).
- Tests : recherche.test.js 83 assertions ; allowlist à 12 origines ;
suite complète 377/377.
This commit is contained in:
@@ -1,3 +1,11 @@
|
|||||||
|
## 0.45.7 — 2026-11-04 — Recherche fédérée : ShaarIt, 5e source de « Rechercher partout »
|
||||||
|
|
||||||
|
- **`recherche.js` re-vendangé depuis dracodev-commons v0.2.1** (source canonique `ui/recherche/`) : ShaarIt devient une source de la page `/recherche` comme les autres — bases prod/dev, onglet, normaliseur (lien profond canonique `{base}shaare/<shorturl>`, contexte « Bookmark · privé · tags », repli recherche native `/?q=`). Le fichier reste **strictement identique** chez les cinq hôtes.
|
||||||
|
- **Gabarit `/recherche`** : onglet et section « ShaarIt — bookmarks », `data-base-shaarit` rendu par `draco_urls.shaarit` (déjà résolu par `render()`), aide mise à jour.
|
||||||
|
- **CORS de recherche** (`app/recherche.py`) : origines officielles ShaarIt prod et dev ajoutées aux listes explicites ; `shaarit` ajoutée aux clés sœurs et au dictionnaire résolu (`urls.shaarit_url`) — `GET /api/search` de Kanbante devient lisible depuis les pages de ShaarIt.
|
||||||
|
- Tests : `tests/recherche.test.js` porté à 5 sections (83 assertions, dont le normaliseur ShaarIt) ; `tests/test_recherche.py` — allowlist attendue à 12 origines.
|
||||||
|
- **Déploiement** : comme les versions précédentes, le conteneur Kanbante se redéploie par un geste de Bruno (la publication seule ne le redémarre pas).
|
||||||
|
|
||||||
## 0.45.6 — 2026-11-03 — Barre commune v0.2.0 : onglet ShaarIt + garde data-theme (phase 3 ShaarIt)
|
## 0.45.6 — 2026-11-03 — Barre commune v0.2.0 : onglet ShaarIt + garde data-theme (phase 3 ShaarIt)
|
||||||
|
|
||||||
- **⚠ CHANGEMENT DE COMPORTEMENT VISIBLE — garde `data-theme` (arbitrage à la fusion)** : le CSS de barre vendangé jusqu'ici (v0.1.11) appliquait les couleurs **sombres dès que le système était en mode sombre**, sans tenir compte du thème clair choisi dans l'app — sur un poste en sombre système, la barre restait sombre alors que Kanbante était en clair. La v0.2.0 de commons corrige ce piège **dans la source** : les deux blocs `@media (prefers-color-scheme: dark)` sont gardés par `html:not([data-theme])` (le sombre système ne s'applique que si `<html>` n'a **aucun** `data-theme`). Kanbante posant toujours `html[data-theme]` (sombre par défaut, bascule mémorisée `kanbante-theme`), sa barre suivra désormais **toujours le thème de l'app**, jamais celui du système contre son choix. Aucune surcharge `style.css` ajoutée : le correctif est entièrement dans le CSS vendangé verbatim.
|
- **⚠ CHANGEMENT DE COMPORTEMENT VISIBLE — garde `data-theme` (arbitrage à la fusion)** : le CSS de barre vendangé jusqu'ici (v0.1.11) appliquait les couleurs **sombres dès que le système était en mode sombre**, sans tenir compte du thème clair choisi dans l'app — sur un poste en sombre système, la barre restait sombre alors que Kanbante était en clair. La v0.2.0 de commons corrige ce piège **dans la source** : les deux blocs `@media (prefers-color-scheme: dark)` sont gardés par `html:not([data-theme])` (le sombre système ne s'applique que si `<html>` n'a **aucun** `data-theme`). Kanbante posant toujours `html[data-theme]` (sombre par défaut, bascule mémorisée `kanbante-theme`), sa barre suivra désormais **toujours le thème de l'app**, jamais celui du système contre son choix. Aucune surcharge `style.css` ajoutée : le correctif est entièrement dans le CSS vendangé verbatim.
|
||||||
|
|||||||
+1
-1
@@ -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.6"
|
APP_VERSION = "0.45.7"
|
||||||
|
|
||||||
|
|
||||||
def _env_bool(name: str, default: bool) -> bool:
|
def _env_bool(name: str, default: bool) -> bool:
|
||||||
|
|||||||
+4
-1
@@ -38,6 +38,7 @@ PROD_ORIGINS = frozenset({
|
|||||||
"https://flowdeck.dracodev.net",
|
"https://flowdeck.dracodev.net",
|
||||||
"https://tiktak.dracodev.net",
|
"https://tiktak.dracodev.net",
|
||||||
"https://kanbante.dracodev.net",
|
"https://kanbante.dracodev.net",
|
||||||
|
"https://shaarit.dracodev.net",
|
||||||
})
|
})
|
||||||
|
|
||||||
DEV_ORIGINS = frozenset({
|
DEV_ORIGINS = frozenset({
|
||||||
@@ -45,6 +46,7 @@ DEV_ORIGINS = frozenset({
|
|||||||
"https://flowdeck-dev.dracodev.net",
|
"https://flowdeck-dev.dracodev.net",
|
||||||
"https://tiktak-dev.dracodev.net",
|
"https://tiktak-dev.dracodev.net",
|
||||||
"https://kanbante-dev.dracodev.net",
|
"https://kanbante-dev.dracodev.net",
|
||||||
|
"https://shaarit-dev.dracodev.net",
|
||||||
})
|
})
|
||||||
|
|
||||||
AGENT_ORIGINS = frozenset({
|
AGENT_ORIGINS = frozenset({
|
||||||
@@ -54,7 +56,7 @@ AGENT_ORIGINS = frozenset({
|
|||||||
|
|
||||||
|
|
||||||
# Clés du dictionnaire rendu par render() (app/main.py).
|
# Clés du dictionnaire rendu par render() (app/main.py).
|
||||||
_SOEUR_KEYS = ("obsigate", "flowdeck", "tiktak", "kanbante")
|
_SOEUR_KEYS = ("obsigate", "flowdeck", "tiktak", "kanbante", "shaarit")
|
||||||
|
|
||||||
|
|
||||||
def is_dev_host(hostname: str | None) -> bool:
|
def is_dev_host(hostname: str | None) -> bool:
|
||||||
@@ -103,6 +105,7 @@ def sister_origins(
|
|||||||
"flowdeck": urls.flowdeck_url,
|
"flowdeck": urls.flowdeck_url,
|
||||||
"tiktak": urls.tiktak_url,
|
"tiktak": urls.tiktak_url,
|
||||||
"kanbante": urls.public_url,
|
"kanbante": urls.public_url,
|
||||||
|
"shaarit": urls.shaarit_url,
|
||||||
}
|
}
|
||||||
except Exception:
|
except Exception:
|
||||||
return PROD_ORIGINS | DEV_ORIGINS
|
return PROD_ORIGINS | DEV_ORIGINS
|
||||||
|
|||||||
@@ -16,9 +16,10 @@
|
|||||||
data-base-flowdeck="{{ draco_urls.flowdeck }}"
|
data-base-flowdeck="{{ draco_urls.flowdeck }}"
|
||||||
data-base-tiktak="{{ draco_urls.tiktak }}"
|
data-base-tiktak="{{ draco_urls.tiktak }}"
|
||||||
data-base-kanbante="{{ draco_urls.kanbante }}"
|
data-base-kanbante="{{ draco_urls.kanbante }}"
|
||||||
|
data-base-shaarit="{{ draco_urls.shaarit }}"
|
||||||
data-base-console="{{ agent_url }}">
|
data-base-console="{{ agent_url }}">
|
||||||
<h1>Rechercher partout</h1>
|
<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>
|
<p class="rp-hint">Notes ObsiGate, pages Flowdeck, tâches TikTak, cartes Kanbante, bookmarks ShaarIt — 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">
|
<div class="rp-form">
|
||||||
<input id="rp-q" class="rp-input" type="search" name="q" value="{{ q }}"
|
<input id="rp-q" class="rp-input" type="search" name="q" value="{{ q }}"
|
||||||
placeholder="Rechercher partout…" autocomplete="off" autofocus>
|
placeholder="Rechercher partout…" autocomplete="off" autofocus>
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="flowdeck">Flowdeck <span class="rp-tab-count"></span></button>
|
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="flowdeck">Flowdeck <span class="rp-tab-count"></span></button>
|
||||||
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="tiktak">TikTak <span class="rp-tab-count"></span></button>
|
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="tiktak">TikTak <span class="rp-tab-count"></span></button>
|
||||||
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="kanbante">Kanbante <span class="rp-tab-count"></span></button>
|
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="kanbante">Kanbante <span class="rp-tab-count"></span></button>
|
||||||
|
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="shaarit">ShaarIt <span class="rp-tab-count"></span></button>
|
||||||
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="console">Console Spark <span class="rp-tab-count"></span></button>
|
<button type="button" class="rp-tab" role="tab" aria-selected="false" tabindex="-1" data-rp-tab="console">Console Spark <span class="rp-tab-count"></span></button>
|
||||||
</nav>
|
</nav>
|
||||||
<section class="rp-section" data-rp-section="obsigate">
|
<section class="rp-section" data-rp-section="obsigate">
|
||||||
@@ -47,6 +49,10 @@
|
|||||||
<div class="rp-head"><h2>Kanbante — cartes</h2><span class="rp-count"></span><a class="rp-all" href="#">Tout voir</a></div>
|
<div class="rp-head"><h2>Kanbante — cartes</h2><span class="rp-count"></span><a class="rp-all" href="#">Tout voir</a></div>
|
||||||
<div class="rp-body"><p class="rp-state">Tapez une recherche ci-dessus.</p></div>
|
<div class="rp-body"><p class="rp-state">Tapez une recherche ci-dessus.</p></div>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="rp-section" data-rp-section="shaarit">
|
||||||
|
<div class="rp-head"><h2>ShaarIt — bookmarks</h2><span class="rp-count"></span><a class="rp-all" href="#">Tout voir</a></div>
|
||||||
|
<div class="rp-body"><p class="rp-state">Tapez une recherche ci-dessus.</p></div>
|
||||||
|
</section>
|
||||||
<section class="rp-section" data-rp-section="console">
|
<section class="rp-section" data-rp-section="console">
|
||||||
<div class="rp-head"><h2>Console Spark — discussions</h2><span class="rp-count"></span><a class="rp-all" href="#">Tout voir</a></div>
|
<div class="rp-head"><h2>Console Spark — discussions</h2><span class="rp-count"></span><a class="rp-all" href="#">Tout voir</a></div>
|
||||||
<div class="rp-body"><p class="rp-state">Tapez une recherche ci-dessus.</p></div>
|
<div class="rp-body"><p class="rp-state">Tapez une recherche ci-dessus.</p></div>
|
||||||
|
|||||||
+39
-9
@@ -2,11 +2,13 @@
|
|||||||
* chantier 2+3 : onglets, « Tout voir », focus).
|
* chantier 2+3 : onglets, « Tout voir », focus).
|
||||||
*
|
*
|
||||||
* Vanilla, sans dépendance. Un seul fichier vendangé tel quel par chaque
|
* Vanilla, sans dépendance. Un seul fichier vendangé tel quel par chaque
|
||||||
* hôte (ObsiGate, Flowdeck, TikTak, Kanbante) : la configuration vient
|
* hôte (ObsiGate, Flowdeck, TikTak, Kanbante, ShaarIt) : la configuration
|
||||||
* des attributs data-* de #recherche, rendus côté serveur par l'hôte.
|
* vient des attributs data-* de #recherche, rendus côté serveur par
|
||||||
|
* l'hôte. Source canonique : dracodev-commons, ui/recherche/
|
||||||
|
* (contrat : contrats/recherche-federee.md).
|
||||||
*
|
*
|
||||||
* Présentation en onglets : Tout, ObsiGate, Flowdeck, TikTak, Kanbante,
|
* Présentation en onglets : Tout, ObsiGate, Flowdeck, TikTak, Kanbante,
|
||||||
* Console Spark. « Tout » = les 4 sections groupées, chaque liste
|
* ShaarIt, Console Spark. « Tout » = les 5 sections groupées, chaque liste
|
||||||
* tronquée à PER_APP_LIMIT ; un onglet application = tous les résultats
|
* tronquée à PER_APP_LIMIT ; un onglet application = tous les résultats
|
||||||
* de cette application (aucune troncature côté client — la requête
|
* de cette application (aucune troncature côté client — la requête
|
||||||
* ObsiGate part avec limit=FULL_LIMIT, les autres API renvoient leur
|
* ObsiGate part avec limit=FULL_LIMIT, les autres API renvoient leur
|
||||||
@@ -46,6 +48,11 @@
|
|||||||
* -> { groups: [{ full_name, rows: [{ issue, column }] }] }
|
* -> { groups: [{ full_name, rows: [{ issue, column }] }] }
|
||||||
* Lien profond : {base}board/<full_name> (la carte n'a pas d'URL propre
|
* Lien profond : {base}board/<full_name> (la carte n'a pas d'URL propre
|
||||||
* adressable — même limite que la page /search native de Kanbante).
|
* adressable — même limite que la page /search native de Kanbante).
|
||||||
|
* - ShaarIt : GET {base}/api/search?q=
|
||||||
|
* -> { links: [{ id, title, url, description, tags, shorturl,
|
||||||
|
* private }] }
|
||||||
|
* Lien profond (contrat liens-profonds) : {base}shaare/<shorturl>.
|
||||||
|
* Recherche native adressable : {base}?q=<q> (page d'accueil).
|
||||||
* - Console Spark : GET {base-console}/api/v1/recherche?q=&limite=
|
* - Console Spark : GET {base-console}/api/v1/recherche?q=&limite=
|
||||||
* (agent-commun, authentifié par le cookie SSO draco_session) ->
|
* (agent-commun, authentifié par le cookie SSO draco_session) ->
|
||||||
* { q, domain, limite_par_type, resultats[], par_type,
|
* { q, domain, limite_par_type, resultats[], par_type,
|
||||||
@@ -87,8 +94,9 @@
|
|||||||
* Authentification cross-origin : les appels sœurs partent avec
|
* Authentification cross-origin : les appels sœurs partent avec
|
||||||
* credentials:"include". Le navigateur envoie alors les cookies de
|
* credentials:"include". Le navigateur envoie alors les cookies de
|
||||||
* chaque origine, dont le cookie SSO partagé draco_session
|
* chaque origine, dont le cookie SSO partagé draco_session
|
||||||
* (Domain=.dracodev.net), accepté par les 4 API de recherche
|
* (Domain=.dracodev.net), accepté par les 5 API de recherche
|
||||||
* (ObsiGate et TikTak nativement, Flowdeck et Kanbante via #68)
|
* (ObsiGate et TikTak nativement, Flowdeck et Kanbante via #68,
|
||||||
|
* ShaarIt via la fédération v0.2.1 de commons)
|
||||||
* et par GET /api/v1/recherche de la console (identity() accepte
|
* et par GET /api/v1/recherche de la console (identity() accepte
|
||||||
* draco_session). Chaque sœur n'autorise en CORS que les origines
|
* draco_session). Chaque sœur n'autorise en CORS que les origines
|
||||||
* sœurs (GET sur l'endpoint de recherche uniquement, pas de "*") ;
|
* sœurs (GET sur l'endpoint de recherche uniquement, pas de "*") ;
|
||||||
@@ -109,12 +117,14 @@
|
|||||||
flowdeck: "https://flowdeck.dracodev.net/",
|
flowdeck: "https://flowdeck.dracodev.net/",
|
||||||
tiktak: "https://tiktak.dracodev.net/",
|
tiktak: "https://tiktak.dracodev.net/",
|
||||||
kanbante: "https://kanbante.dracodev.net/",
|
kanbante: "https://kanbante.dracodev.net/",
|
||||||
|
shaarit: "https://shaarit.dracodev.net/",
|
||||||
};
|
};
|
||||||
var DEV = {
|
var DEV = {
|
||||||
obsigate: "https://og-dev.dracodev.net/",
|
obsigate: "https://og-dev.dracodev.net/",
|
||||||
flowdeck: "https://flowdeck-dev.dracodev.net/",
|
flowdeck: "https://flowdeck-dev.dracodev.net/",
|
||||||
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/",
|
||||||
};
|
};
|
||||||
var PROD_AGENT = "https://agent.dracodev.net/";
|
var PROD_AGENT = "https://agent.dracodev.net/";
|
||||||
var DEV_AGENT = "https://agent-dev.dracodev.net/";
|
var DEV_AGENT = "https://agent-dev.dracodev.net/";
|
||||||
@@ -125,6 +135,7 @@
|
|||||||
{ key: "flowdeck", label: "Flowdeck" },
|
{ key: "flowdeck", label: "Flowdeck" },
|
||||||
{ key: "tiktak", label: "TikTak" },
|
{ key: "tiktak", label: "TikTak" },
|
||||||
{ key: "kanbante", label: "Kanbante" },
|
{ key: "kanbante", label: "Kanbante" },
|
||||||
|
{ key: "shaarit", label: "ShaarIt" },
|
||||||
];
|
];
|
||||||
var CONSOLE_APP = { key: "console", label: "Console Spark" };
|
var CONSOLE_APP = { key: "console", label: "Console Spark" };
|
||||||
var CONSOLE_TYPE_LABELS = {
|
var CONSOLE_TYPE_LABELS = {
|
||||||
@@ -145,7 +156,7 @@
|
|||||||
planification: "/?section=planifie",
|
planification: "/?section=planifie",
|
||||||
identite: "/?section=identites",
|
identite: "/?section=identites",
|
||||||
};
|
};
|
||||||
var TABS = ["all", "obsigate", "flowdeck", "tiktak", "kanbante", "console"];
|
var TABS = ["all", "obsigate", "flowdeck", "tiktak", "kanbante", "shaarit", "console"];
|
||||||
var COLUMN_LABELS = {
|
var COLUMN_LABELS = {
|
||||||
backlog: "Backlog",
|
backlog: "Backlog",
|
||||||
in_progress: "En cours",
|
in_progress: "En cours",
|
||||||
@@ -227,7 +238,7 @@
|
|||||||
return TABS.indexOf(v) !== -1 ? v : "all";
|
return TABS.indexOf(v) !== -1 ? v : "all";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sections visibles pour un onglet. « Tout » = les 4 sections
|
/* Sections visibles pour un onglet. « Tout » = les 5 sections
|
||||||
* groupées (vue #68) ; la console n'y figure pas (voir en-tête). */
|
* groupées (vue #68) ; la console n'y figure pas (voir en-tête). */
|
||||||
function visibleKeys(tab) {
|
function visibleKeys(tab) {
|
||||||
tab = parseTab(tab);
|
tab = parseTab(tab);
|
||||||
@@ -256,7 +267,7 @@
|
|||||||
* Chargement -> "…", ok/vide -> total ("0" honnête),
|
* Chargement -> "…", ok/vide -> total ("0" honnête),
|
||||||
* erreur/indisponible/inactif -> "" (pas de faux 0).
|
* erreur/indisponible/inactif -> "" (pas de faux 0).
|
||||||
* Tout : "…" tant qu'une section charge, sinon somme des totaux
|
* Tout : "…" tant qu'une section charge, sinon somme des totaux
|
||||||
* connus, "" si les 4 sections sont en erreur/inactives. */
|
* connus, "" si les 5 sections sont en erreur/inactives. */
|
||||||
function tabCounts(states) {
|
function tabCounts(states) {
|
||||||
states = states || {};
|
states = states || {};
|
||||||
var out = {};
|
var out = {};
|
||||||
@@ -367,6 +378,22 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (app === "shaarit") {
|
||||||
|
return cut(data.links || []).map(function (l) {
|
||||||
|
var tags = (l.tags || []).filter(function (t) { return !!t; });
|
||||||
|
var ctx = "Bookmark";
|
||||||
|
if (l.private) ctx += " · privé";
|
||||||
|
if (tags.length) ctx += " · " + tags.join(", ");
|
||||||
|
return {
|
||||||
|
title: l.title || l.url || "Sans titre",
|
||||||
|
snippet: snippetOf(l.description || ""),
|
||||||
|
context: ctx,
|
||||||
|
/* Lien profond canonique (contrats/liens-profonds.md) ;
|
||||||
|
* sans shorturl, repli sur l'URL du bookmark lui-même. */
|
||||||
|
url: l.shorturl ? base + "shaare/" + l.shorturl : l.url || null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,13 +482,16 @@
|
|||||||
if (app === "tiktak" || app === "kanbante") {
|
if (app === "tiktak" || app === "kanbante") {
|
||||||
return base + "search?q=" + encodeURIComponent(q || "");
|
return base + "search?q=" + encodeURIComponent(q || "");
|
||||||
}
|
}
|
||||||
|
if (app === "shaarit") {
|
||||||
|
return base + "?q=" + encodeURIComponent(q || "");
|
||||||
|
}
|
||||||
/* ObsiGate et Flowdeck n'ont pas de page de recherche adressable :
|
/* ObsiGate et Flowdeck n'ont pas de page de recherche adressable :
|
||||||
* leur recherche native vit dans la palette (Ctrl+K) de l'app. */
|
* leur recherche native vit dans la palette (Ctrl+K) de l'app. */
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nativeSearchLabel(app) {
|
function nativeSearchLabel(app) {
|
||||||
if (app === "tiktak" || app === "kanbante") {
|
if (app === "tiktak" || app === "kanbante" || app === "shaarit") {
|
||||||
return "Ouvrir la recherche dans " + appLabel(app);
|
return "Ouvrir la recherche dans " + appLabel(app);
|
||||||
}
|
}
|
||||||
return "Ouvrir " + appLabel(app) + " (recherche via la palette Ctrl+K)";
|
return "Ouvrir " + appLabel(app) + " (recherche via la palette Ctrl+K)";
|
||||||
|
|||||||
+21
-5
@@ -61,8 +61,18 @@ items = rp.normalize("kanbante", { groups: [{ full_name: "Projets/site", rows: [
|
|||||||
ok(items[0].title === "#12 Bug" && items[0].url === "https://kanbante-dev.dracodev.net/board/Projets/site", "lien tableau Kanbante");
|
ok(items[0].title === "#12 Bug" && items[0].url === "https://kanbante-dev.dracodev.net/board/Projets/site", "lien tableau Kanbante");
|
||||||
ok(items[0].context === "Projets/site · En cours", "contexte Kanbante");
|
ok(items[0].context === "Projets/site · En cours", "contexte Kanbante");
|
||||||
|
|
||||||
|
/* normalize ShaarIt (commons v0.2.1) : lien profond shaare/<shorturl>,
|
||||||
|
* contexte privé + tags, repli sur l'URL du bookmark sans shorturl */
|
||||||
|
items = rp.normalize("shaarit", { links: [{ title: "Yandex", url: "https://yandex.com", description: "moteur", tags: ["recherche", "web"], shorturl: "xYz9", private: true }] }, "https://shaarit-dev.dracodev.net/", "recherche");
|
||||||
|
ok(items[0].title === "Yandex" && items[0].url === "https://shaarit-dev.dracodev.net/shaare/xYz9", "lien profond ShaarIt (shaare/<shorturl>)");
|
||||||
|
ok(items[0].context === "Bookmark · privé · recherche, web", "contexte ShaarIt (privé + tags)");
|
||||||
|
ok(items[0].snippet === "moteur", "extrait ShaarIt = description");
|
||||||
|
items = rp.normalize("shaarit", { links: [{ title: "", url: "https://exemple.fr", tags: [], shorturl: "" }] }, "https://shaarit.dracodev.net/", "x");
|
||||||
|
ok(items[0].url === "https://exemple.fr" && items[0].title === "https://exemple.fr", "ShaarIt sans shorturl : repli URL + titre");
|
||||||
|
|
||||||
/* nativeSearchUrl */
|
/* nativeSearchUrl */
|
||||||
ok(rp.nativeSearchUrl("tiktak", "https://tiktak-dev.dracodev.net/", "q") === "https://tiktak-dev.dracodev.net/search?q=q", "repli TikTak");
|
ok(rp.nativeSearchUrl("tiktak", "https://tiktak-dev.dracodev.net/", "q") === "https://tiktak-dev.dracodev.net/search?q=q", "repli TikTak");
|
||||||
|
ok(rp.nativeSearchUrl("shaarit", "https://shaarit-dev.dracodev.net/", "q") === "https://shaarit-dev.dracodev.net/?q=q", "repli ShaarIt = accueil ?q=");
|
||||||
ok(rp.nativeSearchUrl("obsigate", "https://og-dev.dracodev.net/", "q") === "https://og-dev.dracodev.net/", "repli ObsiGate = accueil (palette)");
|
ok(rp.nativeSearchUrl("obsigate", "https://og-dev.dracodev.net/", "q") === "https://og-dev.dracodev.net/", "repli ObsiGate = accueil (palette)");
|
||||||
|
|
||||||
|
|
||||||
@@ -70,15 +80,17 @@ ok(rp.nativeSearchUrl("obsigate", "https://og-dev.dracodev.net/", "q") === "http
|
|||||||
|
|
||||||
/* parseTab */
|
/* parseTab */
|
||||||
ok(rp.parseTab("obsigate") === "obsigate", "onglet valide conservé");
|
ok(rp.parseTab("obsigate") === "obsigate", "onglet valide conservé");
|
||||||
|
ok(rp.parseTab("shaarit") === "shaarit", "onglet shaarit valide");
|
||||||
ok(rp.parseTab("console") === "console", "onglet console valide");
|
ok(rp.parseTab("console") === "console", "onglet console valide");
|
||||||
ok(rp.parseTab("bidon") === "all", "onglet inconnu -> Tout");
|
ok(rp.parseTab("bidon") === "all", "onglet inconnu -> Tout");
|
||||||
ok(rp.parseTab(undefined) === "all", "onglet absent -> Tout");
|
ok(rp.parseTab(undefined) === "all", "onglet absent -> Tout");
|
||||||
|
|
||||||
/* visibleKeys : Tout = les 4 sections groupées, sans la console */
|
/* visibleKeys : Tout = les 5 sections groupées, sans la console */
|
||||||
ok(JSON.stringify(rp.visibleKeys("all")) === JSON.stringify(["obsigate", "flowdeck", "tiktak", "kanbante"]), "Tout = 4 sections, pas la console");
|
ok(JSON.stringify(rp.visibleKeys("all")) === JSON.stringify(["obsigate", "flowdeck", "tiktak", "kanbante", "shaarit"]), "Tout = 5 sections, pas la console");
|
||||||
ok(JSON.stringify(rp.visibleKeys("tiktak")) === JSON.stringify(["tiktak"]), "onglet app = sa seule section");
|
ok(JSON.stringify(rp.visibleKeys("tiktak")) === JSON.stringify(["tiktak"]), "onglet app = sa seule section");
|
||||||
|
ok(JSON.stringify(rp.visibleKeys("shaarit")) === JSON.stringify(["shaarit"]), "onglet shaarit = sa seule section");
|
||||||
ok(JSON.stringify(rp.visibleKeys("console")) === JSON.stringify(["console"]), "onglet console = sa seule section");
|
ok(JSON.stringify(rp.visibleKeys("console")) === JSON.stringify(["console"]), "onglet console = sa seule section");
|
||||||
ok(JSON.stringify(rp.visibleKeys("bidon")) === JSON.stringify(["obsigate", "flowdeck", "tiktak", "kanbante"]), "onglet inconnu -> Tout");
|
ok(JSON.stringify(rp.visibleKeys("bidon")) === JSON.stringify(["obsigate", "flowdeck", "tiktak", "kanbante", "shaarit"]), "onglet inconnu -> Tout");
|
||||||
|
|
||||||
/* pageItems : troncature Tout (8), complet dans l'onglet de l'app */
|
/* pageItems : troncature Tout (8), complet dans l'onglet de l'app */
|
||||||
let douze = Array.from({ length: 12 }, (_, i) => ({ title: "T" + i }));
|
let douze = Array.from({ length: 12 }, (_, i) => ({ title: "T" + i }));
|
||||||
@@ -91,9 +103,11 @@ let c = rp.tabCounts({
|
|||||||
flowdeck: { status: "ok", total: 3 },
|
flowdeck: { status: "ok", total: 3 },
|
||||||
tiktak: { status: "empty", total: 0 },
|
tiktak: { status: "empty", total: 0 },
|
||||||
kanbante: { status: "error", total: 0 },
|
kanbante: { status: "error", total: 0 },
|
||||||
|
shaarit: { status: "ok", total: 2 },
|
||||||
console: { status: "idle", total: 0 },
|
console: { status: "idle", total: 0 },
|
||||||
});
|
});
|
||||||
ok(c.obsigate === "…", "compteur … pendant le chargement");
|
ok(c.obsigate === "…", "compteur … pendant le chargement");
|
||||||
|
ok(c.shaarit === "2", "compteur shaarit");
|
||||||
ok(c.flowdeck === "3" && c.tiktak === "0", "compteur total, vide honnête à 0");
|
ok(c.flowdeck === "3" && c.tiktak === "0", "compteur total, vide honnête à 0");
|
||||||
ok(c.kanbante === "" && c.console === "", "erreur/inactif : pas de faux 0");
|
ok(c.kanbante === "" && c.console === "", "erreur/inactif : pas de faux 0");
|
||||||
ok(c.all === "…", "Tout = … tant qu'une section charge");
|
ok(c.all === "…", "Tout = … tant qu'une section charge");
|
||||||
@@ -102,18 +116,20 @@ c = rp.tabCounts({
|
|||||||
flowdeck: { status: "ok", total: 2 },
|
flowdeck: { status: "ok", total: 2 },
|
||||||
tiktak: { status: "empty", total: 0 },
|
tiktak: { status: "empty", total: 0 },
|
||||||
kanbante: { status: "error", total: 0 },
|
kanbante: { status: "error", total: 0 },
|
||||||
|
shaarit: { status: "ok", total: 1 },
|
||||||
console: { status: "ok", total: 4 },
|
console: { status: "ok", total: 4 },
|
||||||
});
|
});
|
||||||
ok(c.all === "7", "Tout = somme des totaux connus");
|
ok(c.all === "8", "Tout = somme des totaux connus (5 sections)");
|
||||||
ok(c.console === "4", "compteur console");
|
ok(c.console === "4", "compteur console");
|
||||||
c = rp.tabCounts({
|
c = rp.tabCounts({
|
||||||
obsigate: { status: "error", total: 0 },
|
obsigate: { status: "error", total: 0 },
|
||||||
flowdeck: { status: "error", total: 0 },
|
flowdeck: { status: "error", total: 0 },
|
||||||
tiktak: { status: "error", total: 0 },
|
tiktak: { status: "error", total: 0 },
|
||||||
kanbante: { status: "error", total: 0 },
|
kanbante: { status: "error", total: 0 },
|
||||||
|
shaarit: { status: "error", total: 0 },
|
||||||
console: { status: "idle", total: 0 },
|
console: { status: "idle", total: 0 },
|
||||||
});
|
});
|
||||||
ok(c.all === "", "Tout vide si les 4 sections sont en erreur");
|
ok(c.all === "", "Tout vide si les 5 sections sont en erreur");
|
||||||
|
|
||||||
/* buildSearchUrl : état onglet partageable */
|
/* buildSearchUrl : état onglet partageable */
|
||||||
ok(rp.buildSearchUrl("café", "tiktak") === "?q=caf%C3%A9&tab=tiktak", "URL q+onglet");
|
ok(rp.buildSearchUrl("café", "tiktak") === "?q=caf%C3%A9&tab=tiktak", "URL q+onglet");
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ RESOLVED_DEV = {
|
|||||||
"flowdeck": "https://flowdeck-dev.dracodev.net",
|
"flowdeck": "https://flowdeck-dev.dracodev.net",
|
||||||
"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/",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -34,17 +35,20 @@ def test_origin_of():
|
|||||||
|
|
||||||
|
|
||||||
def test_sister_origins_dev():
|
def test_sister_origins_dev():
|
||||||
# Correctif 2026-10-28 : 10 origines officielles (8 sœurs + 2 agent), prod ET dev,
|
# Correctif 2026-10-28 : origines officielles prod ET dev, quelle
|
||||||
# quelle que soit la résolution.
|
# que soit la résolution ; ShaarIt ajoutée par la fédération
|
||||||
|
# v0.2.1 (12 origines : 10 sœurs + 2 agent).
|
||||||
assert sister_origins(RESOLVED_DEV) == {
|
assert sister_origins(RESOLVED_DEV) == {
|
||||||
"https://og.dracodev.net",
|
"https://og.dracodev.net",
|
||||||
"https://flowdeck.dracodev.net",
|
"https://flowdeck.dracodev.net",
|
||||||
"https://tiktak.dracodev.net",
|
"https://tiktak.dracodev.net",
|
||||||
"https://kanbante.dracodev.net",
|
"https://kanbante.dracodev.net",
|
||||||
|
"https://shaarit.dracodev.net",
|
||||||
"https://og-dev.dracodev.net",
|
"https://og-dev.dracodev.net",
|
||||||
"https://flowdeck-dev.dracodev.net",
|
"https://flowdeck-dev.dracodev.net",
|
||||||
"https://tiktak-dev.dracodev.net",
|
"https://tiktak-dev.dracodev.net",
|
||||||
"https://kanbante-dev.dracodev.net",
|
"https://kanbante-dev.dracodev.net",
|
||||||
|
"https://shaarit-dev.dracodev.net",
|
||||||
"https://agent.dracodev.net",
|
"https://agent.dracodev.net",
|
||||||
"https://agent-dev.dracodev.net",
|
"https://agent-dev.dracodev.net",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user