Vues
Liste, Formulaire, Kanban, Calendrier, Gantt et plus encore — comment chaque surface d'objet dans Console est déclarée.
Vues
Une vue correspond à la manière dont un utilisateur consulte et modifie des enregistrements dans Console. Les vues sont des métadonnées déclaratives — même cycle de vie que les objets : déclarez-les une fois, livrez-les avec votre package, affichez-les n'importe où.
Deux types :
- Vues de liste — visualiser de nombreux enregistrements (grille, kanban, calendrier, …)
- Vues de formulaire — consulter / modifier un seul enregistrement (simple, à onglets, assistant, …)
Source du schéma :
packages/spec/src/ui/view.zod.ts.
La déclaration la plus courte possible
Chaque objet obtient automatiquement une grille de liste par défaut et un formulaire
simple, même si vous ne déclarez aucune vue. Ajoutez view pour remplacer ou étendre :
import { defineObject, F, P } from '@objectstack/spec'
export default defineObject({
name: 'support_ticket',
fields: [ /* ... */ ],
view: {
list: { type: 'grid', columns: ['subject', 'status', 'priority', 'assignee'] },
form: { sections: [ { label: 'Details', fields: ['subject','description','priority','status','assignee'] } ] }
}
})Pour les objets à vues multiples (par exemple un Kanban et un calendrier sur les mêmes données), utilisez les variantes nommées :
view: {
listViews: {
by_status: { type: 'kanban', kanban: { groupByField: 'status' }, columns: ['subject','priority'] },
schedule: { type: 'calendar', calendar: { startDateField: 'due_at', titleField: 'subject' } },
by_owner: { type: 'grid', columns: ['subject','status','priority'], filterableFields: ['assignee'] }
},
formViews: {
quick: { type: 'modal', sections: [ /* ... */ ] },
full: { type: 'tabbed', sections: [ /* ... */ ] }
}
}Types de vues de liste
type | Affiche | Configuration requise |
|---|---|---|
grid | Tableau de données (par défaut) | columns |
kanban | Tableau avec colonnes | kanban: { groupByField } |
gallery | Jeu de cartes | gallery: { coverField, titleField } |
calendar | Mois / semaine / jour | calendar: { startDateField, titleField } |
timeline | Flux chronologique | timeline: { startDateField, titleField } |
gantt | Échéancier de projet + dépendances | gantt: { startDateField, endDateField, titleField } |
map | Repères géospatiaux | map: { locationField } |
tree | Hiérarchie auto-référencée | tree: { parentField, labelField } |
chart | Graphique intégré | chart: { chartType, dataset } |
Options de liste courantes
{
type: 'grid',
columns: ['subject','status','priority','assignee','created_at'],
filter: [ { field: 'archived', operator: 'equals', value: false } ],
sort: [ { field: 'created_at', order: 'desc' } ],
pagination: { pageSize: 25 },
searchableFields: ['subject','description'],
filterableFields: ['status','priority','assignee'],
navigation: { mode: 'drawer' }, // 'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none'
selection: { type: 'multiple' }, // 'none' | 'single' | 'multiple'
rowActions: ['close_ticket','assign_to_me'],
bulkActions: ['bulk_close','bulk_export'],
conditionalFormatting: [
{ condition: P`record.priority == 'urgent'`, style: { background: '#fef2f2', fontWeight: 600 } }
],
exportOptions: ['csv','xlsx'],
emptyState: { title: 'No tickets yet', message: 'Create one to get started', icon: 'inbox' }
}filter et sort se compilent en ObjectQL ;
rowActions et bulkActions référencent des actions par leur nom.
Kanban
{
type: 'kanban',
kanban: {
groupByField: 'status', // discrete field — usually a select
summarizeField: 'amount', // optional total per column
columns: ['subject', 'priority', 'assignee'] // fields shown on each card
}
}Les colonnes du tableau proviennent des valeurs du groupByField ; leur ordre
et leur couleur sont repris des définitions d'options select de ce champ.
Le glisser-déposer entre colonnes déclenche une mise à jour qui définit le champ de regroupement — mêmes règles d'autorisation qu'une modification manuelle.
Calendrier
{
type: 'calendar',
calendar: {
startDateField: 'start_at',
endDateField: 'end_at', // optional — single-point if omitted
titleField: 'subject',
colorField: 'priority' // optional — colours events by value
}
}Gantt
{
type: 'gantt',
gantt: {
startDateField: 'start_at',
endDateField: 'due_at',
titleField: 'name',
progressField: 'percent_complete', // optional, drives the progress bar
dependenciesField: 'depends_on' // optional — multiselect lookup to same object
}
}Arbre
{
type: 'tree',
tree: {
parentField: 'parent_id', // self-lookup that builds the hierarchy
labelField: 'name', // shown indented in the first column
defaultExpandedDepth: 1 // optional — 0 = roots only, omit = expand all
}
}Pour un objet auto-référencé (catégories, nomenclatures, unités organisationnelles, commentaires imbriqués), la grille arborescente imbrique les lignes selon leur pointeur parentField.
Graphique (intégré)
Une vue liste chart lie un dataset nommé — la couche analytique sémantique (ADR-0021) — et sélectionne ses dimensions et mesures par leur nom. Définissez une métrique une fois, et chaque graphique, tableau de bord et rapport lié au même dataset reste cohérent :
{
type: 'chart',
chart: {
chartType: 'bar', // 'bar' | 'line' | 'pie' | 'area' | 'scatter'
dataset: 'tickets_by_status', // a dataset declared with defineDataset(...)
dimensions: ['status'], // dataset dimension name(s) — X / group / split
values: ['ticket_count'] // dataset measure name(s) — the value axis
}
}La forme en ligne xAxisField / yAxisFields / aggregation / groupByField a été supprimée en 9.0 — chaque graphique, widget de tableau de bord et rapport lie désormais un dataset. Pour des analyses plus riches et inter-objets, utilisez la surface de rapports dédiée.
Types de vues de formulaire
type | Mise en page |
|---|---|
simple | Colonne unique ou sections (par défaut) |
tabbed | Sections à onglets |
wizard | Flux étape par étape |
split | Maître-détail à deux volets |
drawer | Formulaire en panneau latéral |
modal | Formulaire en boîte de dialogue |
{
type: 'tabbed',
sections: [
{ label: 'Overview', fields: ['subject','status','priority','assignee'] },
{ label: 'Customer', fields: ['customer','contact','email','phone'] },
{ label: 'Resolution', fields: ['resolution_notes','resolved_at'] }
],
submitBehavior: { kind: 'next-record' } // 'thank-you' | 'redirect' | 'continue' | 'next-record'
}Formulaires publics
Les formulaires peuvent être rendus accessibles de manière anonyme :
{
type: 'simple',
sections: [ { fields: ['name','email','message'] } ],
sharing: {
enabled: true,
publicLink: 'contact-us', // slug under /forms/
allowAnonymous: true
},
submitBehavior: { kind: 'thank-you' }
}Cela expose automatiquement GET /api/v1/forms/contact-us et
POST /api/v1/forms/contact-us/submit — des routes de formulaire publiques qui
ne nécessitent pas d'authentification. Voir REST API → Public forms.
Visibilité, ARIA, thématisation
visibleOn: P\...`` — sur les sections et champs de formulaire, les masquer selon l'utilisateur / l'enregistrement / l'environnement (prédicat CEL)aria: { label, description, ... }— attributs ARIA pour les lecteurs d'écran (vues de liste et de formulaire)appearance: { showDescription, allowedVisualizations: [...] }— sur les vues de liste, restreint les types de liste vers lesquels les utilisateurs finaux peuvent basculer
Construire par conversation
En général, vous n'écrivez pas les métadonnées de vue à la main. Dites-le à l'AI Builder :
"Ajoute une vue kanban de l'objet support_ticket regroupée par statut, avec des cartes affichant le sujet et la priorité. Colore les colonnes en rouge / ambre / vert selon le statut."
Il appelle les outils de métadonnées, met en file d'attente le diff, et une fois que vous l'approuvez, la vue apparaît dans Console. Voir AI Builder.
Voir aussi
- Modèle de données — les objets que les vues lisent
- Actions — ce que référencent
rowActions/bulkActions - ObjectQL — ce en quoi se compilent
filter/sort - CEL —
conditionalFormatting,visibleOn @objectstack/spec/ui/view.zod.ts— schéma