Skip to main content
Voir en Markdown

Tables et listes

Les composants de données rendent les enregistrements de vos tables. Chacun se lie via le module partagé dataSource et rend les enregistrements correspondants. Le filtrage, le tri et la pagination appartiennent à dataSource, pas au composant — une table n'a ni filter ni sort de premier niveau.

app.yaml
- type: data-table
  dataSource: { table: tasks, sort: [{ field: due_date, direction: asc }] }
  columns:
    - { field: title, sortable: true }
    - { field: due_date, format: relative-date }

data-table

Propriété Description
dataSource Liaison de table. Porte filter, sort et pagination.
columns Définitions de colonnes. Générées depuis les champs de la table si omises.
selection Sélection de lignes.
bulkActions Actions proposées une fois des lignes sélectionnées.
groupBy Regroupement des lignes. Les en-têtes comptent l'ensemble des résultats, pas la page chargée.
summary Agrégats de la grille — et de chaque groupe dès que la grille est groupée.
toolbar Quels contrôles de barre d'outils afficher.
rowHeight short, medium (défaut) ou tall.
striped / bordered Alternance des fonds de lignes ; bordures de cellules.
rowColorField Champ dont les couleurs d'options déclarées remplissent chaque ligne — voir ci-dessous.
showRowNumbers Préfixe une colonne de numéros de ligne.
emptyMessage / noMatchMessage Affiché quand la source ne renvoie rien ; quand une recherche ou un filtre exclut tout.
onRowClick Action invoquée au clic sur une ligne. N'accepte que deux formes — voir ci-dessous.
rowExpand Déplie une ligne en fiche complète. true, false ou un objet — voir ci-dessous.
autoSave Comportement d'édition inline. Voir Sauvegarde automatique.
search Configuration de la recherche dans la table.

onRowClick

Un clic sur une ligne n'accepte que deux formes :

Forme Effet
{ type: navigate, path } Navigue vers path. Les jetons $record.<champ> sont remplacés par les valeurs de la ligne cliquée.
{ action: openDrawer, component } Ouvre le composant drawer voisin portant cet id. props.width optionnel remplace sa largeur pour ce déclencheur.
app.yaml
onRowClick:
  type: navigate
  path: /deals/$record.id

Noter que openDrawer se discrimine sur action, et non sur type.

Tous les autres types d'action — auth, crud, automation, filter, toast, fetch — sont rejetés ici, car un clic sur une ligne ne les a jamais exécutés. Les comportements plus riches relèvent des actions du drawer ouvert, où l'ensemble des actions est disponible : ouvrir la fiche dans un drawer, puis agir dessus depuis là.

rowExpand

Ouvrir la fiche complète d'une ligne est une propriété de la grille : ni composant voisin, ni id à maintenir en phase.

app.yaml
- type: data-table
  dataSource: { table: deals }
  rowExpand: true
Valeur Effet
true Les lignes se déplient en un panneau dont les champs sont dérivés de la table liée.
false Pas de dépliage — équivaut à omettre la clé, ce qui permet de le désactiver sur place.
{ fields?, canEdit?, title? } Restreint la liste des champs, rend le panneau en lecture seule et le nomme.

Sans fields, le panneau affiche tous les champs déclarés de la table liée, dans l'ordre de déclaration — et non les columns visibles. Si tu déplies une ligne, c'est pour voir ce que la ligne ne peut pas montrer : dériver des colonnes rendrait le dépliage sans effet sur une grille qui affiche déjà tout. Chaque champ conserve les label et description qu'il déclare. Une liste fields explicite restreint et réordonne le panneau, et peut nommer un champ qui n'est pas une colonne.

app.yaml
- type: data-table
  dataSource: { table: deals }
  columns: [{ field: name }, { field: stage }]
  rowExpand:
    fields: [name, stage, notes]
    canEdit: false
    title: Détail de l'affaire

rowExpand et onRowClick ne peuvent pas être déclarés ensemble. Une ligne n'a qu'un clic, et deux réponses à ce qu'il déclenche forment une configuration dont les deux moitiés ne peuvent pas s'appliquer : elle est donc refusée plutôt que l'une l'emporte en silence. rowExpand: false aux côtés d'onRowClick reste valide, puisque false signifie « désactivé ».

rowExpand est également refusé sur une grille liée à un point de terminaison de lecture (dataSource.system ou systemSource) : le panneau dérive ses contrôles du schéma de champs de la table liée, et un point de terminaison de lecture n'en a pas. Utilise alors un record-drawer avec dataSource.system et ses propres recordFields, ouvert par onRowClick: { action: openDrawer, component }.

La forme câblée à la main — onRowClick: { action: openDrawer } plus un drawer voisin — reste inchangée et n'est pas dépréciée. rowExpand est un raccourci pour le cas courant, non un remplacement : le drawer peut toujours se lier à une autre table que celle de la grille, se lier à un point de terminaison de lecture, être partagé par deux grilles et porter des actions de pied de panneau.

Ce que signifie un clic

Une ligne peut porter plusieurs sens à la fois. C'est la cible qui tranche, jamais le minutage :

Le clic atteint Effet
Une cellule éditable Le double-clic ouvre l'éditeur de cellule ; la fiche ne se déplie pas.
La case de sélection Sélectionne la ligne, rien d'autre.
Un en-tête de groupe Replie ou déplie ce groupe, à n'importe quel niveau d'imbrication.
Toute autre cellule Déplie la fiche.

Les lignes restent accessibles au clavier : une ligne portant une action est focalisable et répond à Entrée, sans qu'aucun bouton ne soit ajouté par ligne.

columns

Une colonne est soit une colonne de champ, soit une colonne d'actions (type: actions, portant actions, chacune { label, action, icon, confirm, visibleWhen, editSelect }).

Propriété de colonne de champ Description
field Nom du champ dans la table liée.
label Libellé d'en-tête de remplacement.
width / minWidth Largeurs en pixels.
align left (défaut), center, right.
format Rendu de cellule : truncate, currency, percentage, compact, relative-date, relative-time, short-date, long-date, datetime, yes-no, check-cross.
valueLabels Table valeur brute vers libellé affiché, p. ex. { todo: 'To do' }.
frozen Fige la colonne afin qu'elle reste visible au défilement horizontal.
visible false pour masquer la colonne.
sortable / filterable / editable Bascules de capacité par colonne.
cellStyle Règles { when: { <opérateur>: valeur }, className } appliquées par cellule. Opérateurs : eq, neq, in, notIn, contains, gt, lt, gte, lte.
app.yaml
columns:
  - field: status
    frozen: true
    cellStyle: [{ when: { eq: overdue }, className: 'text-red-600' }]
  - type: actions
    actions: [{ label: Delete, action: { type: crud, operation: delete, table: tasks } }]

Sélection, regroupement et totaux

selection prend un mode obligatoire — none, single ou multiple — plus showCheckboxes. Chaque entrée de bulkActions vaut { label, icon, action, confirm }, où confirm est le texte du dialogue et peut contenir {count}, remplacé par le nombre de lignes sélectionnées.

groupBy accepte field, direction (asc par défaut), collapsed et thenBy — jusqu'à deux niveaux supplémentaires imbriqués dans le premier, trois au total. Chaque entrée de thenBy accepte les trois mêmes clés. summary accepte field, label et function — parmi count, sum, avg, min, max.

direction ordonne les en-têtes de groupe eux-mêmes, et non les lignes à l'intérieur d'un groupe : celles-ci suivent dataSource.sort et les en-têtes de colonnes. Un regroupement sur un champ à sélection unique ou de statut ordonne les en-têtes selon l'ordre déclaré des options plutôt qu'alphabétiquement : un stage valant prospect/qualified/won se lit donc dans l'ordre où il a été écrit. Chaque en-tête compte par ailleurs l'ensemble des résultats : un groupe de 30 enregistrements affiche (30) même sur une page qui n'en montre que 22 — et cela vaut à chaque niveau, si bien qu'un sous-groupe débordant d'une page annonce quand même sa taille complète.

Chaque niveau répond pour lui-même. direction s'applique par niveau et indépendamment : un niveau externe peut s'ouvrir dans l'ordre déclaré d'un pipeline pendant que le niveau imbriqué à l'intérieur se lit en desc, sans que l'un touche à l'autre. collapsed est également par niveau, et le repliement s'imbrique : replier un parent masque tout ce qui se trouve en dessous, en-têtes de sous-groupes compris. Un champ nommé par un niveau n'a pas besoin d'être une colonne visible ; l'en-tête en porte la valeur, ce qui est souvent la raison même de grouper dessus.

Nommer le même champ à deux niveaux est refusé à la validation : tous les enregistrements d'un groupe partagent déjà la valeur qui l'a formé, donc un niveau répété place exactement un sous-groupe dans chaque groupe et ne partitionne rien.

Un summary déclaré décrit la grille entière et, dès que la grille est groupée, il décrit en plus chaque groupe — à chaque niveau, et pas seulement au plus interne. Aucune seconde option n'est à activer : les totaux par groupe découlent du summary déjà déclaré, si bien qu'une grille associant groupBy et summary gagne un total par groupe sans qu'une ligne de configuration change. Les totaux d'un groupe restent visibles lorsqu'il est replié, ce qui rend le repliement général utile pour comparer les groupes.

Parce que chaque niveau est synthétisé, les chiffres se recomposent : une sum sur les sous-groupes d'un parent égale celle de ce parent, et celles des parents égalent celle du pied de tableau. C'est tout l'intérêt de l'imbrication — comparer un parent à ses enfants suppose que les deux soient calculés.

Comme le pied de tableau, un total de groupe décrit le groupe entier et non sa partie présente sur la page courante, et il s'affiche dans le format de sa colonne. Le pied de tableau continue de répondre pour la grille entière à leurs côtés : une vue groupée montre donc à la fois les chiffres par groupe à chaque profondeur et le chiffre global.

app.yaml
- type: data-table
  dataSource: { table: deals }
  pagination: { pageSize: 25 }
  groupBy: { field: stage, direction: asc }
  summary:
    - { field: name, function: count, label: Affaires }
    - { field: value, function: sum, label: Valeur du pipeline }

Chaque étape rapporte son propre nombre d'affaires et sa valeur de pipeline, et le pied de tableau rapporte les deux toutes étapes confondues. Les totaux d'un groupe se placent sous la colonne qu'ils décrivent ; un total portant sur un champ qui n'est pas une colonne visible conserve sa valeur et s'affiche à côté du nom du groupe plutôt que d'être écarté.

L'imbrication ajoute des niveaux sans ajouter d'options — le même summary répond désormais à chacun d'eux :

app.yaml
- type: data-table
  dataSource: { table: deals }
  pagination: { pageSize: 25 }
  groupBy:
    field: region
    direction: asc
    thenBy:
      - { field: stage, direction: desc }
      - { field: owner, collapsed: true }
  summary:
    - { field: name, function: count, label: Affaires }
    - { field: value, function: sum, label: Valeur du pipeline }

Les régions se lisent dans leur ordre déclaré, les étapes de chaque région se lisent en sens inverse, et les responsables de chaque étape démarrent repliés. owner ne figure pas parmi les colonnes, et n'a pas besoin d'y figurer.

toolbar est une table de booléens sélectionnant les contrôles affichés : search, filters, sort, export, refresh, density, columnToggle, groupBy, views, viewSwitcher.

rowColorField

Désigne un champ dont les couleurs d'options déclarées remplissent chaque ligne — l'orthographe propre à la grille du colorField que lisent kanban, calendrier et chronologie. La clé s'appelle rowColorField et non colorField parce qu'une grille décide déjà d'une couleur par colonne : un colorField nu s'y lirait comme « colorer les cellules ».

app.yaml
- type: data-table
  dataSource: { table: orders }
  rowColorField: order_status

La grammaire est celle des vues d'enregistrements : le remplissage provient des couleurs d'options déclarées sur le champ désigné, et la couleur du texte de la ligne en est dérivée afin de rester lisible sur n'importe quelle teinte.

Contrairement à un calendrier ou à une chronologie, une grille n'invente rien. Une valeur dont l'option ne déclare aucune couleur n'est pas remplie — il n'y a pas de palette de repli. Il en va de même pour une ligne dont la valeur est vide, et pour une grille sans rowColorField : ces trois cas restent simplement non remplis.

Contrairement au colorField des vues d'enregistrements, celui-ci est vérifié. sovrium validate refuse un rowColorField désignant un champ absent de la table liée : une grille non remplie a la même apparence, que le nom soit une faute de frappe ou que les couleurs aient été volontairement laissées non déclarées.

list

Une liste verticale d'enregistrements. Toute la présentation vit sous listDisplay.

Propriété de listDisplay Description
itemTemplate Modèle par enregistrement : title, subtitle, image, badge, metadata.
loadMore button (un contrôle Charger plus) ou infinite (au défilement).
highlight Met en évidence les termes de recherche trouvés.
divider Trace des séparateurs entre les éléments.
maxItems Plafond d'éléments affichés.
emptyMessage Affiché quand rien ne correspond.

metadata est un tableau de { field, format } rendu dans le pied de l'élément.

app.yaml
- type: list
  dataSource: { table: articles, sort: [{ field: published_at, direction: desc }] }
  listDisplay:
    itemTemplate:
      title: '$record.title'
      metadata: [{ field: published_at, format: relative-date }]
    loadMore: button

data-form / form

Un formulaire adossé à un enregistrement. Les deux noms de type partagent un seul schéma. action décide de ce que fait la soumission ; fields surcharge le rendu de champs individuels.

Propriété Description
dataSource Liaison de table — volontairement limitée aux tables, les écritures allant vers une table et jamais vers un point de terminaison de lecture. mode: single fournit les valeurs courantes d'un formulaire d'édition.
fields Configuration par champ — field plus label, placeholder, control, options, defaultValue, readOnly, disabled, hidden, visibleWhen, requiredWhen, disabledWhen.
fieldGroups Sections { label, fields } divisant le formulaire.
layout single-column (défaut), two-column ou custom.
action Ce que lance la soumission. Voir Interactions.
app.yaml
- type: data-form
  dataSource: { table: contacts, mode: single, param: id }
  layout: two-column
  action:
    type: crud
    operation: update
    table: contacts
  fields:
    - { field: email, label: 'Email address' }
    - { field: notes, control: textarea }

Déplacé vers Tableaux, calendriers et chronologies.

kanban

Déplacé vers Tableaux, calendriers et chronologies.

calendar

Déplacé vers Tableaux, calendriers et chronologies.

data-timeline

Déplacé vers Tableaux, calendriers et chronologies.

chart

Déplacé vers Graphiques et KPI.

kpi

Déplacé vers Graphiques et KPI.

Pages connexes

Dernière mise à jour 11 août 2026

Cette documentation a été rédigée avec de l'IA : des erreurs ou du contenu obsolète sont donc possibles. Sovrium est en bêta. Les contributions et corrections sont les bienvenues.

Construit avec Sovrium