Skip to main content
skill CX Codex

sap-fiori-add-visual-filter — Claude Code skill: how to install

Adds chart-based visual filters to SAP Fiori Elements filter bars and value help dialogs using CAP or ABAP RAP. Configures CDS aggregation annotations and UI charts.

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

What sap-fiori-add-visual-filter does

The skill prompts for visual filter parameters and generates CDS annotations for SAP Fiori Elements. It configures @Aggregation.ApplySupported, declares measures with Analytics.AggregatedProperty, and generates UI.Chart alongside UI.PresentationVariant definitions.

CAP projects run in VS Code or SAP Business Application Studio, with Fiori MCP Server required in VS Code. ABAP RAP works exclusively in VS Code through the ABAP Development Tools extension. In RAP setups, never edit metadata.xml directly because the file is strictly read-only.

Chart type restrictions require extra attention. Line charts support only date and time dimensions like Edm.Date or Edm.DateTimeOffset. For string codes or categories, stick with Bar charts. In CAP models, write aggregation methods as lowercase strings such as 'sum' instead of enums to avoid SQL generation errors.

What it helps with

  • Add Bar or Line chart filters to a Fiori Elements filter bar
  • Configure CDS aggregation annotations for CAP or ABAP RAP
  • Target managed association foreign keys in value help annotations
  • Avoid SQL generation errors caused by uppercase aggregation enums

Example prompts for the agent

  • Add a Bar visual filter to the Travels entity by Category with sum of Amount
  • Create a Line visual filter using BookingDate and TotalPrice in Fiori Elements
  • Configure CDS aggregation and UI.Chart annotations for a status filter in CAP

How to install sap-fiori-add-visual-filter

1Skills CLI (Vercel)

npx skills add SAP/open-ux-tools --skill sap-fiori-add-visual-filter -a claude-code

2Manually: put the files in place

~/.claude/skills/sap-fiori-add-visual-filter/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/sap-fiori-add-visual-filter/

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

Questions about sap-fiori-add-visual-filter

How to install sap-fiori-add-visual-filter in Claude Code?

Run npx skills add SAP/open-ux-tools --skill sap-fiori-add-visual-filter -a claude-code in your terminal.

What does sap-fiori-add-visual-filter do?

It creates CDS annotations for chart-based visual filters in SAP Fiori Elements, setting up aggregation, UI.Chart, and UI.PresentationVariant.

What restrictions apply to Line charts?

The ChartType: #Line setting only works with date and time dimensions like Edm.Date, Edm.TimeOfDay, or Edm.DateTimeOffset. For textual categories or status fields, use #Bar.

Source text

SKILL.md · Apache-2.0
---
name: sap-fiori-add-visual-filter
description: Add visual filters (chart-based) to SAP Fiori Elements filter bar or value help using CAP or ABAP RAP. Use when asked to add chart filters, bar chart selectors, or visual filter bars to a Fiori Elements application.
argument-hint: visual filter with entity name, dimension field (e.g., Status, Category), measure field (e.g., TotalPrice, Amount), aggregation method (sum/min/max/average/countdistinct), and chart type (Bar/Line)
metadata:
  author: sap-fiori-tools
  version: "0.0.7"
---

# SAP Fiori Visual Filter

## Purpose
Add **chart-based filters (Bar/Line)** to filter bar or value help dialog (OData V4).

---

## 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 visual filter to
2. **Dimension field** - The field to filter 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 or Line (recommend Bar as default)

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

⚠️ **Line chart dimension type restriction:** `ChartType: #Line` only supports dimensions typed as `Edm.Date`, `Edm.TimeOfDay`, or `Edm.DateTimeOffset`. If the requested dimension is a different type (e.g. string/association code like Status, Category), either use `#Bar` instead or confirm with the user that the dimension field is a date/time type before proceeding.

---

## CAP Implementation

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

### Aggregated Property (Measure)
```cds
Analytics.AggregatedProperty #Amount_sum : {
  $Type: 'Analytics.AggregatedPropertyType',
  Name: 'Amount_sum',
  AggregatableProperty: Amount,
  AggregationMethod: 'sum',
  ![@Common.Label]: 'Total 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 Annotation
```cds
UI.Chart #visualFilter : {
  ChartType: #Bar,
  Dimensions: [Category],
  DynamicMeasures: ['@Analytics.AggregatedProperty#Amount_sum']
}
```

✅ Uses **DynamicMeasures**

### PresentationVariant
```cds
UI.PresentationVariant #visualFilter: {
  Visualizations: ['@UI.Chart#visualFilter']
}
```

#### Scalar property versus managed association dimension

The annotation location depends on how the dimension is declared in the CAP model:

- A direct scalar property can be annotated inline. For example, `Category : String(80)` is a real entity element, so use `Category @Common.ValueList #visualFilter` inside the `annotate ... with { ... }` block.
- A managed association is different. For example, `Category : Association to Categories` generates the local foreign key `Category_code`; `Category_code` is not a declared element in the source entity and cannot be annotated inline in that block.

For the scalar `Category` dimension, this is valid:

```cds
annotate MyService.Entity with {
  Category @Common.ValueList #visualFilter: {
    $Type: 'Common.ValueListType',
    CollectionPath: 'Entity',
    PresentationVariantQualifier: 'visualFilter',
    Parameters: [
      { $Type: 'Common.ValueListParameterInOut',
        LocalDataProperty: Category, ValueListProperty: 'Category' }
    ]
  };
};
```

For a visual filter whose dimension is the managed `Category` association, use the separate association-key target described below. Do not replace the target with `Category_code` inside the entity annotation block.

#### ⚠️ Dimension is a Managed Association FK (e.g. `Category_code`, `Status_ID`)

When the dimension field is the auto-generated foreign key column of a managed association (e.g. `Category_code` from `Category : Association to Categories`), you **cannot** annotate it inline inside the entity's `annotate ... with { ... }` block — the FK column is not visible as an element there. The CDS compiler will fail with:

```
Element "Category_code" has not been found
```

**✅ CORRECT:** Use a **separate `annotate` statement** targeting the association itself — the compiler rewrites it to the FK column:

```cds
// Compiles to target Travels/Category_code in $metadata
annotate MyService.Entity:Category with @(
  Common.ValueList #visualFilter: {
    $Type                       : 'Common.ValueListType',
    CollectionPath              : 'Entity',
    PresentationVariantQualifier: 'visualFilter',
    Parameters                  : [
      { $Type: 'Common.ValueListParameterInOut',
        LocalDataProperty: Category_code, ValueListProperty: 'Category_code' }
    ]
  }
);
```

Key points:
- Target syntax: `annotate <Service>.<Entity>:<assoc>` — for a managed to-one association, the compiler copies/rewrites annotations on the association to its generated local FK element. This matches documented CAP compiler behavior (see CAP docs on "Managed Associations"). If other annotations (e.g. `Common.Label`, `Common.Text`) already target the same association elsewhere, they're merged into a single `Annotations Target="...Entity/<assoc>_code"` block in `$metadata`. Verify with `cds compile --to edmx` if unsure.
- `LocalDataProperty` and `ValueListProperty` both use the **FK column name** (e.g. `Category_code`), not the association name.
- `CollectionPath` is the **same entity set** that holds the chart data (self-reference), not the code-list entity set.

**❌ WRONG:** Inline annotation inside the entity block — fails to compile:
```cds
annotate MyService.Entity with { ... } {
  Category_code @Common.ValueList #visualFilter: { ... };  // ❌ Element not found
};
```

### SelectionFields
```cds
UI.SelectionFields: [Category]
```

### Manifest configuration (MANDATORY)
The shared Manifest Configuration section below applies to CAP and RAP.
---

## ABAP RAP Implementation (4 Steps)

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

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

**Missing ANY of these will cause the visual filter to fail:**

- [ ] `@OData.applySupportedForAggregation: #FULL` on **projection view** (ZC_*)
- [ ] `@Aggregation.default: #SUM` (or #AVG, #MIN, #MAX) on **measure field**
- [ ] `@UI.chart` annotation with correct **qualifier** in metadata extension
- [ ] `@UI.selectionField` on dimension field
- [ ] Frontend `Common.ValueList` annotation in annotation.xml
- [ ] Manifest `controlConfiguration` with visual filter settings
- [ ] 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
- Visual filter will fail to load
- 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: #SUM  // 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, SelectionField 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: 'visualFilter',
  chartType: #BAR,
  dimensions: ['Category'],
  measures: ['Amount']
}]
@UI.presentationVariant: [{
  qualifier: 'visualFilter',
  visualizations: [{
    type: #AS_CHART,
    qualifier: 'visualFilter'
  }]
}]
annotate view ZC_ENTITY with
{
  @UI.selectionField: [{ position: 10 }]
  Category;

  @EndUserText.label: 'Amount'
  Amount;
}
```

### 3. Frontend (annotation.xml) - Add ValueList

**ValueList Annotation on Dimension Field:**
```xml
<Annotations Target="<YourServiceNamespace>.<YourEntityType>/Category">
  <Annotation Term="Common.ValueList" Qualifier="visualFilter">
    <Record Type="Common.ValueListType">
      <PropertyValue Property="CollectionPath" String="<YourEntitySet>"/>
      <PropertyValue Property="PresentationVariantQualifier" String="visualFilter"/>
      <PropertyValue Property="Parameters">
        <Collection>
          <Record Type="Common.ValueListParameterInOut">
            <PropertyValue Property="LocalDataProperty" PropertyPath="Category"/>
            <PropertyValue Property="ValueListProperty" String="Category"/>
          </Record>
        </Collection>
      </PropertyValue>
    </Record>
  </Annotation>
</Annotations>
```

**Important:** Replace placeholders:
- `<YourServiceNamespace>` - e.g., `com.sap.gateway.srvd.ztravel.v0001`
- `<YourEntityType>` - e.g., `TravelType`
- `<YourEntitySet>` - e.g., `Travel`

### 4. 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 visual filter 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="visualFilter">`
   - Also verify: `<Annotation Term="UI.PresentationVariant" Qualifier="visualFilter">`
   - If these annotations are missing from $metadata, the DDLX is not active OR the service binding needs republishing

### 5. Manifest configuration (MANDATORY)
Use the shared Manifest Configuration section below.

---

## Manifest Configuration (Common for CAP and RAP)

**Complete manifest.json structure:**

```json
"sap.ui5": {
  "routing": {
    "targets": {
      "<YourListReport>": {  // Replace with your actual List Report target name
        "type": "Component",
        "name": "sap.fe.templates.ListReport",
        "options": {
          "settings": {
            "contextPath": "/<YourEntitySet>",  // Replace with your entity set path
            "controlConfiguration": {
              "@com.sap.vocabularies.UI.v1.SelectionFields": {
                "layout": "CompactVisual",
                "initialLayout": "Visual",
                "filterFields": {
                  "Category": {
                    "visualFilter": {
                      "valueList": "com.sap.vocabularies.Common.v1.ValueList#visualFilter"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

**Path:** `sap.ui5.routing.targets.<ListReport>.options.settings.controlConfiguration`
Visual filter settings belong under `controlConfiguration`, not directly under `settings`.

**Important placeholders:**
- `<YourListReport>` - Your List Report target name (e.g., `TravelList`)
- `<YourEntitySet>` - Your entity set path (e.g., `/Travel`)
- `Category` - Your dimension field name
- `visualFilter` - Must match the qualifier in your annotations

---

## CRITICAL: Manifest Configuration Structure
**Visual filter settings go under `controlConfiguration`, NOT directly under `settings`!**

---

## 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

---

## Key Differences

**CAP:**
- Aggregation + measures defined in CDS
- Uses DynamicMeasures
- Aggregation and chart defined in same place

**RAP:**
- Aggregation defined in backend CDS only
- Uses Measures (not DynamicMeasures)
- Metadata is read-only

---

## Common Mistakes
- Backend Changes are not activated.
- Qualifier mismatch between Chart, ValueList, PresentationVariant, and manifest
- Wrong path in manifest (use full vocabulary path)
- Missing SelectionField annotation
- Non-numeric measure field
- Missing compact visual layout configuration in manifest 

**CAP:**
- Trying to annotate a managed-association FK column (e.g. `Status_code`) inline inside `annotate ... with { ... }` — fails with `Element "..._code" has not been found`. Use a separate `annotate Service.Entity:assoc with (...)` statement instead (see "Dimension is a Managed Association FK" above).

**RAP:**
- Missing backend aggregation support
- Using DynamicMeasures instead of Measures
- Adding Common.ValueList in backend instead of frontend (ValueList MUST be in frontend annotation.xml)
- Adding UI annotations directly in CDS projection view instead of metadata extension
- Trying to use @Consumption.valueHelpDefinition for visual filters (that's for value help dialogs, not visual filters)

---

## Best Practices

- Always activate backend changes in ADT MCP before testing
- Use 1 dimension + 1 measure per visual filter
- Prefer Bar charts for better readability
- Keep qualifier names consistent across all annotations
- Test with different data volumes
- Always include layout: "CompactVisual" and initialLayout: "Visual" in manifest

**RAP Specific:**
- ALWAYS use ADT MCP to modify backend files when available
- Chart + PresentationVariant → Backend metadata extension (.ddlx.acds)
- Common.ValueList → Frontend annotation.xml (CANNOT be in backend)

## References

- **SAP Fiori Elements Visual Filter Documentation**: https://ui5.sap.com/#/topic/5ea9bb1d544a42eabf71822a8a2cb753
- **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 set5

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