Aller au contenu principal

Définition de formulaire Model-Driven

Identifiant du schéma : model-driven-form@2

Version remplacée : model-driven-form@1 (model-driven-form-v1.schema.json) reste publiée et enregistrée, afin qu’une solution déjà déployée soit toujours validée selon le schéma pour lequel elle a été conçue. La version 2 ne fait qu’ajouter le champ facultatif controlProps.lookupView : toute définition v1 est donc aussi une définition v2 valide. Schéma lisible par machine : model-driven-form.schema.json

La représentation canonique d’un formulaire Model-Driven Apps (section 6.7) — la mise en page utilisée pour consulter et modifier un enregistrement. Validée de manière identique, qu’elle provienne du concepteur, d’un appel d’API, d’un assistant IA ou d’une importation de solution.

Structure​

ChampTypeObligatoireRemarques
logicalNamestringouiPréfixé par l’éditeur, en snake-case minuscule.
displayNamestringouiNom lisible du formulaire.
entitystringouiLe nom logique de la table propriétaire.
descriptionstringnonLa ligne affichée sous le titre dans la barre de titre du formulaire.
iconstringnonL’icône affichée dans la barre de titre du formulaire.
sectionsarrayl’un des deuxUne ou plusieurs sections titrées — l’ancienne mise en page à plat (voir ci-dessous).
tabsarrayl’un des deuxLa mise en page plus riche en onglets (voir ci-dessous).
actionsarraynonActions de barre de commandes configurables.

Un formulaire porte soit sections, soit tabs, mais jamais aucun des deux. Les nouvelles définitions doivent utiliser tabs ; sections est accepté pour que les formulaires existants continuent de fonctionner, et est traité comme un onglet unique de lignes à une colonne.

Section (ancienne mise en page sections)​

ChampTypeObligatoireRemarques
titlestringouiTitre de la section.
columnsintegerouiColonnes de mise en page, de 1 à 4.
fieldsarrayouiPlacements de champs (voir ci-dessous).

Onglet (mise en page tabs)​

ChampTypeObligatoireRemarques
idstringnonId stable attribué par le concepteur.
titlestringouiTitre de l’onglet.
iconstringnonIcône affichée à côté du titre de l’onglet.
rowsarrayouiLignes de mise en page pleine largeur : { id?, columns: 1–4, sections: [...] }, chaque section étant { id?, title, icon?, span?, fields, timeline? }.

Placement de champ​

ChampTypeObligatoireRemarques
fieldstringvoir remarquesLe nom logique du champ (doit être défini sur la table). Omis uniquement pour un placement Label, qui est un contenu statique et n’est lié à aucun champ.
labelstringnonRemplacement du libellé ; à défaut, le nom d’affichage du champ est utilisé.
controlstringnonLe nom logique d’un contrôle personnalisé monté à la place de l’éditeur de champ natif. Le contrôle doit être installé dans l’environnement ; sinon, le champ revient à son éditeur natif.
controlTypestringnonLe contrôle intégré avec lequel afficher le champ (section 6.13.5). L’un de Text, TextArea, Check, Toggle, Date, DateTime, Time, PersianDate, PersianDateTime, PersianTime, Lookup, Dropdown, Label. À omettre pour laisser le Player choisir la saisie par défaut du type de données du champ. Les variantes Persian… affichent le même sélecteur que leurs équivalents grégoriens, mais s’ouvrent sur le calendrier jalali quelle que soit la langue de l’application ; la valeur stockée reste un instant grégorien. Label est un contenu Markdown statique (controlProps.labelText) sans champ lié.
requiredbooleannonIndique si le champ est obligatoire pour l’activité sur ce formulaire (section 6.13.5) — l’utilisateur doit le renseigner avant d’enregistrer. Une préoccupation du formulaire, et non une contrainte de base de données (chaque colonne de table accepte null) ; le Player l’applique dans le navigateur, le serveur non. En son absence, c’est le IsRequired propre au champ qui s’applique.
readOnlybooleannonIndique si le champ est affiché en lecture seule sur ce formulaire (affichage, pas modification). Un champ en lecture seule s’affiche en texte simple, sans contrôle de saisie. Absent n’est pas false : absent, le champ est modifiable dans un onglet mais en lecture seule dans header ; un champ d’en-tête devient donc modifiable avec un false explicite.
controlPropsobjectnonLes propriétés du contrôle choisi (voir ci-dessous).

Priorité des contrôles : un control personnalisé l’emporte sur controlType, qui l’emporte sur la valeur par défaut du type de données du champ. Omettez les deux et le Player choisit la valeur par défaut.

« Obligatoire » est une règle de formulaire, pas une contrainte de colonne. required réside sur le placement : un même champ peut donc être obligatoire sur un formulaire et facultatif sur un autre, et il n’est vérifié que dans le Player, lorsque l’utilisateur enregistre. Les colonnes de table acceptent toujours null au niveau de la base de données (à la manière de Power Apps) : un enregistrement créé par une importation ou un appel d’API n’est donc jamais rejeté pour un champ obligatoire manquant — la seule valeur qu’exige le serveur est le champ principal (nom) de la table.

Propriétés du contrôle (controlProps)​

ChampTypeLu parRemarques
dateFormatstringDate, DateTime, Time (et leurs variantes Persian…)Format d’affichage. Jetons : yyyy/yy, MMMM (nom complet du mois)/MMM (abrégé)/MM/M, dd/d, HH, mm, ss ; tout autre caractère est littéral. En son absence, le format par défaut du calendrier est utilisé — d MMMM yyyy pour le persan (p. ex. 12 اردیبهشت 1405), yyyy/MM/dd pour le grégorien.
trueLabelstringCheck, ToggleLe libellé affiché pour l’état « oui ».
falseLabelstringCheck, ToggleLe libellé affiché pour l’état « non ».
rowsintegerTextAreaNombre de lignes visibles, de 2 à 20.
lookupEntitystringLookupNom logique de la table sur laquelle la recherche se résout.
lookupViewstringLookupNom logique de la vue qui fournit les colonnes affichées dans le panneau de résultats de la recherche. En son absence, la plateforme en résout une — voir le viewType du schéma de vue.
lookupRowCountintegerLookupCombien de lignes candidates le panneau de la recherche propose à la fois (1–500). En son absence, la valeur par défaut de la plateforme, 10, est utilisée. Le serveur plafonne toute demande — un sélecteur n’est pas un rapport. Ajouté après la v2 par élargissement sur place : toute définition valide sans lui l’est toujours.
lookupPrimaryFieldstringLookupRemplacement, propre au contrôle, du champ servant de ligne de nom à chaque candidat. En son absence, le champ principal de la table cible est utilisé ; un nom qui n’est pas un champ de la cible est ignoré.
lookupSecondaryFieldstringLookupRemplacement, propre au contrôle, de la seconde ligne sous le nom, qui prend le pas sur le champ désigné par la table cible. En son absence, la désignation de la table est utilisée.
lookupImageFieldstringLookupRemplacement, propre au contrôle, du champ File/Image servant d’image à chaque candidat, qui prend le pas sur l’image d’enregistrement de la table cible. En son absence, l’image de la table est utilisée ; un champ qui n’est pas une image est ignoré.
imageSizestringChamp ImageLa taille d’affichage de l’aperçu d’un champ Image — sm (par défaut, taille d’avatar), md ou lg (une image bien visible). N’a de sens que pour un champ Image.
labelTextstringLabelLe texte fixe d’un contrôle Label, rendu dans un petit sous-ensemble de Markdown sûr : titres #/##/###, **bold**, *italic*, `code`, listes - , liens [text](url) (http/https/mailto/relatifs uniquement) et {color:name}…{/color} (un nom de couleur autorisé ou #hex). Aucun HTML brut n’est jamais rendu.
optionsarrayDropdownOptions fixes, chacune { value, label }, propres à ce seul champ. Préférez un groupe d’options pour tout ce qui est réutilisé entre champs ou tables : un groupe est un composant partagé et versionné, aux valeurs à l’abri des collisions, alors que ces options sont une liste privée sur un seul formulaire. Un champ dont le type de données est OptionSet ignore ceci et puise dans son groupe.

Les propriétés qui ne s’appliquent pas au controlType choisi sont ignorées, et non rejetées — changer le contrôle d’un champ puis revenir en arrière ne fait donc pas perdre sa configuration.

Chaque field référencé doit être un champ défini sur la table — ce qui est appliqué à l’enregistrement, en plus de la validation du schéma.

Section chronologie (timeline)​

Une section d’un onglet peut être une chronologie au lieu d’un groupe de champs : les enregistrements d’autres tables dont la recherche pointe vers l’enregistrement ouvert, fusionnés et du plus récent au plus ancien — les e-mails, appels et notes d’un client dans une seule colonne. Une section est l’un ou l’autre : lorsque timeline est présent, fields doit être un tableau vide.

ChampTypeObligatoireRemarques
sourcesarray (1–10)ouiLes tables qu’elle lit, une entrée par table (ci-dessous).
pageSizeinteger (5–100)nonÉléments affichés avant Charger plus ; 20 en son absence.

Chaque source :

ChampTypeObligatoireRemarques
entitystringouiLe nom logique de la table source.
regardingstringouiUne recherche de la table source qui cible la table du formulaire, ou une recherche multitable qui la liste. La chronologie affiche les lignes dont la valeur est l’enregistrement ouvert.
datestringouiUn champ Date et heure de la source (champs système tels que created_at_utc compris). Les éléments sont triés selon ce champ, du plus récent au plus ancien.
titlestringouiLe champ qui sert de titre à chaque élément.
bodystringnonUn champ dont chaque élément affiche les premiers mots.
typestringnonUn champ de groupe d’options qui distingue les lignes de la source. Chaque élément prend son icône et sa couleur de son option, le filtre affiche une puce par option, et Nouveau propose une entrée par option, préremplie.
statusstringnonUn champ affiché à côté de la date de chaque élément.

À l’enregistrement et à l’importation, chaque nom est vérifié par rapport aux tables de l’environnement : la table source doit exister, regarding doit pouvoir pointer vers la table du formulaire, date doit être une date, type doit être un choix, et le reste doit exister. Une chronologie qui échoue à l’une de ces vérifications est refusée (modelapps.form.timeline_*) plutôt qu’affichée vide. Supprimer un champ utilisé par une chronologie le retire de celle-ci : une partie facultative est abandonnée, et une source qui perd son regarding, sa date ou son title est supprimée.

Exemple​

{
"logicalName": "par_invoice_main",
"displayName": "Main",
"entity": "par_invoice",
"description": "The invoice's main form",
"icon": "Receipt",
"tabs": [
{
"id": "tab-general",
"title": "General",
"rows": [
{
"id": "row-1",
"columns": 2,
"sections": [
{
"id": "sec-header",
"title": "Header",
"fields": [
{ "field": "par_name", "required": true },
{ "field": "par_total", "label": "Amount" },
{ "field": "par_number", "readOnly": true },
{
"field": "par_due",
"controlType": "Date",
"controlProps": { "dateFormat": "dd/MM/yyyy" }
},
{
"field": "par_paid",
"controlType": "Toggle",
"controlProps": { "trueLabel": "Paid", "falseLabel": "Unpaid" }
},
{ "field": "par_signature", "control": "par_signature_pad" }
]
}
]
}
]
}
]
}