Aller au contenu principal

Menus

Le menu définit la barre latérale React. Une arborescence par app, dont les feuilles renvoient vers ce que l'app expose : une requête de connecteur (ouvre une grille de table), un tableau de bord (ouvre un dashboard), un endpoint API (ouvre un HttpRunner), ou un slug statique. L'arborescence est filtrée selon les droits de l'utilisateur : une feuille qu'il ne peut pas exécuter est masquée, et un dossier devenu vide disparaît à son tour.

Les menus sont déclarés dans config/menus.toml. Rechargeables à chaud avec le reste de la configuration.


Vue d'ensemble

📄 menus.toml[apps.myapp]label = "My App"connector = "myapp"[[apps.myapp.items]]label = "Données maîtres"type = "folder"items = [...]feuille · type = "query"label = "Users"query = "users_get"screen = "users"feuille · type = "dashboard"label = "Overview"dashboard = "overview"⚙ filtrage par permissionssql:{c}:{q}requise pour type = "query"sinon, la feuille est masquéeapi:{c}:{e}requise pour type = "endpoint"sinon, la feuille est masquéefiltre par rôlesfeuille avec roles = [...]l'utilisateur doit en posséder undossiers vides masquésun dossier sans feuilledisparaît de l'arborescenceGET /api/menusrésolue dans la langue de la requête⚛️ BARRE LATÉRALE📊 Vue d'ensemble📁 Données maîtres📋 Utilisateurs📋 Villes📋 Rôles📁 Opérations📊 Indicateurs journaliers🌐 Vérification de santé📁 Paramètres⚙ Utilisateurs⚙ Rôles⚙ Connecteursi18nlibellés via la clé l = …

Racine des apps

Un fichier de menus déclare une ou plusieurs apps. Chaque app correspond au dossier de premier niveau dans le sélecteur de workspace.

[apps.myapp]
label = "My App"
description = "Application adossée au connecteur `myapp`."
connector = "myapp" # connecteur par défaut pour toutes les feuilles dessous

[apps.myapp.l]
fr = "Mon application"

Le connector déclaré sur l'app sert de connecteur par défaut : chaque feuille en hérite tant qu'elle n'en désigne pas un autre. Pratique pour les apps qui ciblent un seul connecteur ; une feuille peut désigner un connecteur différent pour traiter un cas particulier.


Items

Chaque app porte une liste ordonnée d'items. Un item est soit un dossier, soit une feuille.

[[apps.myapp.items]]
label = "Données maîtres"
type = "folder"

[[apps.myapp.items.items]] # imbrication
label = "Utilisateurs"
type = "query"
query = "users_get"
screen = "users" # ouvre l'écran `screens.myapp.users` (sinon, simple grille)

[[apps.myapp.items.items]]
label = "Villes"
type = "query"
query = "cities_get"

[[apps.myapp.items]]
label = "Vue d'ensemble"
type = "dashboard"
dashboard = "overview"

[[apps.myapp.items]]
label = "Vérification de santé"
type = "endpoint"
endpoint = "ping"
connector = "myservice" # surcharge le défaut de l'app

Dossier

ChampDescription
type"folder".
label / lTitre du dossier ; l = { fr = "…" } ajoute la traduction.
itemsItems imbriqués (dossiers ou feuilles).

Un dossier dont toutes les feuilles ont été masquées par le filtrage des permissions disparaît à son tour de l'arborescence.

Feuilles

typeCe que la feuille ouvreChamps requis
"query"Une grille de table sur connector.query. Si screen est précisé, le clic sur une ligne ouvre son dialogue.query (+ connector si différent du défaut de l'app)
"dashboard"Un tableau de bord (connector.dashboard).dashboard
"endpoint"Un HttpRunner sur connector.endpoint.endpoint (+ connector)
"page"Une route React statique — pour un écran personnalisé que le framework n'héberge pas.slug
"link"Une URL externe — s'ouvre dans un nouvel onglet.href

Options communes à toutes les feuilles :

ChampEffet
iconNom d'icône lucide-react (Users, Database, …).
rolesListe de noms de rôles ; la feuille est masquée si l'utilisateur n'en possède aucun.
descriptionInfobulle ou ligne secondaire sous le libellé.

Filtrage par permissions

L'arborescence renvoyée par GET /api/menus est l'arborescence propre à l'utilisateur — tout ce qu'il n'est pas habilité à exécuter en est retiré.

FeuillePermission requise
type = "query"sql:<connecteur>:<query>
type = "endpoint"api:<connecteur>:<endpoint>
type = "dashboard"L'union des sql:<connecteur>:<query> de chaque panneau (un panneau non autorisé est masqué — voir Tableaux de bord)

S'y ajoute le filtre roles quand il est défini sur la feuille. Le filtrage remonte en cascade : si toutes les feuilles d'un dossier disparaissent, le dossier disparaît aussi.


Endpoints REST

MéthodeCheminRôle
GET/api/menusLes arborescences de toutes les apps accessibles.
GET/api/menus/{app}L'arborescence d'une seule app.

L'arborescence est résolue dans la langue de la requête (X-Liberty-Lang) ; les libellés reviennent déjà traduits. La barre latérale les affiche directement, sans recherche i18n côté client.


Conseils & bonnes pratiques

  • Une app par domaine métier. Éviter de regrouper tout un tenant sous une seule app — le sélecteur de workspace est conçu pour basculer entre plusieurs. Les dossiers à l'intérieur d'une app sont le bon niveau de regroupement.
  • Définir connector une seule fois sur l'app. La plupart des feuilles restent implicites ; les feuilles qui visent un autre connecteur ressortent visuellement.
  • Choisir le bon type de feuille selon la cible. query pour les données que l'utilisateur filtre ou édite, dashboard pour les graphiques, endpoint pour une action déclenchée sans contexte de ligne, page pour une route React personnalisée qui n'est pas hébergée par défaut.
  • Le filtre roles est une barrière douce. Les permissions assurent le contrôle réel ; roles masque la feuille pour que l'utilisateur ne voie pas ce qu'il ne peut pas exécuter. Les deux se complètent — roles seul ne suffit jamais pour la sécurité.
  • Le rechargement à chaud gère proprement les renommages et les réorganisations. Modifier menus.toml, appeler POST /admin/reload, rafraîchir l'onglet — la barre latérale se reconstruit. Les grilles de table et les tableaux de bord en cours conservent leurs données ; seule l'arborescence change.