Écrans
Un Screen rassemble tout ce qu'il faut pour rendre un objet métier dans l'interface : la grille (alimentée par la read_query), les requêtes CRUD optionnelles, la définition du formulaire modal, le drapeau d'audit et le menu de ligne. Un Screen par objet métier — la grille, les onglets, les champs et les actions sont déclarés dans une seule entrée TOML.
Les écrans vivent dans config/screens.toml, organisés sous [screens.<app>.<id>]. Ils sont rechargeables à chaud avec le reste de la configuration.
Vue d'ensemble
Déclarer un écran
[screens.myapp.users]
label = "Users"
description = "Application users"
read_query = "users_get" # requis
update_query = "users_put"
insert_query = "users_post"
delete_query = "users_delete"
auto_load = true
audit = true # ajoute l'onglet d'audit au dialogue
editable = true # un clic sur une ligne ouvre le formulaire modal
uploadable = true # active l'import Excel
[[screens.myapp.users.dialog.tabs]]
id = "general"
label = "General"
cols = 2
fields = [
{ column = "ID", hidden = true },
{ column = "NAME", required = true, colspan = 2 },
{ column = "EMAIL" },
{ column = "STATUS" },
{ column = "CITY" },
{ column = "ADMIN", visible_when = [{ field = "STATUS", value = "Y" }] },
{ column = "PASSWORD", hide_on_edit = true },
]
Le champ connector est optionnel — il reprend par défaut le connecteur qui porte la read_query. Les écrans mixtes (un connecteur pour la lecture, un autre pour l'écriture) sont autorisés.
Requêtes
Un Screen peut référencer jusqu'à quatre requêtes :
| Champ | Rôle | Permission |
|---|---|---|
read_query | Le SELECT qui alimente la grille. Obligatoire. | sql:<conn>:<read_query> |
update_query | Le UPDATE appelé sur Enregistrer en mode modification. Optionnel. | sql:<conn>:<update_query> + writable = true sur la requête |
insert_query | Le INSERT appelé sur Enregistrer en mode création. Optionnel. | sql:<conn>:<insert_query> + writable = true |
delete_query | Le DELETE appelé depuis le menu de ligne. Optionnel. | sql:<conn>:<delete_query> + writable = true |
Les requêtes que l'utilisateur peut effectivement exécuter sont renvoyées par GET /api/screens/{app}/{id} — l'interface React masque les boutons Enregistrer, Ajouter et Supprimer en conséquence.
Dialogue
Le dialog décrit le formulaire modal. Il est défini directement sur l'écran — pas de seconde table à consulter.
Onglets
[[screens.myapp.users.dialog.tabs]]
id = "general"
label = "General"
cols = 2 # largeur de la grille CSS (2 = deux colonnes)
hide_on_add = false
hide_on_edit = false
| Champ | Description |
|---|---|
id | Identifiant de l'onglet — apparaît dans l'URL au clic. |
label / l | Titre de l'onglet ; l = { fr = "..." } ajoute la traduction. |
cols | Largeur de la grille CSS. Le colspan de chaque champ s'élargit dans cette grille. |
hide_on_add / hide_on_edit | Masque l'onglet en mode création ou modification. |
fields | Liste ordonnée de ScreenField. |
Champs
fields = [
{ column = "NAME", required = true },
{ column = "STATUS", required = true, default = "Y" },
{ column = "PASSWORD", hide_on_edit = true, hidden_in_view = true },
{ column = "ADMIN", visible_when = [{ field = "STATUS", value = "Y" }],
required_when = [{ field = "ROLE", value = ["admin", "owner"] }] },
]
Pour chaque champ :
| Champ | Effet |
|---|---|
column | Colonne du résultat de read_query. Le widget est choisi d'après la règle de cette colonne (BOOLEAN → case à cocher, ENUM → SearchSelect, LOOKUP → SearchSelect, plus date / nombre / texte selon format/type). |
hidden | Masque le champ. |
disabled | Affiche un écho en lecture seule. |
required | Marque le libellé d'un *. |
colspan | Élargit dans la grille cols de l'onglet. |
default | Valeur initiale à la création. |
hide_on_add / hide_on_edit | Visibilité selon le mode (création ou modification). |
visible_when / required_when / disabled_when | Conditions par champ (voir ci-dessous). |
Conditions par champ
Chaque règle *_when se réfère à un autre champ du même dialogue (jamais à un filtre serveur). La règle se déclenche quand la valeur courante de ce champ dans le formulaire est égale à value (ou présente dans value quand c'est une liste). Plusieurs règles dans une même liste sont combinées en ET logique ; la règle est active quand toutes ses conditions sont vérifiées.
Les drapeaux statiques (visible: false, required: false, disabled: false) agissent comme valeur par défaut quand la liste *_when correspondante est vide.
Audit
Avec audit = true, l'onglet Audit est ajouté automatiquement au dialogue. Il expose :
AUD_CREATED_BY/AUD_CREATED_ATAUD_UPDATED_BY/AUD_UPDATED_AT
Ces champs sont remplis côté serveur à l'enregistrement, depuis principal.username et SYSDATE. L'onglet est en lecture seule.
Actions et menu de ligne
| Champ | Rôle |
|---|---|
actions | Boutons d'action en haut du dialogue qui déclenchent des appels connecteur. Même mécanique que les liaisons Actions de NomaUBL. Slice 4 — runtime à venir. |
row_menu | Menu ⋮ par ligne dans la grille. Slice 6 — runtime à venir. |
Ces champs sont déjà présents dans le schéma Screen ; le runtime est en avance dans NomaUBL et est en cours de portage. Voir le fichier docs/PLAN.md du dépôt du framework pour l'ordre des slices.
Endpoints REST
| Méthode | Chemin | Rôle |
|---|---|---|
GET | /api/screens | Tous les écrans accessibles, regroupés par app (vue liste — sans le corps du dialogue ni les actions). |
GET | /api/screens/{app} | Tous les écrans accessibles pour une app donnée. Renvoie 404 quand aucun écran ne survit au filtrage. |
GET | /api/screens/{app}/{id} | L'écran complet, avec dialog, actions et row_menu. |
L'ensemble est filtré par les permissions : un écran dont l'utilisateur ne peut pas exécuter la read_query est masqué dans GET /api/screens et renvoie 403 sur la route par identifiant.
Conseils & bonnes pratiques
- Un écran par objet métier. Résister à la tentation de regrouper plusieurs lectures dans le même écran : la grille est rapide, et un second écran avec son propre dialogue est plus lisible qu'un dialogue à douze onglets.
- Marquer les champs vraiment obligatoires avec
required. Cela évite un aller-retour : le dialogue refuse d'enregistrer tant qu'un champ requis n'est pas rempli, au lieu de laisser le backend rejeter la ligne. - Les conditions par champ sont évaluées en direct.
visible_when/required_when/disabled_whensont attachées au champ et combinées en ET logique. Chaque règle ne référence qu'un autre champ du même dialogue, ce qui rend le comportement prévisible. - L'audit remplit lui-même l'utilisateur et l'horodatage. Ne pas lier manuellement
AUD_CREATED_BYouAUD_UPDATED_ATà un champ de formulaire — ils sont renseignés côté serveur depuis le principal etSYSDATEau moment de l'enregistrement. - Les écrans inter-connecteurs sont légitimes. Un écran qui lit dans
myappet écrit dans un connecteur d'audit est parfaitement supporté. Le choix du connecteur se fait sur la requête, pas sur l'écran.