Skip to main content
skill CX Codex

sap-fiori-analytical-chart — Claude Code skill for SAP Fiori

A skill that puts an aggregated chart above the table on a SAP Fiori Elements List Report. Useful when a report has to be read as a diagram, not row by row.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add SAP/open-ux-tools --skill sap-fiori-analytical-chart -a claude-code
Open on GitHub

What sap-fiori-analytical-chart does

On a SAP Fiori Elements List Report the skill builds a chart section with the table kept underneath, and the numbers behind the chart are aggregated. CAP and ABAP RAP projects on OData V4 both work. Six answers come first: the entity, a dimension to group by, a numeric measure, the aggregation method, a chart type (Bar, Column, Line, Pie, HeatMap, Waterfall, HorizontalWaterfall) and separate tabs or a hybrid view. Nothing is edited until those are settled.

For CAP it changes CDS annotations: @Aggregation.ApplySupported, Analytics.AggregatedProperty, UI.Chart and PresentationVariant. Write the aggregation method as a lowercase string. 'average' works, #AVG breaks SQL generation. In ABAP RAP, @OData.applySupportedForAggregation: #FULL has to sit on the projection view ZC_* and never on the interface view — the app will not load without it. @UI.chart belongs in the header block ahead of annotate view; attached to a field it fails activation with a wrong-scope error. metadata.xml stays as it is, the file is read-only.

Both setups need a Fiori MCP Server, and ABAP RAP also relies on the ADT MCP server bundled with the ABAP Development Tools extension. CAP runs in VS Code or SAP Business Application Studio, ABAP RAP in VS Code only.

What it helps with

  • add a chart section with aggregated values to an existing List Report
  • switch a report between chart and table views
  • declare an aggregated property for an average measure
  • turn on aggregation support on a RAP projection view
  • move a chart annotation into header scope so activation passes

Example prompts for the agent

  • Add an analytical chart to the List Report for entity Reservations: dimension Category, measure Amount, aggregation average, chart type Column, hybrid view.
  • Give me separate ChartView and TableView tabs for Bookings, grouped by Status, measure TotalPrice, aggregation sum, chart type Bar.
  • Check that @OData.applySupportedForAggregation: #FULL is on the projection view ZC_Reservation, and move @UI.chart into the header if activation fails.

How to install sap-fiori-analytical-chart

1Skills CLI (Vercel)

npx skills add SAP/open-ux-tools --skill sap-fiori-analytical-chart -a claude-code

2Manually: put the files in place

~/.claude/skills/sap-fiori-analytical-chart/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/sap-fiori-analytical-chart/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about sap-fiori-analytical-chart

How do I install sap-fiori-analytical-chart in Claude Code?

Run npx skills add SAP/open-ux-tools --skill sap-fiori-analytical-chart -a claude-code. The skill lands in ~/.claude/skills/sap-fiori-analytical-chart/SKILL.md.

What does sap-fiori-analytical-chart do?

It writes the annotations for a chart-plus-table view on a SAP Fiori Elements List Report, reading aggregated data from a CAP or ABAP RAP service on OData V4.

Does ABAP RAP work outside VS Code?

No. RAP support needs the ABAP Development Tools extension, which only exists for VS Code, so SAP Business Application Studio is an option for CAP projects alone.

Source text

SKILL.md · Apache-2.0
---
name: sap-fiori-analytical-chart
description: Add analytical chart (chart + table hybrid) to SAP Fiori Elements List Report using aggregated data. Supports CAP and ABAP RAP (OData V4). Use when asked to add a chart section, aggregated data visualization, or Analytical List Page chart to a List Report.
argument-hint: Entity, dimension, measure, aggregation
metadata:
  author: sap-fiori-tools
  version: "0.0.5"
---

# SAP Fiori Analytical Chart

## Purpose
Add **analytical chart + table (hybrid view)** to visualize aggregated data.

---

## Prerequisites

**CAP Projects:**
- ✅ **VS Code or SAP Business Application Studio (BAS)** - Both environments supported
- ✅ **Fiori MCP Server** - Required for Fiori app modification (VS Code only)

**ABAP RAP Projects:**
- ✅ **VS Code only** - ABAP Development Tools extension is VS Code-specific
- ✅ **Fiori MCP Server** - Required for Fiori app modification
- ✅ **ABAP Development Tools for VS Code extension** - Required for backend development (includes ADT MCP server for RAP operations)

---

## MANDATORY: Gather Required Inputs First

**STOP and ASK the user for ALL of these inputs if ANY are missing from the prompt:**

1. **Entity** - Which entity to add the analytical chart to
2. **Dimension field** - The field to group by (e.g., Category, Status, Destination)
3. **Measure field** - The numeric field to aggregate (e.g., Amount, TotalPrice, ReservationPrice)
4. **Aggregation method** - How to aggregate (see valid values below)
5. **Chart type** - Bar, Column, Line, Pie, HeatMap, Waterfall, HorizontalWaterfall
6. **Display mode** - How the chart should be shown:
   - **Separate tabs** (Approach 2)
   - **Hybrid view** (Approach 1)

**DO NOT proceed with implementation until all inputs are confirmed.**

---

## CAP Implementation

### Enable Aggregation
```cds
@Aggregation.ApplySupported: {
  Transformations: ['aggregate','groupby'],
  AggregatableProperties: [{Property: Amount}],
  GroupableProperties: [Category]
}
```

### Aggregated Property
```cds
Analytics.AggregatedProperty #Amount_avg: {
  Name: 'Amount_avg',
  AggregatableProperty: Amount,
  AggregationMethod: 'average',
  ![@Common.Label]: 'Average Amount'
}
```

**Valid `AggregationMethod` values (lowercase string):**
- `sum` - Sum of the non-null values
- `min` - Smallest of the non-null values
- `max` - Largest of the non-null values
- `average` - Sum of non-null values divided by count of non-null values
- `countdistinct` - Count of distinct values, omitting null values

⚠️ **CRITICAL:** Must be a **lowercase string** (e.g., `'sum'`), **NOT** an enum (e.g., `#SUM`). Using an enum will cause SQL generation errors.

### Chart
```cds
UI.Chart #AnalyticalChart: {
  $Type: 'UI.ChartDefinitionType',
  Title: 'Chart Title',
  ChartType: #Column,
  Dimensions: [Category],
  DynamicMeasures: ['@Analytics.AggregatedProperty#Amount_avg'],
  MeasureAttributes: [{
    $Type: 'UI.ChartMeasureAttributeType',
    DynamicMeasure: '@Analytics.AggregatedProperty#Amount_avg',
    Role: #Axis1
  }],
  DimensionAttributes: [{
    $Type: 'UI.ChartDimensionAttributeType',
    Dimension: Category,
    Role: #Category
  }]
},
UI.PresentationVariant #ChartView: {
  $Type: 'UI.PresentationVariantType',
  Text: 'Chart View',
  Visualizations: ['@UI.Chart#AnalyticalChart']
},
UI.PresentationVariant #TableView: {
  $Type: 'UI.PresentationVariantType',
  Text: 'Table View',
  Visualizations: ['@UI.LineItem']
}
```

✅ Uses **DynamicMeasures**

---

## ABAP RAP Implementation (3 Steps + Manifest Configuration)

### CRITICAL: NEVER EDIT metadata.xml - IT IS READ-ONLY!

### ⚠️ PRE-FLIGHT CHECKLIST - Verify BEFORE Implementation

**Missing ANY of these will cause the app to fail/not load:**

- [ ] `@OData.applySupportedForAggregation: #FULL` on **projection view** (ZC_*)
- [ ] `@Aggregation.default: #AVG` (or #SUM, #MIN, #MAX) on **measure field**
- [ ] `@UI.chart` annotation with correct **qualifier** in metadata extension
- [ ] Manifest `targets.<ListReport>.options.settings.views.paths` configuration
- [ ] All CDS objects **activated**

---

### 1. Backend Projection View (MANDATORY) - Enable Aggregation Support

⚠️ **CRITICAL: @OData.applySupportedForAggregation annotation is MANDATORY**

**WITHOUT this annotation:**
- OData service will NOT support aggregation
- App will FAIL TO LOAD (blank screen/errors)
- Chart annotations will be ignored

**Placement:**
- ✅ **MUST be on PROJECTION view** (ZC_* or ZZZC_*) with `TRANSACTIONAL_QUERY` contract
- ❌ **NOT on interface view** (ZR_* or ZZZR_*)

**CORRECT Example:**
```abap
// MANDATORY! Must be present!
@OData.applySupportedForAggregation: #FULL
define root view entity ZC_ENTITY
  provider contract TRANSACTIONAL_QUERY
  as projection on ZR_ENTITY
{
  @Aggregation.default: #AVG  // Specify aggregation method for measure
  Amount;
  Category;  // Dimension field (no aggregation annotation needed)
}
```

**WRONG Example:**
```abap
// ❌ WRONG - Don't put on interface view
// WRONG PLACE!
@OData.applySupportedForAggregation: #FULL
define root view entity ZR_ENTITY
  as select from TABLE
```

### 2. Backend Metadata Extension (MANDATORY) - Add Chart, PresentationVariant Annotations

⚠️ **CRITICAL: `@UI.chart` and `@UI.presentationVariant` are ENTITY-LEVEL (header) annotations.**
Place them in the **header block — BEFORE `annotate view ZC_ENTITY with`** (alongside `@UI.headerInfo.*`), **NOT inside the `{ ... }` field block and NOT on a field** (e.g. the dimension field).
Attaching `@UI.chart` to a field fails activation with: `Annotation 'UI.chart.qualifier' used at wrong position (wrong scope)`.

```abap
// ↓↓↓ HEADER SCOPE: these go BEFORE `annotate view`, never on a field ↓↓↓
@UI.chart: [{
  qualifier: 'AnalyticalChart',
  title: 'Chart Title',
  description: 'Chart description',
  chartType: #COLUMN,
  dimensions: ['Category'],
  measures: ['Amount'],
  dimensionAttributes: [{
    dimension: 'Category',
    role: #CATEGORY
  }],
  measureAttributes: [{
    measure: 'Amount',
    role: #AXIS_1
  }]
}]
@UI.presentationVariant: [{
  qualifier: 'ChartView',
  text: 'Chart View',
  visualizations: [{
    type: #AS_CHART,
    qualifier: 'AnalyticalChart'
  }]
},
{
  qualifier: 'TableView',
  text: 'Table View',
  visualizations: [{
    type: #AS_LINEITEM
  }]
}]
annotate view ZC_ENTITY with
{
  // Other field annotations...
  @EndUserText.label: 'Amount'
  Amount;
  
  @EndUserText.label: 'Category'
  Category;
}
```

### 3. Verify Active Annotations (MANDATORY)

**After activating both DDLS and DDLX, verify the changes are live:**

⚠️ **IMPORTANT: DDLS and DDLX are Separate Objects**

The **projection view (DDLS file)** and **metadata extension (DDLX file)** are **separate ABAP development objects** that happen to share the same entity name.

**Key points:**
- **DDLS** = Data Definition (projection view) - contains entity definition, associations, fields, and data annotations
- **DDLX** = Metadata Extension - contains UI annotations (@UI.chart, @UI.presentationVariant, field labels, etc.)
- **Both must be activated individually** - activating one does NOT activate the other
- **Both must exist** for the analytical chart to work

**Activation:**
- Use ABAP ADT MCP to activate ABAP objects
- Activate the **DDLS file** separately from the **DDLX file**

**Verification Steps:**

1. **Verify Activation Status:**
   - Check the activation tool output for success messages
   - Verify no errors were reported during activation
   - Both DDLS and DDLX must show successful activation

2. **Check OData $metadata:**
   - Open your service URL in browser: `<service-url>/$metadata`
   - Search for: `<Annotation Term="UI.Chart" Qualifier="AnalyticalChart">`
   - Also verify: `<Annotation Term="UI.PresentationVariant" Qualifier="ChartView">`
   - If these annotations are missing from $metadata, the DDLX is not active OR the service binding needs republishing

---

## Manifest Configuration (Common for CAP and RAP)

### Approach 1: Hybrid View (Chart + Table Together)

**Manifest:**
```json
"targets": {
  "<ListReport>": {  // Replace with your actual List Report target name
    "type": "Component",
    "name": "sap.fe.templates.ListReport",
    "options": {
      "settings": {
        "contextPath": "/<YourEntity>",  // Replace with your entity set path
        "views": {
          "paths": [
            {
              "primary": [
                { "annotationPath": "com.sap.vocabularies.UI.v1.Chart#AnalyticalChart" }
              ],
              "secondary": [
                { "annotationPath": "com.sap.vocabularies.UI.v1.LineItem" }
              ],
              "defaultPath": "both"
            }
          ]
        }
      }
    }
  }
}
```

### Approach 2: Multiple View Tabs with PresentationVariant

**Manifest:**
```json
"targets": {
  "<ListReport>": {  // Replace with your actual List Report target name
    "type": "Component",
    "name": "sap.fe.templates.ListReport",
    "options": {
      "settings": {
        "contextPath": "/<YourEntity>",  // Replace with your entity set path
        "views": {
          "paths": [
            {
              "key": "ChartView",
              "annotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant#ChartView"
            },
            {
              "key": "TableView",
              "annotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant#TableView"
            }
          ]
        }
      }
    }
  }
}
```
---

## Testing

Refer to the **Application Preview Guidelines** section in the `sap-fiori-app-development` skill for detailed testing instructions, including:
- CAP project testing with watch scripts
- Standalone Fiori project testing with live backend vs. mock mode
- Metadata refresh procedures after backend changes

---

## Implementation Order (RAP)

**Follow this sequence to avoid errors:**

1. **Modify Projection View (ZC_ENTITY) - DDLS file**
   - Add `@OData.applySupportedForAggregation: #FULL` at top
   - Add `@Aggregation.default: #AVG` to measure field
   - **Activate** using ABAP ADT MCP
   - Verify activation succeeded

2. **Modify Metadata Extension (ZC_ENTITY) - DDLX file**
   - Add `@UI.chart` annotation with qualifier
   - Add `@UI.presentationVariant` annotations
   - **Activate** using ABAP ADT MCP
   - Verify activation succeeded

3. **Verify Annotations are Active** (see Step 3 in ABAP RAP Implementation section above)

4. **Update Fiori App Manifest**
   - Add `views.paths` under `targets.<ListReport>.options.settings` (NOT inside `controlConfiguration`)
   - Save manifest.json

5. **Test**
   - Run `npm start` (fetches live metadata - no republishing needed)
   - Service binding does NOT need to be republished
   - If chart doesn't appear, check browser console for "Annotation Path ... not found" error

---

## Troubleshooting

### Symptom: Console error "Annotation Path for the primary visualization ... not found"

**Full error message:**
```
Annotation Path for the primary visualization com.sap.vocabularies.UI.v1.Chart#AnalyticalChart not found
```

**Cause:** The metadata extension (DDLX) is NOT active, so the `@UI.chart` annotation is not exposed in the OData $metadata.

**Solution:**
1. Activate the DDLX file using ABAP ADT MCP
2. Verify activation succeeded (check tool output for errors)
3. Verify the annotation appears in $metadata: `<service-url>/$metadata` (search for `Chart#AnalyticalChart`)
4. Restart the Fiori app: `npm start`

**Note:** Even if you edited the DDLX, it won't take effect until explicitly activated. The DDLS and DDLX are separate objects.

---

### Symptom: App doesn't load / Blank screen / Chart not visible

**Cause 1:** Missing `@OData.applySupportedForAggregation: #FULL`
- **Solution:** Add to projection view (ZC_*), activate, restart app

**Cause 2:** Annotation on wrong view
- **Solution:** Move from interface view (ZR_*) to projection view (ZC_*)

**Cause 3:** Measure field not numeric
- **Solution:** Verify field is numeric type (Amount, Quantity, Decimal, Integer)

**Cause 4:** Wrong qualifier in manifest
- **Solution:** Verify qualifier in manifest matches `@UI.chart: [{ qualifier: 'AnalyticalChart' }]`

**Cause 5:** Missing `@Aggregation.default` on measure
- **Solution:** Add `@Aggregation.default: #AVG` (or #SUM, #MIN, #MAX) to measure field

**Cause 6:** DDLX not activated (see console error above)
- **Solution:** Activate the metadata extension (DDLX) file using ABAP ADT MCP

### Symptom: Chart shows but with wrong data

**Cause:** Wrong aggregation method
- **Solution:** Change `@Aggregation.default` value (#AVG, #SUM, #MIN, #MAX)

---

## Key Differences

**CAP:**
- Aggregation + measures defined in CDS  
- Uses DynamicMeasures  

**RAP:**
- Aggregation defined in backend CDS only  
- Uses Measures  

---

## Common Mistakes 

**General:**
- Wrong manifest config  
- Mixing Approach 1 and Approach 2 configurations
- Non-numeric measure field
- Wrong qualifier (manifest doesn't match annotation)

**RAP-Specific:**
- ❌ **MOST COMMON:** Missing `@OData.applySupportedForAggregation: #FULL` → App won't load
- ❌ Placing aggregation annotation on interface view instead of projection view
- ❌ Missing `@Aggregation.default` on measure field
- ❌ Forgetting to activate CDS objects after changes
- ❌ Using wrong view contract (must be `TRANSACTIONAL_QUERY`)

---

## Best Practices
- Use 1 dimension + 1–2 measures  
- Prefer Column/Bar charts  
- **Approach 1**: Use "defaultPath": "both" for chart + table side-by-side in same view
- **Approach 2**: Use `PresentationVariant` for separate view tabs (chart or table)  

## References

- **SAP Fiori Elements Analytical List Report**: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/topic/floorplanListReport/analyticalListReport
- **ABAP RAP Aggregation support**: https://help.sap.com/docs/abap-cloud/abap-rap/projection-view

© sap-fiori-tools · Apache-2.0 · SAP/open-ux-tools

Similar skills

Everything for Frontend and UI →

From the same set8

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor