Personnalisations Fiori List Report : Header Facets, Sections et Charts

Catégorie
Fiori
Publié
Auteur
Johannes

Le List Report est l’un des templates Fiori Elements les plus utilisés. Il affiche les données sous forme de tableau et offre des filtres, un tri et des actions. Via les annotations CDS, vous pouvez personnaliser l’apparence en détail – sans une ligne de code UI5.

Structure de base d’un List Report

Un List Report se compose de plusieurs zones :

┌─────────────────────────────────────────────────────────┐
│ Zone d'en-tête │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Header Facets (KPI, graphiques, statut) │ │
│ └───────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Barre de filtres │
│ [Champ 1 ▼] [Champ 2 ▼] [Champ 3 ▼] [Go] [Adapter] │
├─────────────────────────────────────────────────────────┤
│ Barre d'outils tableau │
│ [Créer] [Supprimer] [Action perso] │
├─────────────────────────────────────────────────────────┤
│ Contenu tableau │
│ | Col 1 | Col 2 | Col 3 | Col 4 | │
│ |-------|-------|-------|-------| │
│ | Ligne 1 | ... | ... | ... | │
│ | Ligne 2 | ... | ... | ... | │
└─────────────────────────────────────────────────────────┘

Annotation @UI.facet en détail

L’annotation @UI.facet est la clé pour personnaliser les List Reports et Object Pages. Elle définit quelles facettes (sections) sont affichées et comment elles sont structurées.

Types de facettes

TypeDescriptionUtilisation
#HEADER_SECTIONZone dans l’en-têteKPI, indicateurs de statut
#COLLECTIONConteneur pour plusieurs facettesGroupement
#IDENTIFICATION_REFERENCEChamps d’identification standardEn-tête Object Page
#LINEITEM_REFERENCEVue tableauEntités subordonnées
#DATAPOINT_REFERENCEPoint de données uniqueKPI, indicateur
#CHART_REFERENCEGraphiqueVisualisations
#FIELDGROUP_REFERENCEGroupe de champsZones de formulaire

Structure de base d’une définition de facette

@UI.facet: [{
id: 'HeaderFacetID', -- ID unique
purpose: #HEADER, -- #HEADER ou #STANDARD
type: #DATAPOINT_REFERENCE, -- Type de facette
targetQualifier: 'TotalAmount', -- Référence à @UI.dataPoint
label: 'Montant total', -- Texte d'affichage
position: 10 -- Ordre
}]

Header et Collection Facets : La différence

Les Header Facets apparaissent dans la zone supérieure (en-tête) d’un List Report ou d’une Object Page. Elles affichent des informations condensées comme des KPI ou des statuts.

Les Collection Facets sont des conteneurs qui regroupent plusieurs facettes. Elles apparaissent généralement dans la zone de contenu de l’Object Page.

@UI.facet: [
-- Header Facets (en haut dans l'en-tête)
{
id: 'HeaderKPI',
purpose: #HEADER, -- Zone d'en-tête
type: #DATAPOINT_REFERENCE,
targetQualifier: 'TotalOrders',
position: 10
},
-- Collection Facet (zone de contenu)
{
id: 'GeneralInfo',
purpose: #STANDARD, -- Zone de contenu
type: #COLLECTION, -- Conteneur
label: 'Informations générales',
position: 20
},
{
id: 'Details',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Details',
parentId: 'GeneralInfo', -- Subordonné
position: 10
}
]

Header Facets personnalisés (KPI, indicateurs de statut)

Les Header Facets sont parfaits pour les KPI et les affichages de statut.

KPI avec DataPoint

@Metadata.allowExtensions: true
define view entity ZC_SalesOrder
as projection on ZI_SalesOrder
{
key SalesOrderId,
@UI.dataPoint: {
qualifier: 'TotalAmount',
title: 'Valeur de commande',
valueFormat: { numberOfFractionalDigits: 2 }
}
@Semantics.amount.currencyCode: 'CurrencyCode"
TotalAmount,
CurrencyCode,
@UI.dataPoint: {
qualifier: 'ItemCount',
title: 'Positions',
valueFormat: { numberOfFractionalDigits: 0 }
}
NumberOfItems,
@UI.dataPoint: {
qualifier: 'OrderStatus',
title: 'Statut',
criticality: 'StatusCriticality"
}
Status,
StatusCriticality
}

La définition de facette correspondante :

@UI.facet: [
{
id: 'TotalAmountHeader',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'TotalAmount',
position: 10
},
{
id: 'ItemCountHeader',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'ItemCount',
position: 20
},
{
id: 'StatusHeader',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'OrderStatus',
position: 30
}
]

Statut avec Criticality

La Criticality détermine la couleur de l’indicateur de statut :

ValeurSignificationCouleur
0NeutreGris
1NégatifRouge
2CritiqueOrange
3PositifVert
define view entity ZC_Order
as projection on ZI_Order
{
key OrderId,
Status,
-- Calcul de la Criticality
case Status
when 'OPEN' then 0 -- Gris
when 'PENDING' then 2 -- Orange
when 'COMPLETED' then 3 -- Vert
when 'CANCELLED' then 1 -- Rouge
else 0
end as StatusCriticality
}

Sections personnalisées dans le List Report

Les sections structurent la zone de contenu. Avec #COLLECTION, vous créez des sections groupées.

Plusieurs sections avec groupes de champs

@UI.facet: [
-- Section 1 : En-tête de commande
{
id: 'OrderHeader',
purpose: #STANDARD,
type: #COLLECTION,
label: 'En-tête de commande',
position: 10
},
{
id: 'BasicData',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'BasicData',
parentId: 'OrderHeader',
label: 'Données de base',
position: 10
},
{
id: 'Dates',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Dates',
parentId: 'OrderHeader',
label: 'Échéances',
position: 20
},
-- Section 2 : Positions
{
id: 'OrderItems',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
targetElement: '_Items',
label: 'Positions',
position: 20
},
-- Section 3 : Notes
{
id: 'Notes',
purpose: #STANDARD,
type: #COLLECTION,
label: 'Notes & pièces jointes',
position: 30
}
]

Définir des groupes de champs

define view entity ZC_Order
{
key OrderId,
@UI.fieldGroup: [{ qualifier: 'BasicData', position: 10 }]
CustomerId,
@UI.fieldGroup: [{ qualifier: 'BasicData', position: 20 }]
CustomerName,
@UI.fieldGroup: [{ qualifier: 'BasicData', position: 30 }]
ShipToAddress,
@UI.fieldGroup: [{ qualifier: 'Dates', position: 10 }]
OrderDate,
@UI.fieldGroup: [{ qualifier: 'Dates', position: 20 }]
RequestedDeliveryDate,
@UI.fieldGroup: [{ qualifier: 'Dates', position: 30 }]
ActualDeliveryDate
}

Conditional Facets (dépendant des données)

Les Conditional Facets ne sont affichées que lorsque certaines conditions sont remplies. Cela se fait via la propriété hidden.

Masquer une facette en fonction du statut

@UI.facet: [
{
id: 'ShippingInfo',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Shipping',
label: 'Informations d''expédition',
position: 20,
hidden: 'HideShipping' -- Référence au champ calculé
}
]
define view entity ZC_Order
{
key OrderId,
Status,
-- Info expédition uniquement pour certains statuts
case when Status in ('SHIPPED', 'DELIVERED')
then abap_false
else abap_true
end as HideShipping,
@UI.fieldGroup: [{ qualifier: 'Shipping', position: 10 }]
TrackingNumber,
@UI.fieldGroup: [{ qualifier: 'Shipping', position: 20 }]
Carrier,
@UI.fieldGroup: [{ qualifier: 'Shipping', position: 30 }]
ShippedDate
}

Combiner plusieurs conditions

define view entity ZC_Contract
{
key ContractId,
ContractType,
Status,
-- Facette uniquement pour contrats de service actifs
case when ContractType = 'SERVICE"
and Status = 'ACTIVE"
then abap_false
else abap_true
end as HideServiceDetails,
-- Facette uniquement pour contrats avec option de renouvellement
case when HasRenewalOption = abap_true
then abap_false
else abap_true
end as HideRenewalInfo
}

Intégration de graphiques dans l’en-tête

Les graphiques dans l’en-tête visualisent les données d’un coup d’œil.

Micro Chart dans l’en-tête

@UI.facet: [{
id: 'SalesChart',
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'SalesTrend',
position: 40
}]
define view entity ZC_SalesOverview
{
key SalesOrgId,
@UI.chart: [{
qualifier: 'SalesTrend',
chartType: #COLUMN,
title: 'Chiffre d''affaires mensuel',
measures: ['Revenue'],
dimensions: ['Month']
}]
@Aggregation.default: #SUM
Revenue,
Month
}

Différents types de graphiques

-- Bullet Chart pour atteinte d'objectif
@UI.chart: [{
qualifier: 'TargetAchievement',
chartType: #BULLET,
title: 'Atteinte d''objectif',
measures: ['ActualValue'],
measureAttributes: [{
measure: 'ActualValue',
role: #AXIS_1,
asDataPoint: true
}]
}]
@UI.dataPoint: {
qualifier: 'ActualValue',
targetValue: 'TargetValue',
forecastValue: 'ForecastValue',
minimumValue: 0,
criticality: 'AchievementCriticality"
}
ActualValue,
TargetValue,
ForecastValue,
-- Radial Chart pour affichage en pourcentage
@UI.chart: [{
qualifier: 'CompletionRate',
chartType: #DONUT,
title: 'Taux d''achèvement',
measures: ['CompletedPercent']
}]
CompletedPercent

Graphique avec couleurs Criticality

define view entity ZC_ProjectStatus
{
key ProjectId,
@UI.chart: [{
qualifier: 'BudgetChart',
chartType: #BULLET,
title: 'Budget',
measures: ['SpentBudget'],
measureAttributes: [{
measure: 'SpentBudget',
role: #AXIS_1,
asDataPoint: true
}]
}]
@UI.dataPoint: {
qualifier: 'SpentBudget',
targetValue: 'TotalBudget',
criticality: 'BudgetCriticality"
}
SpentBudget,
TotalBudget,
-- Calculer la Criticality
case
when SpentBudget <= TotalBudget * 0.8 then 3 -- Vert
when SpentBudget <= TotalBudget then 2 -- Orange
else 1 -- Rouge
end as BudgetCriticality
}

Exemple complet : Vue d’ensemble des ventes

@Metadata.allowExtensions: true
@UI.headerInfo: {
typeName: 'Document de vente',
typeNamePlural: 'Documents de vente',
title: { value: 'SalesOrderId' },
description: { value: 'CustomerName' }
}
define view entity ZC_SalesOrderReport
as projection on ZI_SalesOrder
{
-- Définitions de facettes
@UI.facet: [
-- Header Facets
{
id: 'TotalValueHeader',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'TotalValue',
position: 10
},
{
id: 'ItemCountHeader',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'ItemCount',
position: 20
},
{
id: 'StatusHeader',
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'Status',
position: 30
},
{
id: 'TrendChart',
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'MonthlySales',
position: 40
},
-- Sections de contenu
{
id: 'GeneralSection',
purpose: #STANDARD,
type: #COLLECTION,
label: 'Général',
position: 10
},
{
id: 'CustomerData',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Customer',
parentId: 'GeneralSection',
label: 'Données client',
position: 10
},
{
id: 'OrderData',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Order',
parentId: 'GeneralSection',
label: 'Données de commande',
position: 20
},
{
id: 'ItemsSection',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
targetElement: '_Items',
label: 'Positions',
position: 20
},
{
id: 'ShippingSection',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Shipping',
label: 'Expédition',
position: 30,
hidden: 'HideShipping"
}
]
@UI.lineItem: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
key SalesOrderId,
@UI.lineItem: [{ position: 20 }]
@UI.selectionField: [{ position: 20 }]
@UI.fieldGroup: [{ qualifier: 'Customer', position: 10 }]
CustomerId,
@UI.lineItem: [{ position: 30 }]
@UI.fieldGroup: [{ qualifier: 'Customer', position: 20 }]
CustomerName,
@UI.fieldGroup: [{ qualifier: 'Customer', position: 30 }]
CustomerCity,
@UI.lineItem: [{ position: 40 }]
@UI.selectionField: [{ position: 30 }]
@UI.fieldGroup: [{ qualifier: 'Order', position: 10 }]
OrderDate,
@UI.fieldGroup: [{ qualifier: 'Order', position: 20 }]
RequestedDeliveryDate,
@UI.lineItem: [{ position: 50, criticality: 'StatusCriticality' }]
@UI.selectionField: [{ position: 40 }]
@UI.dataPoint: {
qualifier: 'Status',
title: 'Statut',
criticality: 'StatusCriticality"
}
Status,
StatusCriticality,
@UI.lineItem: [{ position: 60 }]
@UI.dataPoint: {
qualifier: 'TotalValue',
title: 'Valeur de commande"
}
@Semantics.amount.currencyCode: 'CurrencyCode"
TotalValue,
CurrencyCode,
@UI.dataPoint: {
qualifier: 'ItemCount',
title: 'Positions"
}
NumberOfItems,
@UI.fieldGroup: [{ qualifier: 'Shipping', position: 10 }]
TrackingNumber,
@UI.fieldGroup: [{ qualifier: 'Shipping', position: 20 }]
ShippedDate,
-- Conditionnel : Expédition uniquement pour commandes expédiées
case when Status in ('SHIPPED', 'DELIVERED')
then abap_false
else abap_true
end as HideShipping,
_Items
}

Bonnes pratiques

1. Nommer les ID de facettes de manière cohérente

-- Bonne convention de nommage
{
id: 'HeaderStatus', -- Header + Contenu
id: 'SectionCustomer', -- Section + Thème
id: 'FieldGroupAddress', -- Type + Contenu
}

2. Attribuer les positions avec des intervalles

-- Avec intervalles pour extensions ultérieures
position: 10
position: 20
position: 30
-- Pas : 1, 2, 3 (pas d'intervalles pour extensions)

3. Criticality toujours comme champ séparé

-- Bon : Champ séparé pour Criticality
Status,
StatusCriticality,
-- À éviter : Calcul inline dans l'annotation

4. Tenir compte des performances pour les graphiques

-- Optimiser les agrégations pour les graphiques
@Aggregation.default: #SUM
Revenue,
-- Limiter la quantité de données pour les graphiques d'en-tête

Erreurs typiques et solutions

ProblèmeCauseSolution
Facette non affichéepurpose incorrectVérifier #HEADER vs. #STANDARD
Graphique videPas d’agrégationAjouter @Aggregation.default
Conditionnel ne fonctionne pasChamp non exposéInclure le champ Hidden dans Projection
Groupe de champs non visibleparentId manquantDéfinir parentId sur Collection

Sujets complémentaires