From d777dd64fecc192b939480a77b7064ad68f82d89 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 14 May 2026 14:45:29 +0300 Subject: [PATCH 1/8] feat(ui5): Add integration cards skill --- plugins/ui5/skills/integration-cards/SKILL.md | 1943 +++++++++++++++++ 1 file changed, 1943 insertions(+) create mode 100644 plugins/ui5/skills/integration-cards/SKILL.md diff --git a/plugins/ui5/skills/integration-cards/SKILL.md b/plugins/ui5/skills/integration-cards/SKILL.md new file mode 100644 index 0000000..a5e79c8 --- /dev/null +++ b/plugins/ui5/skills/integration-cards/SKILL.md @@ -0,0 +1,1943 @@ +--- +name: integration-cards +description: Guidelines and best practices for developing UI Integration Cards (also called UI5 Integration Cards). This skill MUST be loaded before working on any Integration Card related task. +--- + +# UI Integration Cards Development Guidelines + +> *This document outlines the fundamental rules and best practices an AI agent must follow when developing or modifying Integration Cards. Adherence to these guidelines is critical for creating modern, maintainable, and performant UI Integration Cards.* +## 1. Coding Guidelines +- **ALWAYS** strive to create declarative Integration Card, such as "Calendar", "List", "Table", "Timeline", "Object" or "Analytical". + - create an Integration Card Extension only in exceptional cases. +- **ALWAYS** create links using the `actions` property. +- **ALWAYS** refer to parameters using correct syntax - `{parameters>/parameterKey/value}`. +- **ALWAYS** perform validation of the integration card as described in [2. Validation](#2-validation). +- **ALWAYS** show a preview of the generated card following the [4. Preview Instructions](#4-preview-instructions). +- **ALWAYS** generate new declarative integration cards using the `create_integration_card` tool. + +### 1.1 Data +- **NEVER** modify the provided data under any circumstances. +- **ALWAYS** include the service URL directly in the card manifest when one is supplied. +- **ALWAYS** reference destinations by name when available. Configure the destination in the `sap.card/configuration/destinations/` and reuse it with binding syntax like `{{destinations.destinationName}}`. +- **NEVER** replace destination name with its URL. +- **ALWAYS** place data configuration in: `"sap.card"/data/` +- **NEVER** place data configuration in: + - `"sap.card"/content/data/` + - `"sap.card"/header/data/` +- Data can be provided via: + 1. Inline JSON object + 2. Network request (HTTP/HTTPS/Destination) + 3. Extension method call +- **ALWAYS** verify these paths are correctly set: + - `"sap.card"/data/path` (Primary data path) + - `"sap.card"/content/data/path` (Content-specific path. It overrides the primary data path) + - `"sap.card"/header/data/path` (Header-specific path. It overrides the primary data path) + +#### 1.1.1 Data Errors Detection +- Symptom: "No data to display" message appears. +- Cause: Incorrect data configuration or data path in the content incorrectly overrides the primary data path. +- Solution: Verify all rules in [1.1 Data](#11-data) are properly followed. + +### 1.2 Internationalization +- **ALWAYS** bind properties that are not bound to the data to the `i18n` model. + +### 1.3 Analytical Cards +- **ALWAYS** follow [6. Analytical Cards Coding Guidelines](#6-analytical-cards-coding-guidelines) when developing Analytical cards. + +### 1.4 Configuration Editor +- **ALWAYS** follow [5. Configuration Editor](#5-configuration-editor) guidelines when creating or modifying Configuration Editors for Integration Cards. + +## 2. Validation +- **ALWAYS** ensure that `manifest.json` file is valid JSON. +- **ALWAYS** ensure that in `manifest.json` file the property `sap.app/type` is set to `"card"`. +- **ALWAYS** validate the `manifest.json` against the UI5 Manifest schema. Use the `run_manifest_validation` tool to do this. +- **ALWAYS** avoid using deprecated properties in `manifest.json` and elsewhere. +- **NEVER** treat Integration Cards' project as UI5 project, except for cards of type "Component". + +## 3. Card Explorer +- The Card Explorer provides detailed documentation for the Integration Cards schema, including descriptions of every property, guidance for integrating cards into hosting environments, configuration editor documentation with examples, and broader best practices. It is available at: https://ui5.sap.com/test-resources/sap/ui/integration/demokit/cardExplorer/webapp/index.html + +## 4. Preview Instructions +- If preview of the card must be shown, **ALWAYS** check the card folder for an existing preview file and any accompanying instructions or scripts, and reuse them if available. + * for example, in NodeJS-based projects, search the `package.json` file for `start` or similar script. If such is available, use it + * also search in the `README.md` file. +- If preview instructions are not available, you have to create an HTML page that contains a `ui-integration` card element which references the card manifest. Then serve the HTML page using `http` server. + +## 5. Configuration Editor +Configuration Editor allows different personas to customize Integration Cards without modifying the manifest file directly. +The following roles/personas are supported: +- Administrator +- Page/Content Administrator +- Translator + +The Configuration Editor is implemented through two key components: + +1. **Definition file**: Create a `dt/Configuration.js` file that exports a Designtime definition object +2. **Manifest reference**: Reference this definition in the `manifest.json` under the `sap.card/configuration/editor` property + +The `dt/Configuration.js` file defines the Configuration Editor's structure by specifying: +- Form layout and field definitions +- Input controls and visualizations +- Validation rules and field relationships +- Grouping and organization of configuration options + +When creating or modifying Integration Cards, follow these guidelines for Configuration Editors: +- Assume the role of Administrator persona when designing the Configuration Editor. +- **ALWAYS** ensure that the Configuration Editor reflects the current structure and fields of the `manifest.json`. +- **ALWAYS** make the existing fields in the `manifest.json` configurable via the editor. For example manifest parameters, title, subtitle, icon of the header, etc. +- **NEVER** add fields to the editor that do not exist in the `manifest.json`. +- **ALWAYS** remove fields from the editor when removing them from the `manifest.json`. +- **ALWAYS** add fields in the Configuration Editor when adding them to the `manifest.json`. + +### 5.1 Example: +`manifest.json` file: +```json +{ + "sap.app": { + "id": "test.editor", + "type": "card", + "title": "Test Card", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui": { + "technology": "UI5" + }, + "sap.card": { + "type": "List", + "configuration": { + "editor": "./dt/Configuration", + "parameters": { + "cardTitle": { + "value": "Customers" + }, + "icon": { + "value": "sap-icon://account" + }, + "maxItems": { + "value": 3 + }, + "showDescription": { + "value": true + }, + "dateContext": { + "value": "2020-09-02" + }, + "Customers": { + "value": ["ALFKI"] + }, + "northwindDestination": { + "value": "northwind" + } + }, + "destinations": { + "northwind": { + "name": "Northwind_V4", + "defaultUrl": "https://services.odata.org/V4/Northwind/Northwind.svc" + } + } + }, + "data": { + "request": { + "url": "{{destinations.northwind}}/Customers", + "parameters": { + "$select": "CustomerID,CompanyName,ContactName", + "$top": "{parameters>/maxItems/value}" + } + } + }, + "header": { + "title": "{parameters>/cardTitle/value}", + "subtitle": "As of {parameters>/dateContext/value}", + "icon": { + "src": "{parameters>/icon/value}", + "shape": "Circle" + } + }, + "content": { + "data": { + "path": "/value" + }, + "item": { + "title": "{CompanyName}", + "description": "{= ${parameters>/showDescription/value} ? ${ContactName} : '' }" + }, + "maxItems": "{parameters>/maxItems/value}" + } + } +} +``` + +`dt/Configuration.js` file: +```javascript +sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { + "use strict"; + + return function () { + return new Designtime({ + form: { + items: { + + /* ======================= + General + ======================= */ + generalGroup: { + type: "group", + label: "General" + }, + + cardTitle: { + manifestpath: "/sap.card/configuration/parameters/cardTitle/value", + type: "string", + label: "Card Title", + translatable: true, + required: true, + allowDynamicValues: true + }, + + icon: { + manifestpath: "/sap.card/header/icon/src", + type: "string", + label: "Icon", + visualization: { + type: "IconSelect", + settings: { + value: "{currentSettings>value}", + editable: "{currentSettings>editable}" + } + } + }, + + iconShape: { + manifestpath: "/sap.card/header/icon/shape", + type: "string", + label: "Icon Shape", + visualization: { + type: "ShapeSelect", + settings: { + value: "{currentSettings>value}", + editable: "{currentSettings>editable}" + } + }, + cols: 1 + }, + + iconBackground: { + manifestpath: "/sap.card/header/icon/backgroundColor", + type: "string", + label: "Icon Background", + visualization: { + type: "ColorSelect", + settings: { + enumValue: "{currentSettings>value}", + editable: "{currentSettings>editable}" + } + }, + cols: 1 + }, + + /* ======================= + Data & Behavior + ======================= */ + dataGroup: { + type: "group", + label: "Data & Behavior" + }, + + maxItems: { + manifestpath: "/sap.card/configuration/parameters/maxItems/value", + type: "integer", + label: "Maximum Items", + visualization: { + type: "Slider", + settings: { + value: "{currentSettings>value}", + min: 1, + max: 10, + width: "100%", + enabled: "{currentSettings>editable}" + } + } + }, + + showDescription: { + manifestpath: "/sap.card/configuration/parameters/showDescription/value", + type: "boolean", + label: "Show Contact Name", + visualization: { + type: "Switch", + settings: { + state: "{currentSettings>value}", + customTextOn: "Show", + customTextOff: "Hide", + enabled: "{currentSettings>editable}" + } + } + }, + + dateContext: { + manifestpath: "/sap.card/configuration/parameters/dateContext/value", + type: "date", + label: "Date Context" + }, + + /* ======================= + Filtering + ======================= */ + filterGroup: { + type: "group", + label: "Customer Filter" + }, + + CustomerID: { + manifestpath: "/sap.card/configuration/parameters/CustomerID/value", + type: "string", + label: "Customer ID", + values: { + data: { + request: { + url: "{{destinations.northwind}}/Customers", + parameters: { + "$select": "CustomerID,CompanyName" + } + }, + path: "/value" + }, + item: { + key: "{CustomerID}", + text: "{CompanyName}" + } + } + } + } + }, + preview: { + modes: "None" + } + }); + }; +}); + +``` + +## 6. Analytical Cards Coding Guidelines +- **ALWAYS** set `sap.card/content/chartType` property. +- **ALWAYS** adjust `sap.card/content/measures`, `sap.card/content/dimensions` and `sap.card/content/feeds` to match the `sap.card/content/chartType` property and data structure. This is critical for proper data display. +- **ALWAYS** use `sap.card/content/chartProperties` to adjust labels, colors, the legend, and other chart aspects. +- **ALWAYS** define each feed with its type (Dimension or Measure), its unique identifier (uid), and the associated values using defined measures and dimensions. Example: +```json +"feeds": [ + { + "type": "Dimension", + "uid": "color", + "values": [ + "Store Name" + ] + }, + { + "type": "Measure", + "uid": "size", + "values": [ + "Revenue" + ] + } +] +``` +- **ALWAYS** ensure the `uid` in `feeds` exactly matches the UID required for the selected chartType (e.g., color, size, dataFrame). + +### 6.1 Comprehensive List of All Chart Types, UIDs and Examples + +1. donut/pie + * UIDs: size, color, dataFrame + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueDataField}" + } + ], + "dimensions": [ + { + "name": "Product Category", + "value": "{productCategoryField}" + } + ], + "feeds": [ + { + "type": "Measure", + "uid": "size", + "values": ["Revenue"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Product Category"] + } + ] + } + ``` + +2. heatmap + * UIDs: categoryAxis, categoryAxis2, color + * Example: + ```json + { + "measures": [ + { + "name": "Temperature", + "value": "{temperatureField}" + } + ], + "dimensions": [ + { + "name": "Location", + "value": "{locationField}" + }, + { + "name": "Product", + "value": "{productField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Location"] + }, + { + "type": "Dimension", + "uid": "categoryAxis2", + "values": ["Product"] + }, + { + "type": "Measure", + "uid": "color", + "values": ["Temperature"] + } + ] + } + ``` + +3. treemap + * UIDs: title, color, weight + * Example: + ```json + { + "measures": [ + { + "name": "Profit", + "value": "{profitField}" + }, + { + "name": "Budget", + "value": "{budgetField}" + } + ], + "dimensions": [ + { + "name": "Department", + "value": "{departmentField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "title", + "values": ["Department"] + }, + { + "type": "Measure", + "uid": "color", + "values": ["Profit"] + }, + { + "type": "Measure", + "uid": "weight", + "values": ["Budget"] + } + ] + } + ``` + +4. bar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + } + ] + } + ``` + +5. dual_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Expenses", + "value": "{expensesField}" + } + ], + "dimensions": [ + { + "name": "Quarter", + "value": "{quarterField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Quarter"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Expenses"] + } + ] + } + ``` + +6. column + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + } + ] + } + ``` + +7. timeseries_column + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Traffic", + "value": "{trafficField}" + } + ], + "dimensions": [ + { + "name": "Date", + "value": "{dateField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Date"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Traffic"] + } + ] + } + ``` + +8. dual_column + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Costs", + "value": "{costsField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Costs"] + } + ] + } + ``` + +9. stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + } + ] + } + ``` + +10. stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Market Share", + "value": "{marketShareField}" + } + ], + "dimensions": [ + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Market Share"] + } + ] + } + ``` + +11. timeseries_stacked_column + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Investment", + "value": "{investmentField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Investment"] + } + ] + } + ``` + +12. 100_stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Costs", + "value": "{costsField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Costs"] + } + ] + } + ``` + +13. 100_stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Market Share", + "value": "{marketShareField}" + } + ], + "dimensions": [ + { + "name": "Product", + "value": "{productField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Product"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Market Share"] + } + ] + } + ``` + +14. timeseries_100_stacked_column + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Investment", + "value": "{investmentField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Investment"] + } + ] + } + ``` + +15. dual_stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Profit", + "value": "{profitField}" + } + ], + "dimensions": [ + { + "name": "Brand", + "value": "{brandField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Brand"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Profit"] + } + ] + } + ``` + +16. dual_stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Growth", + "value": "{growthField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Growth"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Revenue"] + } + ] + } + ``` + +17. 100_dual_stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + }, + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Growth"] + } + ] + } + ``` + +18. 100_dual_stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + }, + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Growth"] + } + ] + } + ``` + +19. line + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Price", + "value": "{priceField}" + } + ], + "dimensions": [ + { + "name": "Time", + "value": "{timeField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Price"] + } + ] + } + ``` + +20. dual_line + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Price", + "value": "{priceField}" + }, + { + "name": "Volume", + "value": "{volumeField}" + } + ], + "dimensions": [ + { + "name": "Time", + "value": "{timeField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Price"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Volume"] + } + ] + } + ``` + +21. timeseries_line + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Temperature", + "value": "{temperatureField}" + } + ], + "dimensions": [ + { + "name": "Date", + "value": "{dateField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Date"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Temperature"] + } + ] + } + ``` + +22. bubble + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * Example: + ```json + { + "measures": [ + { + "name": "Expansion", + "value": "{expansionField}" + }, + { + "name": "Size", + "value": "{sizeField}" + } + ], + "dimensions": [ + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Measure", + "uid": "bubbleWidth", + "values": ["Size"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expansion"] + } + ] + } + ``` + +23. time_bubble + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * Example: + ```json + { + "measures": [ + { + "name": "Expansion", + "value": "{expansionField}" + }, + { + "name": "Size", + "value": "{sizeField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}" + }, + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "bubbleWidth", + "values": ["Size"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Sector"] + } + ] + } + ``` + +24. timeseries_bubble + * UIDs: color, shape, valueAxis, timeAxis, bubbleWidth + * Example: + ```json + { + "measures": [ + { + "name": "Size", + "value": "{sizeField}" + }, + { + "name": "Performance", + "value": "{performanceField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + }, + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "bubbleWidth", + "values": ["Size"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Performance"] + } + ] + } + ``` + +25. scatter + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Efficiency", + "value": "{efficiencyField}" + }, + { + "name": "Cost", + "value": "{costField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Efficiency"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Cost"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Region"] + } + ] + } + ``` + +26. timeseries_scatter + * UIDs: color, shape, valueAxis, timeAxis + * Example: + ```json + { + "measures": [ + { + "name": "Performance", + "value": "{performanceField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Performance"] + } + ] + } + ``` + +27. area + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Score", + "value": "{scoreField}" + } + ], + "dimensions": [ + { + "name": "Competency", + "value": "{competencyField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Competency"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Score"] + } + ] + } + ``` + +28. radar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Proficiency Level", + "value": "{proficiencyField}" + } + ], + "dimensions": [ + { + "name": "Skill", + "value": "{skillField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Skill"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Proficiency Level"] + } + ] + } + ``` + +29. vertical_bullet + * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues + * Example: + ```json + { + "measures": [ + { + "name": "Achievement", + "value": "{achievementField}" + } + ], + "dimensions": [ + { + "name": "Target", + "value": "{targetField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Target"] + }, + { + "type": "Measure", + "uid": "actualValues", + "values": ["Achievement"] + } + ] + } + ``` + +30. bullet + * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues + * Example: + ```json + { + "measures": [ + { + "name": "Achievement", + "value": "{achievementField}" + } + ], + "dimensions": [ + { + "name": "Target", + "value": "{targetField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Target"] + }, + { + "type": "Measure", + "uid": "actualValues", + "values": ["Achievement"] + } + ] + } + ``` + +31. timeseries_bullet + * UIDs: timeAxis, color, actualValues, additionalValues, targetValues + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + } + ], + "dimensions": [ + { + "name": "Date", + "value": "{dateField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Date"] + }, + { + "type": "Measure", + "uid": "actualValues", + "values": ["Sales"] + } + ] + } + ``` + +32. waterfall + * UIDs: categoryAxis, waterfallType, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Change", + "value": "{changeField}" + } + ], + "dimensions": [ + { + "name": "Phase", + "value": "{phaseField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Phase"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Change"] + } + ] + } + ``` + +33. timeseries_waterfall + * UIDs: timeAxis, valueAxis, color + * Example: + ```json + { + "measures": [ + { + "name": "Financial Change", + "value": "{financialChangeField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Financial Change"] + } + ] + } + ``` + +34. horizontal_waterfall + * UIDs: categoryAxis, waterfallType, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Milestone", + "value": "{milestoneField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Milestone"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Growth"] + } + ] + } + ``` + +35. combination + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Expense", + "value": "{expenseField}" + } + ], + "dimensions": [ + { + "name": "Period", + "value": "{periodField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Period"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expense"] + } + ] + } + ``` + +36. stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Category", + "value": "{categoryField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Category"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + } + ] + } + ``` + +37. horizontal_stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Product", + "value": "{productField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Product"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Growth"] + } + ] + } + ``` + +38. dual_stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Costs", + "value": "{costsField}" + } + ], + "dimensions": [ + { + "name": "Time Period", + "value": "{timePeriodField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time Period"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Costs"] + } + ] + } + ``` + +39. dual_horizontal_stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + }, + { + "name": "Returns", + "value": "{returnsField}" + } + ], + "dimensions": [ + { + "name": "Brand", + "value": "{brandField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Brand"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Returns"] + } + ] + } + ``` + +40. dual_horizontal_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Engagement", + "value": "{engagementField}" + }, + { + "name": "Spend", + "value": "{spendField}" + } + ], + "dimensions": [ + { + "name": "Campaign", + "value": "{campaignField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Campaign"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Engagement"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Spend"] + } + ] + } + ``` + +41. dual_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales Revenue", + "value": "{salesRevenueField}" + }, + { + "name": "Operating Cost", + "value": "{operatingCostField}" + } + ], + "dimensions": [ + { + "name": "Time Frame", + "value": "{timeFrameField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time Frame"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Operating Cost"] + } + ] + } + ``` + +42. timeseries_combination + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Earnings", + "value": "{earningsField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Earnings"] + } + ] + } + ``` + +43. dual_timeseries_combination + * UIDs: timeAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Cost", + "value": "{costField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Cost"] + } + ] + } + ``` + +44. timeseries_stacked_combination + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Performance", + "value": "{performanceField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Performance"] + } + ] + } + ``` From e2257370856a8042642956515869f425117a9d69 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Mon, 18 May 2026 09:52:42 +0300 Subject: [PATCH 2/8] docs: Correct samples for bubble and combination charts --- plugins/ui5/skills/integration-cards/SKILL.md | 77 +++++++++++++++---- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/plugins/ui5/skills/integration-cards/SKILL.md b/plugins/ui5/skills/integration-cards/SKILL.md index a5e79c8..565060a 100644 --- a/plugins/ui5/skills/integration-cards/SKILL.md +++ b/plugins/ui5/skills/integration-cards/SKILL.md @@ -1107,6 +1107,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 22. bubble * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * Note: Requires at least 3 measures (for valueAxis, valueAxis2, and bubbleWidth) * Example: ```json { @@ -1115,6 +1116,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { "name": "Expansion", "value": "{expansionField}" }, + { + "name": "Cost", + "value": "{costField}" + }, { "name": "Size", "value": "{sizeField}" @@ -1127,6 +1132,16 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { } ], "feeds": [ + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expansion"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Cost"] + }, { "type": "Measure", "uid": "bubbleWidth", @@ -1136,18 +1151,14 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { "type": "Dimension", "uid": "color", "values": ["Sector"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Expansion"] } ] } ``` 23. time_bubble - * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth, timeAxis + * Note: Requires timeAxis dimension, at least 2 measures (for valueAxis and bubbleWidth), and a color dimension * Example: ```json { @@ -1156,6 +1167,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { "name": "Expansion", "value": "{expansionField}" }, + { + "name": "Growth", + "value": "{growthField}" + }, { "name": "Size", "value": "{sizeField}" @@ -1177,6 +1192,16 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { "uid": "timeAxis", "values": ["Year"] }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expansion"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Growth"] + }, { "type": "Measure", "uid": "bubbleWidth", @@ -1193,6 +1218,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 24. timeseries_bubble * UIDs: color, shape, valueAxis, timeAxis, bubbleWidth + * Note: Requires timeAxis dimension with dataType "date", bubbleWidth measure, and valueAxis measure * Example: ```json { @@ -1244,6 +1270,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 25. scatter * UIDs: dataFrame, color, shape, valueAxis, valueAxis2 + * Note: Requires 2 measures for valueAxis and valueAxis2 * Example: ```json { @@ -1576,6 +1603,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 35. combination * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1583,6 +1611,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "name": "Expense", "value": "{expenseField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1600,7 +1632,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "type": "Measure", "uid": "valueAxis", - "values": ["Expense"] + "values": ["Expense", "Revenue"] } ] } @@ -1608,6 +1640,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 36. stacked_combination * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1615,6 +1648,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "name": "Revenue", "value": "{revenueField}" + }, + { + "name": "Sales", + "value": "{salesField}" } ], "dimensions": [ @@ -1632,7 +1669,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "type": "Measure", "uid": "valueAxis", - "values": ["Revenue"] + "values": ["Revenue", "Sales"] } ] } @@ -1640,6 +1677,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 37. horizontal_stacked_combination * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1647,6 +1685,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "name": "Growth", "value": "{growthField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1664,7 +1706,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "type": "Measure", "uid": "valueAxis", - "values": ["Growth"] + "values": ["Growth", "Revenue"] } ] } @@ -1836,6 +1878,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 42. timeseries_combination * UIDs: timeAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1843,6 +1886,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "name": "Earnings", "value": "{earningsField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1861,7 +1908,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "type": "Measure", "uid": "valueAxis", - "values": ["Earnings"] + "values": ["Earnings", "Revenue"] } ] } @@ -1911,6 +1958,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { 44. timeseries_stacked_combination * UIDs: timeAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1918,6 +1966,10 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "name": "Performance", "value": "{performanceField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1936,8 +1988,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { { "type": "Measure", "uid": "valueAxis", - "values": ["Performance"] + "values": ["Performance", "Revenue"] } ] - } - ``` + } \ No newline at end of file From d6677fe93532bac64243f483fb94e230b76e2ca0 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Mon, 18 May 2026 13:22:18 +0300 Subject: [PATCH 3/8] refactor(ui5): Split integration cards skill into reference files --- plugins/ui5/skills/integration-cards/SKILL.md | 1883 +---------------- .../references/analytical_chart_types.md | 1599 ++++++++++++++ .../configuration_editor_example.md | 233 ++ 3 files changed, 1837 insertions(+), 1878 deletions(-) create mode 100644 plugins/ui5/skills/integration-cards/references/analytical_chart_types.md create mode 100644 plugins/ui5/skills/integration-cards/references/configuration_editor_example.md diff --git a/plugins/ui5/skills/integration-cards/SKILL.md b/plugins/ui5/skills/integration-cards/SKILL.md index 565060a..ceffc78 100644 --- a/plugins/ui5/skills/integration-cards/SKILL.md +++ b/plugins/ui5/skills/integration-cards/SKILL.md @@ -6,6 +6,7 @@ description: Guidelines and best practices for developing UI Integration Cards ( # UI Integration Cards Development Guidelines > *This document outlines the fundamental rules and best practices an AI agent must follow when developing or modifying Integration Cards. Adherence to these guidelines is critical for creating modern, maintainable, and performant UI Integration Cards.* + ## 1. Coding Guidelines - **ALWAYS** strive to create declarative Integration Card, such as "Calendar", "List", "Table", "Timeline", "Object" or "Analytical". - create an Integration Card Extension only in exceptional cases. @@ -46,6 +47,7 @@ description: Guidelines and best practices for developing UI Integration Cards ( ### 1.4 Configuration Editor - **ALWAYS** follow [5. Configuration Editor](#5-configuration-editor) guidelines when creating or modifying Configuration Editors for Integration Cards. +- **ALWAYS** load [references/configuration_editor_example.md](references/configuration_editor_example.md) whenever a `dt/Configuration.js` file is present in the project, is being created, or is being modified — even if the user did not explicitly mention the Configuration Editor. ## 2. Validation - **ALWAYS** ensure that `manifest.json` file is valid JSON. @@ -77,7 +79,7 @@ The Configuration Editor is implemented through two key components: The `dt/Configuration.js` file defines the Configuration Editor's structure by specifying: - Form layout and field definitions -- Input controls and visualizations +- Input controls and visualizations - Validation rules and field relationships - Grouping and organization of configuration options @@ -89,237 +91,7 @@ When creating or modifying Integration Cards, follow these guidelines for Config - **ALWAYS** remove fields from the editor when removing them from the `manifest.json`. - **ALWAYS** add fields in the Configuration Editor when adding them to the `manifest.json`. -### 5.1 Example: -`manifest.json` file: -```json -{ - "sap.app": { - "id": "test.editor", - "type": "card", - "title": "Test Card", - "applicationVersion": { - "version": "1.0.0" - } - }, - "sap.ui": { - "technology": "UI5" - }, - "sap.card": { - "type": "List", - "configuration": { - "editor": "./dt/Configuration", - "parameters": { - "cardTitle": { - "value": "Customers" - }, - "icon": { - "value": "sap-icon://account" - }, - "maxItems": { - "value": 3 - }, - "showDescription": { - "value": true - }, - "dateContext": { - "value": "2020-09-02" - }, - "Customers": { - "value": ["ALFKI"] - }, - "northwindDestination": { - "value": "northwind" - } - }, - "destinations": { - "northwind": { - "name": "Northwind_V4", - "defaultUrl": "https://services.odata.org/V4/Northwind/Northwind.svc" - } - } - }, - "data": { - "request": { - "url": "{{destinations.northwind}}/Customers", - "parameters": { - "$select": "CustomerID,CompanyName,ContactName", - "$top": "{parameters>/maxItems/value}" - } - } - }, - "header": { - "title": "{parameters>/cardTitle/value}", - "subtitle": "As of {parameters>/dateContext/value}", - "icon": { - "src": "{parameters>/icon/value}", - "shape": "Circle" - } - }, - "content": { - "data": { - "path": "/value" - }, - "item": { - "title": "{CompanyName}", - "description": "{= ${parameters>/showDescription/value} ? ${ContactName} : '' }" - }, - "maxItems": "{parameters>/maxItems/value}" - } - } -} -``` - -`dt/Configuration.js` file: -```javascript -sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { - "use strict"; - - return function () { - return new Designtime({ - form: { - items: { - - /* ======================= - General - ======================= */ - generalGroup: { - type: "group", - label: "General" - }, - - cardTitle: { - manifestpath: "/sap.card/configuration/parameters/cardTitle/value", - type: "string", - label: "Card Title", - translatable: true, - required: true, - allowDynamicValues: true - }, - - icon: { - manifestpath: "/sap.card/header/icon/src", - type: "string", - label: "Icon", - visualization: { - type: "IconSelect", - settings: { - value: "{currentSettings>value}", - editable: "{currentSettings>editable}" - } - } - }, - - iconShape: { - manifestpath: "/sap.card/header/icon/shape", - type: "string", - label: "Icon Shape", - visualization: { - type: "ShapeSelect", - settings: { - value: "{currentSettings>value}", - editable: "{currentSettings>editable}" - } - }, - cols: 1 - }, - - iconBackground: { - manifestpath: "/sap.card/header/icon/backgroundColor", - type: "string", - label: "Icon Background", - visualization: { - type: "ColorSelect", - settings: { - enumValue: "{currentSettings>value}", - editable: "{currentSettings>editable}" - } - }, - cols: 1 - }, - - /* ======================= - Data & Behavior - ======================= */ - dataGroup: { - type: "group", - label: "Data & Behavior" - }, - - maxItems: { - manifestpath: "/sap.card/configuration/parameters/maxItems/value", - type: "integer", - label: "Maximum Items", - visualization: { - type: "Slider", - settings: { - value: "{currentSettings>value}", - min: 1, - max: 10, - width: "100%", - enabled: "{currentSettings>editable}" - } - } - }, - - showDescription: { - manifestpath: "/sap.card/configuration/parameters/showDescription/value", - type: "boolean", - label: "Show Contact Name", - visualization: { - type: "Switch", - settings: { - state: "{currentSettings>value}", - customTextOn: "Show", - customTextOff: "Hide", - enabled: "{currentSettings>editable}" - } - } - }, - - dateContext: { - manifestpath: "/sap.card/configuration/parameters/dateContext/value", - type: "date", - label: "Date Context" - }, - - /* ======================= - Filtering - ======================= */ - filterGroup: { - type: "group", - label: "Customer Filter" - }, - - CustomerID: { - manifestpath: "/sap.card/configuration/parameters/CustomerID/value", - type: "string", - label: "Customer ID", - values: { - data: { - request: { - url: "{{destinations.northwind}}/Customers", - parameters: { - "$select": "CustomerID,CompanyName" - } - }, - path: "/value" - }, - item: { - key: "{CustomerID}", - text: "{CompanyName}" - } - } - } - } - }, - preview: { - modes: "None" - } - }); - }; -}); - -``` +- **ALWAYS** load [references/configuration_editor_example.md](references/configuration_editor_example.md) before creating or modifying a Configuration Editor (i.e. a `dt/Configuration.js` file). It contains a complete example of a `manifest.json` paired with the corresponding `dt/Configuration.js` file. ## 6. Analytical Cards Coding Guidelines - **ALWAYS** set `sap.card/content/chartType` property. @@ -346,1649 +118,4 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { ``` - **ALWAYS** ensure the `uid` in `feeds` exactly matches the UID required for the selected chartType (e.g., color, size, dataFrame). -### 6.1 Comprehensive List of All Chart Types, UIDs and Examples - -1. donut/pie - * UIDs: size, color, dataFrame - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueDataField}" - } - ], - "dimensions": [ - { - "name": "Product Category", - "value": "{productCategoryField}" - } - ], - "feeds": [ - { - "type": "Measure", - "uid": "size", - "values": ["Revenue"] - }, - { - "type": "Dimension", - "uid": "color", - "values": ["Product Category"] - } - ] - } - ``` - -2. heatmap - * UIDs: categoryAxis, categoryAxis2, color - * Example: - ```json - { - "measures": [ - { - "name": "Temperature", - "value": "{temperatureField}" - } - ], - "dimensions": [ - { - "name": "Location", - "value": "{locationField}" - }, - { - "name": "Product", - "value": "{productField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Location"] - }, - { - "type": "Dimension", - "uid": "categoryAxis2", - "values": ["Product"] - }, - { - "type": "Measure", - "uid": "color", - "values": ["Temperature"] - } - ] - } - ``` - -3. treemap - * UIDs: title, color, weight - * Example: - ```json - { - "measures": [ - { - "name": "Profit", - "value": "{profitField}" - }, - { - "name": "Budget", - "value": "{budgetField}" - } - ], - "dimensions": [ - { - "name": "Department", - "value": "{departmentField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "title", - "values": ["Department"] - }, - { - "type": "Measure", - "uid": "color", - "values": ["Profit"] - }, - { - "type": "Measure", - "uid": "weight", - "values": ["Budget"] - } - ] - } - ``` - -4. bar - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Sales", - "value": "{salesField}" - } - ], - "dimensions": [ - { - "name": "Month", - "value": "{monthField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Month"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Sales"] - } - ] - } - ``` - -5. dual_bar - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - }, - { - "name": "Expenses", - "value": "{expensesField}" - } - ], - "dimensions": [ - { - "name": "Quarter", - "value": "{quarterField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Quarter"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Expenses"] - } - ] - } - ``` - -6. column - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Month", - "value": "{monthField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Month"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - } - ] - } - ``` - -7. timeseries_column - * UIDs: timeAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Traffic", - "value": "{trafficField}" - } - ], - "dimensions": [ - { - "name": "Date", - "value": "{dateField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Date"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Traffic"] - } - ] - } - ``` - -8. dual_column - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - }, - { - "name": "Costs", - "value": "{costsField}" - } - ], - "dimensions": [ - { - "name": "Region", - "value": "{regionField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Region"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Costs"] - } - ] - } - ``` - -9. stacked_bar - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Region", - "value": "{regionField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Region"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - } - ] - } - ``` - -10. stacked_column - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Market Share", - "value": "{marketShareField}" - } - ], - "dimensions": [ - { - "name": "Sector", - "value": "{sectorField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Sector"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Market Share"] - } - ] - } - ``` - -11. timeseries_stacked_column - * UIDs: timeAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Investment", - "value": "{investmentField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Investment"] - } - ] - } - ``` - -12. 100_stacked_bar - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Costs", - "value": "{costsField}" - } - ], - "dimensions": [ - { - "name": "Region", - "value": "{regionField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Region"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Costs"] - } - ] - } - ``` - -13. 100_stacked_column - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Market Share", - "value": "{marketShareField}" - } - ], - "dimensions": [ - { - "name": "Product", - "value": "{productField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Product"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Market Share"] - } - ] - } - ``` - -14. timeseries_100_stacked_column - * UIDs: timeAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Investment", - "value": "{investmentField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Investment"] - } - ] - } - ``` - -15. dual_stacked_bar - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - }, - { - "name": "Profit", - "value": "{profitField}" - } - ], - "dimensions": [ - { - "name": "Brand", - "value": "{brandField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Brand"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Profit"] - } - ] - } - ``` - -16. dual_stacked_column - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Growth", - "value": "{growthField}" - }, - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Sector", - "value": "{sectorField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Sector"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Growth"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Revenue"] - } - ] - } - ``` - -17. 100_dual_stacked_bar - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Sales", - "value": "{salesField}" - }, - { - "name": "Growth", - "value": "{growthField}" - } - ], - "dimensions": [ - { - "name": "Region", - "value": "{regionField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Region"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Sales"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Growth"] - } - ] - } - ``` - -18. 100_dual_stacked_column - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Sales", - "value": "{salesField}" - }, - { - "name": "Growth", - "value": "{growthField}" - } - ], - "dimensions": [ - { - "name": "Region", - "value": "{regionField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Region"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Sales"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Growth"] - } - ] - } - ``` - -19. line - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Price", - "value": "{priceField}" - } - ], - "dimensions": [ - { - "name": "Time", - "value": "{timeField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Time"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Price"] - } - ] - } - ``` - -20. dual_line - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Price", - "value": "{priceField}" - }, - { - "name": "Volume", - "value": "{volumeField}" - } - ], - "dimensions": [ - { - "name": "Time", - "value": "{timeField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Time"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Price"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Volume"] - } - ] - } - ``` - -21. timeseries_line - * UIDs: timeAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Temperature", - "value": "{temperatureField}" - } - ], - "dimensions": [ - { - "name": "Date", - "value": "{dateField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Date"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Temperature"] - } - ] - } - ``` - -22. bubble - * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth - * Note: Requires at least 3 measures (for valueAxis, valueAxis2, and bubbleWidth) - * Example: - ```json - { - "measures": [ - { - "name": "Expansion", - "value": "{expansionField}" - }, - { - "name": "Cost", - "value": "{costField}" - }, - { - "name": "Size", - "value": "{sizeField}" - } - ], - "dimensions": [ - { - "name": "Sector", - "value": "{sectorField}" - } - ], - "feeds": [ - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Expansion"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Cost"] - }, - { - "type": "Measure", - "uid": "bubbleWidth", - "values": ["Size"] - }, - { - "type": "Dimension", - "uid": "color", - "values": ["Sector"] - } - ] - } - ``` - -23. time_bubble - * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth, timeAxis - * Note: Requires timeAxis dimension, at least 2 measures (for valueAxis and bubbleWidth), and a color dimension - * Example: - ```json - { - "measures": [ - { - "name": "Expansion", - "value": "{expansionField}" - }, - { - "name": "Growth", - "value": "{growthField}" - }, - { - "name": "Size", - "value": "{sizeField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}" - }, - { - "name": "Sector", - "value": "{sectorField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Expansion"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Growth"] - }, - { - "type": "Measure", - "uid": "bubbleWidth", - "values": ["Size"] - }, - { - "type": "Dimension", - "uid": "color", - "values": ["Sector"] - } - ] - } - ``` - -24. timeseries_bubble - * UIDs: color, shape, valueAxis, timeAxis, bubbleWidth - * Note: Requires timeAxis dimension with dataType "date", bubbleWidth measure, and valueAxis measure - * Example: - ```json - { - "measures": [ - { - "name": "Size", - "value": "{sizeField}" - }, - { - "name": "Performance", - "value": "{performanceField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}", - "dataType": "date" - }, - { - "name": "Sector", - "value": "{sectorField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "bubbleWidth", - "values": ["Size"] - }, - { - "type": "Dimension", - "uid": "color", - "values": ["Sector"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Performance"] - } - ] - } - ``` - -25. scatter - * UIDs: dataFrame, color, shape, valueAxis, valueAxis2 - * Note: Requires 2 measures for valueAxis and valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Efficiency", - "value": "{efficiencyField}" - }, - { - "name": "Cost", - "value": "{costField}" - } - ], - "dimensions": [ - { - "name": "Region", - "value": "{regionField}" - } - ], - "feeds": [ - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Efficiency"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Cost"] - }, - { - "type": "Dimension", - "uid": "color", - "values": ["Region"] - } - ] - } - ``` - -26. timeseries_scatter - * UIDs: color, shape, valueAxis, timeAxis - * Example: - ```json - { - "measures": [ - { - "name": "Performance", - "value": "{performanceField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Performance"] - } - ] - } - ``` - -27. area - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Score", - "value": "{scoreField}" - } - ], - "dimensions": [ - { - "name": "Competency", - "value": "{competencyField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Competency"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Score"] - } - ] - } - ``` - -28. radar - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Proficiency Level", - "value": "{proficiencyField}" - } - ], - "dimensions": [ - { - "name": "Skill", - "value": "{skillField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Skill"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Proficiency Level"] - } - ] - } - ``` - -29. vertical_bullet - * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues - * Example: - ```json - { - "measures": [ - { - "name": "Achievement", - "value": "{achievementField}" - } - ], - "dimensions": [ - { - "name": "Target", - "value": "{targetField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Target"] - }, - { - "type": "Measure", - "uid": "actualValues", - "values": ["Achievement"] - } - ] - } - ``` - -30. bullet - * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues - * Example: - ```json - { - "measures": [ - { - "name": "Achievement", - "value": "{achievementField}" - } - ], - "dimensions": [ - { - "name": "Target", - "value": "{targetField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Target"] - }, - { - "type": "Measure", - "uid": "actualValues", - "values": ["Achievement"] - } - ] - } - ``` - -31. timeseries_bullet - * UIDs: timeAxis, color, actualValues, additionalValues, targetValues - * Example: - ```json - { - "measures": [ - { - "name": "Sales", - "value": "{salesField}" - } - ], - "dimensions": [ - { - "name": "Date", - "value": "{dateField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Date"] - }, - { - "type": "Measure", - "uid": "actualValues", - "values": ["Sales"] - } - ] - } - ``` - -32. waterfall - * UIDs: categoryAxis, waterfallType, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Change", - "value": "{changeField}" - } - ], - "dimensions": [ - { - "name": "Phase", - "value": "{phaseField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Phase"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Change"] - } - ] - } - ``` - -33. timeseries_waterfall - * UIDs: timeAxis, valueAxis, color - * Example: - ```json - { - "measures": [ - { - "name": "Financial Change", - "value": "{financialChangeField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Financial Change"] - } - ] - } - ``` - -34. horizontal_waterfall - * UIDs: categoryAxis, waterfallType, valueAxis - * Example: - ```json - { - "measures": [ - { - "name": "Growth", - "value": "{growthField}" - } - ], - "dimensions": [ - { - "name": "Milestone", - "value": "{milestoneField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Milestone"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Growth"] - } - ] - } - ``` - -35. combination - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Note: Requires at least 2 measures in the valueAxis feed for proper rendering - * Example: - ```json - { - "measures": [ - { - "name": "Expense", - "value": "{expenseField}" - }, - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Period", - "value": "{periodField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Period"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Expense", "Revenue"] - } - ] - } - ``` - -36. stacked_combination - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Note: Requires at least 2 measures in the valueAxis feed for proper rendering - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - }, - { - "name": "Sales", - "value": "{salesField}" - } - ], - "dimensions": [ - { - "name": "Category", - "value": "{categoryField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Category"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue", "Sales"] - } - ] - } - ``` - -37. horizontal_stacked_combination - * UIDs: dataFrame, categoryAxis, color, valueAxis - * Note: Requires at least 2 measures in the valueAxis feed for proper rendering - * Example: - ```json - { - "measures": [ - { - "name": "Growth", - "value": "{growthField}" - }, - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Product", - "value": "{productField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Product"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Growth", "Revenue"] - } - ] - } - ``` - -38. dual_stacked_combination - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - }, - { - "name": "Costs", - "value": "{costsField}" - } - ], - "dimensions": [ - { - "name": "Time Period", - "value": "{timePeriodField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Time Period"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Costs"] - } - ] - } - ``` - -39. dual_horizontal_stacked_combination - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Sales", - "value": "{salesField}" - }, - { - "name": "Returns", - "value": "{returnsField}" - } - ], - "dimensions": [ - { - "name": "Brand", - "value": "{brandField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Brand"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Sales"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Returns"] - } - ] - } - ``` - -40. dual_horizontal_combination - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Engagement", - "value": "{engagementField}" - }, - { - "name": "Spend", - "value": "{spendField}" - } - ], - "dimensions": [ - { - "name": "Campaign", - "value": "{campaignField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Campaign"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Engagement"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Spend"] - } - ] - } - ``` - -41. dual_combination - * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Sales Revenue", - "value": "{salesRevenueField}" - }, - { - "name": "Operating Cost", - "value": "{operatingCostField}" - } - ], - "dimensions": [ - { - "name": "Time Frame", - "value": "{timeFrameField}" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "categoryAxis", - "values": ["Time Frame"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Sales Revenue"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Operating Cost"] - } - ] - } - ``` - -42. timeseries_combination - * UIDs: timeAxis, color, valueAxis - * Note: Requires at least 2 measures in the valueAxis feed for proper rendering - * Example: - ```json - { - "measures": [ - { - "name": "Earnings", - "value": "{earningsField}" - }, - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Month", - "value": "{monthField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Month"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Earnings", "Revenue"] - } - ] - } - ``` - -43. dual_timeseries_combination - * UIDs: timeAxis, color, valueAxis, valueAxis2 - * Example: - ```json - { - "measures": [ - { - "name": "Revenue", - "value": "{revenueField}" - }, - { - "name": "Cost", - "value": "{costField}" - } - ], - "dimensions": [ - { - "name": "Month", - "value": "{monthField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Month"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Revenue"] - }, - { - "type": "Measure", - "uid": "valueAxis2", - "values": ["Cost"] - } - ] - } - ``` - -44. timeseries_stacked_combination - * UIDs: timeAxis, color, valueAxis - * Note: Requires at least 2 measures in the valueAxis feed for proper rendering - * Example: - ```json - { - "measures": [ - { - "name": "Performance", - "value": "{performanceField}" - }, - { - "name": "Revenue", - "value": "{revenueField}" - } - ], - "dimensions": [ - { - "name": "Year", - "value": "{yearField}", - "dataType": "date" - } - ], - "feeds": [ - { - "type": "Dimension", - "uid": "timeAxis", - "values": ["Year"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Performance", "Revenue"] - } - ] - } \ No newline at end of file +- **ALWAYS** load [references/analytical_chart_types.md](references/analytical_chart_types.md) before creating or modifying an Analytical card. It contains the comprehensive list of all supported chart types, their required UIDs, and example configurations. diff --git a/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md b/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md new file mode 100644 index 0000000..372ef37 --- /dev/null +++ b/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md @@ -0,0 +1,1599 @@ +# Analytical Cards - Chart Types Reference + +Comprehensive list of all supported chart types for Analytical Integration Cards, with their required UIDs and example configurations. + +For each chart type, the `feeds` array must use the listed UIDs to bind the corresponding measures and dimensions. + +1. donut/pie + * UIDs: size, color, dataFrame + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueDataField}" + } + ], + "dimensions": [ + { + "name": "Product Category", + "value": "{productCategoryField}" + } + ], + "feeds": [ + { + "type": "Measure", + "uid": "size", + "values": ["Revenue"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Product Category"] + } + ] + } + ``` + +2. heatmap + * UIDs: categoryAxis, categoryAxis2, color + * Example: + ```json + { + "measures": [ + { + "name": "Temperature", + "value": "{temperatureField}" + } + ], + "dimensions": [ + { + "name": "Location", + "value": "{locationField}" + }, + { + "name": "Product", + "value": "{productField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Location"] + }, + { + "type": "Dimension", + "uid": "categoryAxis2", + "values": ["Product"] + }, + { + "type": "Measure", + "uid": "color", + "values": ["Temperature"] + } + ] + } + ``` + +3. treemap + * UIDs: title, color, weight + * Example: + ```json + { + "measures": [ + { + "name": "Profit", + "value": "{profitField}" + }, + { + "name": "Budget", + "value": "{budgetField}" + } + ], + "dimensions": [ + { + "name": "Department", + "value": "{departmentField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "title", + "values": ["Department"] + }, + { + "type": "Measure", + "uid": "color", + "values": ["Profit"] + }, + { + "type": "Measure", + "uid": "weight", + "values": ["Budget"] + } + ] + } + ``` + +4. bar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + } + ] + } + ``` + +5. dual_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Expenses", + "value": "{expensesField}" + } + ], + "dimensions": [ + { + "name": "Quarter", + "value": "{quarterField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Quarter"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Expenses"] + } + ] + } + ``` + +6. column + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + } + ] + } + ``` + +7. timeseries_column + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Traffic", + "value": "{trafficField}" + } + ], + "dimensions": [ + { + "name": "Date", + "value": "{dateField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Date"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Traffic"] + } + ] + } + ``` + +8. dual_column + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Costs", + "value": "{costsField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Costs"] + } + ] + } + ``` + +9. stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + } + ] + } + ``` + +10. stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Market Share", + "value": "{marketShareField}" + } + ], + "dimensions": [ + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Market Share"] + } + ] + } + ``` + +11. timeseries_stacked_column + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Investment", + "value": "{investmentField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Investment"] + } + ] + } + ``` + +12. 100_stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Costs", + "value": "{costsField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Costs"] + } + ] + } + ``` + +13. 100_stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Market Share", + "value": "{marketShareField}" + } + ], + "dimensions": [ + { + "name": "Product", + "value": "{productField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Product"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Market Share"] + } + ] + } + ``` + +14. timeseries_100_stacked_column + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Investment", + "value": "{investmentField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Investment"] + } + ] + } + ``` + +15. dual_stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Profit", + "value": "{profitField}" + } + ], + "dimensions": [ + { + "name": "Brand", + "value": "{brandField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Brand"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Profit"] + } + ] + } + ``` + +16. dual_stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Growth", + "value": "{growthField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Growth"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Revenue"] + } + ] + } + ``` + +17. 100_dual_stacked_bar + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + }, + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Growth"] + } + ] + } + ``` + +18. 100_dual_stacked_column + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + }, + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Region"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Growth"] + } + ] + } + ``` + +19. line + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Price", + "value": "{priceField}" + } + ], + "dimensions": [ + { + "name": "Time", + "value": "{timeField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Price"] + } + ] + } + ``` + +20. dual_line + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Price", + "value": "{priceField}" + }, + { + "name": "Volume", + "value": "{volumeField}" + } + ], + "dimensions": [ + { + "name": "Time", + "value": "{timeField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Price"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Volume"] + } + ] + } + ``` + +21. timeseries_line + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Temperature", + "value": "{temperatureField}" + } + ], + "dimensions": [ + { + "name": "Date", + "value": "{dateField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Date"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Temperature"] + } + ] + } + ``` + +22. bubble + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * Example: + ```json + { + "measures": [ + { + "name": "Expansion", + "value": "{expansionField}" + }, + { + "name": "Size", + "value": "{sizeField}" + } + ], + "dimensions": [ + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Measure", + "uid": "bubbleWidth", + "values": ["Size"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expansion"] + } + ] + } + ``` + +23. time_bubble + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * Example: + ```json + { + "measures": [ + { + "name": "Expansion", + "value": "{expansionField}" + }, + { + "name": "Size", + "value": "{sizeField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}" + }, + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "bubbleWidth", + "values": ["Size"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Sector"] + } + ] + } + ``` + +24. timeseries_bubble + * UIDs: color, shape, valueAxis, timeAxis, bubbleWidth + * Example: + ```json + { + "measures": [ + { + "name": "Size", + "value": "{sizeField}" + }, + { + "name": "Performance", + "value": "{performanceField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + }, + { + "name": "Sector", + "value": "{sectorField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "bubbleWidth", + "values": ["Size"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Sector"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Performance"] + } + ] + } + ``` + +25. scatter + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Efficiency", + "value": "{efficiencyField}" + }, + { + "name": "Cost", + "value": "{costField}" + } + ], + "dimensions": [ + { + "name": "Region", + "value": "{regionField}" + } + ], + "feeds": [ + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Efficiency"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Cost"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Region"] + } + ] + } + ``` + +26. timeseries_scatter + * UIDs: color, shape, valueAxis, timeAxis + * Example: + ```json + { + "measures": [ + { + "name": "Performance", + "value": "{performanceField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Performance"] + } + ] + } + ``` + +27. area + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Score", + "value": "{scoreField}" + } + ], + "dimensions": [ + { + "name": "Competency", + "value": "{competencyField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Competency"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Score"] + } + ] + } + ``` + +28. radar + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Proficiency Level", + "value": "{proficiencyField}" + } + ], + "dimensions": [ + { + "name": "Skill", + "value": "{skillField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Skill"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Proficiency Level"] + } + ] + } + ``` + +29. vertical_bullet + * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues + * Example: + ```json + { + "measures": [ + { + "name": "Achievement", + "value": "{achievementField}" + } + ], + "dimensions": [ + { + "name": "Target", + "value": "{targetField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Target"] + }, + { + "type": "Measure", + "uid": "actualValues", + "values": ["Achievement"] + } + ] + } + ``` + +30. bullet + * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues + * Example: + ```json + { + "measures": [ + { + "name": "Achievement", + "value": "{achievementField}" + } + ], + "dimensions": [ + { + "name": "Target", + "value": "{targetField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Target"] + }, + { + "type": "Measure", + "uid": "actualValues", + "values": ["Achievement"] + } + ] + } + ``` + +31. timeseries_bullet + * UIDs: timeAxis, color, actualValues, additionalValues, targetValues + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + } + ], + "dimensions": [ + { + "name": "Date", + "value": "{dateField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Date"] + }, + { + "type": "Measure", + "uid": "actualValues", + "values": ["Sales"] + } + ] + } + ``` + +32. waterfall + * UIDs: categoryAxis, waterfallType, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Change", + "value": "{changeField}" + } + ], + "dimensions": [ + { + "name": "Phase", + "value": "{phaseField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Phase"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Change"] + } + ] + } + ``` + +33. timeseries_waterfall + * UIDs: timeAxis, valueAxis, color + * Example: + ```json + { + "measures": [ + { + "name": "Financial Change", + "value": "{financialChangeField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Financial Change"] + } + ] + } + ``` + +34. horizontal_waterfall + * UIDs: categoryAxis, waterfallType, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Milestone", + "value": "{milestoneField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Milestone"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Growth"] + } + ] + } + ``` + +35. combination + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Expense", + "value": "{expenseField}" + } + ], + "dimensions": [ + { + "name": "Period", + "value": "{periodField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Period"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expense"] + } + ] + } + ``` + +36. stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + } + ], + "dimensions": [ + { + "name": "Category", + "value": "{categoryField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Category"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + } + ] + } + ``` + +37. horizontal_stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Growth", + "value": "{growthField}" + } + ], + "dimensions": [ + { + "name": "Product", + "value": "{productField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Product"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Growth"] + } + ] + } + ``` + +38. dual_stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Costs", + "value": "{costsField}" + } + ], + "dimensions": [ + { + "name": "Time Period", + "value": "{timePeriodField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time Period"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Costs"] + } + ] + } + ``` + +39. dual_horizontal_stacked_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales", + "value": "{salesField}" + }, + { + "name": "Returns", + "value": "{returnsField}" + } + ], + "dimensions": [ + { + "name": "Brand", + "value": "{brandField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Brand"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Returns"] + } + ] + } + ``` + +40. dual_horizontal_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Engagement", + "value": "{engagementField}" + }, + { + "name": "Spend", + "value": "{spendField}" + } + ], + "dimensions": [ + { + "name": "Campaign", + "value": "{campaignField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Campaign"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Engagement"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Spend"] + } + ] + } + ``` + +41. dual_combination + * UIDs: dataFrame, categoryAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Sales Revenue", + "value": "{salesRevenueField}" + }, + { + "name": "Operating Cost", + "value": "{operatingCostField}" + } + ], + "dimensions": [ + { + "name": "Time Frame", + "value": "{timeFrameField}" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "categoryAxis", + "values": ["Time Frame"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Sales Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Operating Cost"] + } + ] + } + ``` + +42. timeseries_combination + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Earnings", + "value": "{earningsField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Earnings"] + } + ] + } + ``` + +43. dual_timeseries_combination + * UIDs: timeAxis, color, valueAxis, valueAxis2 + * Example: + ```json + { + "measures": [ + { + "name": "Revenue", + "value": "{revenueField}" + }, + { + "name": "Cost", + "value": "{costField}" + } + ], + "dimensions": [ + { + "name": "Month", + "value": "{monthField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Month"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Revenue"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Cost"] + } + ] + } + ``` + +44. timeseries_stacked_combination + * UIDs: timeAxis, color, valueAxis + * Example: + ```json + { + "measures": [ + { + "name": "Performance", + "value": "{performanceField}" + } + ], + "dimensions": [ + { + "name": "Year", + "value": "{yearField}", + "dataType": "date" + } + ], + "feeds": [ + { + "type": "Dimension", + "uid": "timeAxis", + "values": ["Year"] + }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Performance"] + } + ] + } + ``` diff --git a/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md b/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md new file mode 100644 index 0000000..902dab6 --- /dev/null +++ b/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md @@ -0,0 +1,233 @@ +# Configuration Editor Example + +This reference shows a complete pairing of a `manifest.json` and the corresponding `dt/Configuration.js` file for an Integration Card with a Configuration Editor. + +`manifest.json` file: +```json +{ + "sap.app": { + "id": "test.editor", + "type": "card", + "title": "Test Card", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui": { + "technology": "UI5" + }, + "sap.card": { + "type": "List", + "configuration": { + "editor": "./dt/Configuration", + "parameters": { + "cardTitle": { + "value": "Customers" + }, + "icon": { + "value": "sap-icon://account" + }, + "maxItems": { + "value": 3 + }, + "showDescription": { + "value": true + }, + "dateContext": { + "value": "2020-09-02" + }, + "Customers": { + "value": ["ALFKI"] + }, + "northwindDestination": { + "value": "northwind" + } + }, + "destinations": { + "northwind": { + "name": "Northwind_V4", + "defaultUrl": "https://services.odata.org/V4/Northwind/Northwind.svc" + } + } + }, + "data": { + "request": { + "url": "{{destinations.northwind}}/Customers", + "parameters": { + "$select": "CustomerID,CompanyName,ContactName", + "$top": "{parameters>/maxItems/value}" + } + } + }, + "header": { + "title": "{parameters>/cardTitle/value}", + "subtitle": "As of {parameters>/dateContext/value}", + "icon": { + "src": "{parameters>/icon/value}", + "shape": "Circle" + } + }, + "content": { + "data": { + "path": "/value" + }, + "item": { + "title": "{CompanyName}", + "description": "{= ${parameters>/showDescription/value} ? ${ContactName} : '' }" + }, + "maxItems": "{parameters>/maxItems/value}" + } + } +} +``` + +`dt/Configuration.js` file: +```javascript +sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { + "use strict"; + + return function () { + return new Designtime({ + form: { + items: { + + /* ======================= + General + ======================= */ + generalGroup: { + type: "group", + label: "General" + }, + + cardTitle: { + manifestpath: "/sap.card/configuration/parameters/cardTitle/value", + type: "string", + label: "Card Title", + translatable: true, + required: true, + allowDynamicValues: true + }, + + icon: { + manifestpath: "/sap.card/header/icon/src", + type: "string", + label: "Icon", + visualization: { + type: "IconSelect", + settings: { + value: "{currentSettings>value}", + editable: "{currentSettings>editable}" + } + } + }, + + iconShape: { + manifestpath: "/sap.card/header/icon/shape", + type: "string", + label: "Icon Shape", + visualization: { + type: "ShapeSelect", + settings: { + value: "{currentSettings>value}", + editable: "{currentSettings>editable}" + } + }, + cols: 1 + }, + + iconBackground: { + manifestpath: "/sap.card/header/icon/backgroundColor", + type: "string", + label: "Icon Background", + visualization: { + type: "ColorSelect", + settings: { + enumValue: "{currentSettings>value}", + editable: "{currentSettings>editable}" + } + }, + cols: 1 + }, + + /* ======================= + Data & Behavior + ======================= */ + dataGroup: { + type: "group", + label: "Data & Behavior" + }, + + maxItems: { + manifestpath: "/sap.card/configuration/parameters/maxItems/value", + type: "integer", + label: "Maximum Items", + visualization: { + type: "Slider", + settings: { + value: "{currentSettings>value}", + min: 1, + max: 10, + width: "100%", + enabled: "{currentSettings>editable}" + } + } + }, + + showDescription: { + manifestpath: "/sap.card/configuration/parameters/showDescription/value", + type: "boolean", + label: "Show Contact Name", + visualization: { + type: "Switch", + settings: { + state: "{currentSettings>value}", + customTextOn: "Show", + customTextOff: "Hide", + enabled: "{currentSettings>editable}" + } + } + }, + + dateContext: { + manifestpath: "/sap.card/configuration/parameters/dateContext/value", + type: "date", + label: "Date Context" + }, + + /* ======================= + Filtering + ======================= */ + filterGroup: { + type: "group", + label: "Customer Filter" + }, + + CustomerID: { + manifestpath: "/sap.card/configuration/parameters/CustomerID/value", + type: "string", + label: "Customer ID", + values: { + data: { + request: { + url: "{{destinations.northwind}}/Customers", + parameters: { + "$select": "CustomerID,CompanyName" + } + }, + path: "/value" + }, + item: { + key: "{CustomerID}", + text: "{CompanyName}" + } + } + } + } + }, + preview: { + modes: "None" + } + }); + }; +}); +``` From 19fb94c596ed6ab92c52821b7ac7d8b783f9afd5 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 19 May 2026 12:23:56 +0300 Subject: [PATCH 4/8] docs(ui5): Align Customer parameter key in editor sample Editor field referenced parameters/CustomerID/value but the manifest declared "Customers" as an array, so the binding never matched. Use a singular "Customer" string key in both places. --- .../references/configuration_editor_example.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md b/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md index 902dab6..e79c3aa 100644 --- a/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md +++ b/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md @@ -36,8 +36,8 @@ This reference shows a complete pairing of a `manifest.json` and the correspondi "dateContext": { "value": "2020-09-02" }, - "Customers": { - "value": ["ALFKI"] + "Customer": { + "value": "ALFKI" }, "northwindDestination": { "value": "northwind" @@ -202,8 +202,8 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { label: "Customer Filter" }, - CustomerID: { - manifestpath: "/sap.card/configuration/parameters/CustomerID/value", + Customer: { + manifestpath: "/sap.card/configuration/parameters/Customer/value", type: "string", label: "Customer ID", values: { From 68b8fb0e3f25e3e0826d3eece62c63a9d8c3f1d5 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 20 May 2026 14:22:01 +0300 Subject: [PATCH 5/8] docs(ui5): Address review feedback on integration cards skill - Fix analytical chart samples (bubble, time_bubble, stacked variants, bullet, waterfall, combinations) so feeds and measures match each chart type's requirements - Add GitHub samples link to the Card Explorer section - Require asking the user before making all manifest fields editable in the Configuration Editor - Clarify the donut/pie context on the feeds example in SKILL.md --- plugins/ui5/skills/integration-cards/SKILL.md | 4 +- .../references/analytical_chart_types.md | 169 ++++++++++++++++-- 2 files changed, 154 insertions(+), 19 deletions(-) diff --git a/plugins/ui5/skills/integration-cards/SKILL.md b/plugins/ui5/skills/integration-cards/SKILL.md index ceffc78..de400cd 100644 --- a/plugins/ui5/skills/integration-cards/SKILL.md +++ b/plugins/ui5/skills/integration-cards/SKILL.md @@ -58,6 +58,7 @@ description: Guidelines and best practices for developing UI Integration Cards ( ## 3. Card Explorer - The Card Explorer provides detailed documentation for the Integration Cards schema, including descriptions of every property, guidance for integrating cards into hosting environments, configuration editor documentation with examples, and broader best practices. It is available at: https://ui5.sap.com/test-resources/sap/ui/integration/demokit/cardExplorer/webapp/index.html +- The Card Explorer sample sources (manifest.json, data.json, etc.) are available in the openui5 GitHub repository: https://github.com/UI5/openui5/tree/master/src/sap.ui.integration/test/sap/ui/integration/demokit/cardExplorer/webapp/samples ## 4. Preview Instructions - If preview of the card must be shown, **ALWAYS** check the card folder for an existing preview file and any accompanying instructions or scripts, and reuse them if available. @@ -87,6 +88,7 @@ When creating or modifying Integration Cards, follow these guidelines for Config - Assume the role of Administrator persona when designing the Configuration Editor. - **ALWAYS** ensure that the Configuration Editor reflects the current structure and fields of the `manifest.json`. - **ALWAYS** make the existing fields in the `manifest.json` configurable via the editor. For example manifest parameters, title, subtitle, icon of the header, etc. +- **ALWAYS** ask the user if they agree to make all fields editable and what other fields should be added. - **NEVER** add fields to the editor that do not exist in the `manifest.json`. - **ALWAYS** remove fields from the editor when removing them from the `manifest.json`. - **ALWAYS** add fields in the Configuration Editor when adding them to the `manifest.json`. @@ -97,7 +99,7 @@ When creating or modifying Integration Cards, follow these guidelines for Config - **ALWAYS** set `sap.card/content/chartType` property. - **ALWAYS** adjust `sap.card/content/measures`, `sap.card/content/dimensions` and `sap.card/content/feeds` to match the `sap.card/content/chartType` property and data structure. This is critical for proper data display. - **ALWAYS** use `sap.card/content/chartProperties` to adjust labels, colors, the legend, and other chart aspects. -- **ALWAYS** define each feed with its type (Dimension or Measure), its unique identifier (uid), and the associated values using defined measures and dimensions. Example: +- **ALWAYS** define each feed with its type (Dimension or Measure), its unique identifier (uid), and the associated values using defined measures and dimensions. Example (for a donut/pie chart): ```json "feeds": [ { diff --git a/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md b/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md index 372ef37..86e59f3 100644 --- a/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md +++ b/plugins/ui5/skills/integration-cards/references/analytical_chart_types.md @@ -299,6 +299,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 9. stacked_bar * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Stacking requires a second dimension fed to `color`; without it the chart renders as a plain bar * Example: ```json { @@ -312,6 +313,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Region", "value": "{regionField}" + }, + { + "name": "Product", + "value": "{productField}" } ], "feeds": [ @@ -324,6 +329,11 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Measure", "uid": "valueAxis", "values": ["Revenue"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Product"] } ] } @@ -331,6 +341,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 10. stacked_column * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Stacking requires a second dimension fed to `color`; without it the chart renders as a plain column * Example: ```json { @@ -344,6 +355,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Sector", "value": "{sectorField}" + }, + { + "name": "Product", + "value": "{productField}" } ], "feeds": [ @@ -356,6 +371,11 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Measure", "uid": "valueAxis", "values": ["Market Share"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Product"] } ] } @@ -396,6 +416,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 12. 100_stacked_bar * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Stacking requires a second dimension fed to `color`; without it the chart renders as a plain bar * Example: ```json { @@ -409,6 +430,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Region", "value": "{regionField}" + }, + { + "name": "Category", + "value": "{categoryField}" } ], "feeds": [ @@ -421,6 +446,11 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Measure", "uid": "valueAxis", "values": ["Costs"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Category"] } ] } @@ -428,6 +458,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 13. 100_stacked_column * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Stacking requires a second dimension fed to `color`; without it the chart renders as a plain column * Example: ```json { @@ -441,6 +472,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Product", "value": "{productField}" + }, + { + "name": "Region", + "value": "{regionField}" } ], "feeds": [ @@ -453,6 +488,11 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Measure", "uid": "valueAxis", "values": ["Market Share"] + }, + { + "type": "Dimension", + "uid": "color", + "values": ["Region"] } ] } @@ -763,6 +803,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 22. bubble * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * Note: Requires at least 3 measures (for valueAxis, valueAxis2, and bubbleWidth) * Example: ```json { @@ -771,6 +812,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "name": "Expansion", "value": "{expansionField}" }, + { + "name": "Cost", + "value": "{costField}" + }, { "name": "Size", "value": "{sizeField}" @@ -783,6 +828,16 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr } ], "feeds": [ + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expansion"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Cost"] + }, { "type": "Measure", "uid": "bubbleWidth", @@ -792,18 +847,14 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Dimension", "uid": "color", "values": ["Sector"] - }, - { - "type": "Measure", - "uid": "valueAxis", - "values": ["Expansion"] } ] } ``` 23. time_bubble - * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth + * UIDs: dataFrame, color, shape, valueAxis, valueAxis2, bubbleWidth, timeAxis + * Note: Requires timeAxis dimension, at least 2 measures (for valueAxis and bubbleWidth), and a color dimension * Example: ```json { @@ -812,6 +863,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "name": "Expansion", "value": "{expansionField}" }, + { + "name": "Growth", + "value": "{growthField}" + }, { "name": "Size", "value": "{sizeField}" @@ -820,7 +875,8 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "dimensions": [ { "name": "Year", - "value": "{yearField}" + "value": "{yearField}", + "dataType": "date" }, { "name": "Sector", @@ -833,6 +889,16 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "uid": "timeAxis", "values": ["Year"] }, + { + "type": "Measure", + "uid": "valueAxis", + "values": ["Expansion"] + }, + { + "type": "Measure", + "uid": "valueAxis2", + "values": ["Growth"] + }, { "type": "Measure", "uid": "bubbleWidth", @@ -849,6 +915,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 24. timeseries_bubble * UIDs: color, shape, valueAxis, timeAxis, bubbleWidth + * Note: Requires timeAxis dimension with dataType "date", bubbleWidth measure, and valueAxis measure * Example: ```json { @@ -900,6 +967,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 25. scatter * UIDs: dataFrame, color, shape, valueAxis, valueAxis2 + * Note: Requires 2 measures for valueAxis and valueAxis2 * Example: ```json { @@ -1038,6 +1106,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 29. vertical_bullet * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues + * Note: `targetValues` expects a measure (target value), not a dimension * Example: ```json { @@ -1045,24 +1114,33 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Achievement", "value": "{achievementField}" + }, + { + "name": "Target", + "value": "{targetField}" } ], "dimensions": [ { - "name": "Target", - "value": "{targetField}" + "name": "KPI Name", + "value": "{kpiNameField}" } ], "feeds": [ { "type": "Dimension", "uid": "categoryAxis", - "values": ["Target"] + "values": ["KPI Name"] }, { "type": "Measure", "uid": "actualValues", "values": ["Achievement"] + }, + { + "type": "Measure", + "uid": "targetValues", + "values": ["Target"] } ] } @@ -1070,6 +1148,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 30. bullet * UIDs: categoryAxis, color, actualValues, additionalValues, targetValues, forecastValues + * Note: `targetValues` expects a measure (target value), not a dimension * Example: ```json { @@ -1077,24 +1156,33 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Achievement", "value": "{achievementField}" + }, + { + "name": "Target", + "value": "{targetField}" } ], "dimensions": [ { - "name": "Target", - "value": "{targetField}" + "name": "KPI Name", + "value": "{kpiNameField}" } ], "feeds": [ { "type": "Dimension", "uid": "categoryAxis", - "values": ["Target"] + "values": ["KPI Name"] }, { "type": "Measure", "uid": "actualValues", "values": ["Achievement"] + }, + { + "type": "Measure", + "uid": "targetValues", + "values": ["Target"] } ] } @@ -1135,6 +1223,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 32. waterfall * UIDs: categoryAxis, waterfallType, valueAxis + * Note: `waterfallType` is optional but recommended; it distinguishes total bars from running positive/negative changes * Example: ```json { @@ -1148,6 +1237,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Phase", "value": "{phaseField}" + }, + { + "name": "Type", + "value": "{typeField}" } ], "feeds": [ @@ -1160,6 +1253,11 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Measure", "uid": "valueAxis", "values": ["Change"] + }, + { + "type": "Dimension", + "uid": "waterfallType", + "values": ["Type"] } ] } @@ -1200,6 +1298,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 34. horizontal_waterfall * UIDs: categoryAxis, waterfallType, valueAxis + * Note: `waterfallType` is optional but recommended; it distinguishes total bars from running positive/negative changes * Example: ```json { @@ -1213,6 +1312,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Milestone", "value": "{milestoneField}" + }, + { + "name": "Type", + "value": "{typeField}" } ], "feeds": [ @@ -1225,6 +1328,11 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr "type": "Measure", "uid": "valueAxis", "values": ["Growth"] + }, + { + "type": "Dimension", + "uid": "waterfallType", + "values": ["Type"] } ] } @@ -1232,6 +1340,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 35. combination * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1239,6 +1348,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Expense", "value": "{expenseField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1256,7 +1369,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "type": "Measure", "uid": "valueAxis", - "values": ["Expense"] + "values": ["Expense", "Revenue"] } ] } @@ -1264,6 +1377,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 36. stacked_combination * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1271,6 +1385,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Revenue", "value": "{revenueField}" + }, + { + "name": "Sales", + "value": "{salesField}" } ], "dimensions": [ @@ -1288,7 +1406,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "type": "Measure", "uid": "valueAxis", - "values": ["Revenue"] + "values": ["Revenue", "Sales"] } ] } @@ -1296,6 +1414,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 37. horizontal_stacked_combination * UIDs: dataFrame, categoryAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1303,6 +1422,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Growth", "value": "{growthField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1320,7 +1443,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "type": "Measure", "uid": "valueAxis", - "values": ["Growth"] + "values": ["Growth", "Revenue"] } ] } @@ -1492,6 +1615,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 42. timeseries_combination * UIDs: timeAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1499,6 +1623,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Earnings", "value": "{earningsField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1517,7 +1645,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "type": "Measure", "uid": "valueAxis", - "values": ["Earnings"] + "values": ["Earnings", "Revenue"] } ] } @@ -1567,6 +1695,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr 44. timeseries_stacked_combination * UIDs: timeAxis, color, valueAxis + * Note: Requires at least 2 measures in the valueAxis feed for proper rendering * Example: ```json { @@ -1574,6 +1703,10 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "name": "Performance", "value": "{performanceField}" + }, + { + "name": "Revenue", + "value": "{revenueField}" } ], "dimensions": [ @@ -1592,7 +1725,7 @@ For each chart type, the `feeds` array must use the listed UIDs to bind the corr { "type": "Measure", "uid": "valueAxis", - "values": ["Performance"] + "values": ["Performance", "Revenue"] } ] } From e7e246972f06a803e81c4abdc1fa99129124eee1 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 20 May 2026 14:22:01 +0300 Subject: [PATCH 6/8] docs(ui5): Strengthen integration-cards skill auto-load signal Lead the skill description with the same imperative the UI5 MCP server's "Get Integration Cards Guidelines" tool uses, and enumerate the trigger surfaces (manifest.json, Configuration Editor, analytical charts), so Claude prefers loading the skill over calling the MCP tool. --- plugins/ui5/skills/integration-cards/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ui5/skills/integration-cards/SKILL.md b/plugins/ui5/skills/integration-cards/SKILL.md index de400cd..9868987 100644 --- a/plugins/ui5/skills/integration-cards/SKILL.md +++ b/plugins/ui5/skills/integration-cards/SKILL.md @@ -1,6 +1,6 @@ --- name: integration-cards -description: Guidelines and best practices for developing UI Integration Cards (also called UI5 Integration Cards). This skill MUST be loaded before working on any Integration Card related task. +description: MUST be loaded before any UI Integration Cards (also called UI5 Integration Cards) task — creating, modifying, validating, previewing, or reviewing a card, its `manifest.json`, its Configuration Editor (`dt/Configuration.js`), or any analytical chart configuration. Provides the official guidelines, validation rules, supported chart types, and Configuration Editor patterns. --- # UI Integration Cards Development Guidelines From 45c7c6a6c0f1deb792af6708c5c1436fd72385f0 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 20 May 2026 14:13:19 +0300 Subject: [PATCH 7/8] docs(ui5): Fix icon binding contradiction in Configuration Editor example The manifest defines header.icon.src as {parameters>/icon/value}, so the editor should bind to the parameter path instead of the header path. Otherwise the editor writes to a different manifest location than the binding reads from. --- .../references/configuration_editor_example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md b/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md index e79c3aa..57b8994 100644 --- a/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md +++ b/plugins/ui5/skills/integration-cards/references/configuration_editor_example.md @@ -109,7 +109,7 @@ sap.ui.define(["sap/ui/integration/Designtime"], function (Designtime) { }, icon: { - manifestpath: "/sap.card/header/icon/src", + manifestpath: "/sap.card/configuration/parameters/icon/value", type: "string", label: "Icon", visualization: { From c34d265b759b91d2f12901e7e0277a755868bd88 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 20 May 2026 14:13:25 +0300 Subject: [PATCH 8/8] docs(ui5): Restructure integration-cards skill for agent efficiency Reduce word count from ~1058 to ~740 by restructuring prose into compact rules tables. Hoist reference-loading triggers to the top so agents load analytical_chart_types.md and configuration_editor_example.md before working on those areas. Replace section symbols with markdown anchor links, demote the Card Explorer reference to the bottom, and add a "No data to display" symptom callout pointing at the data-placement rule (the most common cause). --- plugins/ui5/skills/integration-cards/SKILL.md | 198 ++++++++---------- 1 file changed, 89 insertions(+), 109 deletions(-) diff --git a/plugins/ui5/skills/integration-cards/SKILL.md b/plugins/ui5/skills/integration-cards/SKILL.md index 9868987..8e60d6c 100644 --- a/plugins/ui5/skills/integration-cards/SKILL.md +++ b/plugins/ui5/skills/integration-cards/SKILL.md @@ -5,119 +5,99 @@ description: MUST be loaded before any UI Integration Cards (also called UI5 Int # UI Integration Cards Development Guidelines -> *This document outlines the fundamental rules and best practices an AI agent must follow when developing or modifying Integration Cards. Adherence to these guidelines is critical for creating modern, maintainable, and performant UI Integration Cards.* - -## 1. Coding Guidelines -- **ALWAYS** strive to create declarative Integration Card, such as "Calendar", "List", "Table", "Timeline", "Object" or "Analytical". - - create an Integration Card Extension only in exceptional cases. -- **ALWAYS** create links using the `actions` property. -- **ALWAYS** refer to parameters using correct syntax - `{parameters>/parameterKey/value}`. -- **ALWAYS** perform validation of the integration card as described in [2. Validation](#2-validation). -- **ALWAYS** show a preview of the generated card following the [4. Preview Instructions](#4-preview-instructions). -- **ALWAYS** generate new declarative integration cards using the `create_integration_card` tool. - -### 1.1 Data -- **NEVER** modify the provided data under any circumstances. -- **ALWAYS** include the service URL directly in the card manifest when one is supplied. -- **ALWAYS** reference destinations by name when available. Configure the destination in the `sap.card/configuration/destinations/` and reuse it with binding syntax like `{{destinations.destinationName}}`. -- **NEVER** replace destination name with its URL. -- **ALWAYS** place data configuration in: `"sap.card"/data/` -- **NEVER** place data configuration in: - - `"sap.card"/content/data/` - - `"sap.card"/header/data/` -- Data can be provided via: - 1. Inline JSON object - 2. Network request (HTTP/HTTPS/Destination) - 3. Extension method call -- **ALWAYS** verify these paths are correctly set: - - `"sap.card"/data/path` (Primary data path) - - `"sap.card"/content/data/path` (Content-specific path. It overrides the primary data path) - - `"sap.card"/header/data/path` (Header-specific path. It overrides the primary data path) - -#### 1.1.1 Data Errors Detection -- Symptom: "No data to display" message appears. -- Cause: Incorrect data configuration or data path in the content incorrectly overrides the primary data path. -- Solution: Verify all rules in [1.1 Data](#11-data) are properly followed. - -### 1.2 Internationalization -- **ALWAYS** bind properties that are not bound to the data to the `i18n` model. - -### 1.3 Analytical Cards -- **ALWAYS** follow [6. Analytical Cards Coding Guidelines](#6-analytical-cards-coding-guidelines) when developing Analytical cards. - -### 1.4 Configuration Editor -- **ALWAYS** follow [5. Configuration Editor](#5-configuration-editor) guidelines when creating or modifying Configuration Editors for Integration Cards. -- **ALWAYS** load [references/configuration_editor_example.md](references/configuration_editor_example.md) whenever a `dt/Configuration.js` file is present in the project, is being created, or is being modified — even if the user did not explicitly mention the Configuration Editor. - -## 2. Validation -- **ALWAYS** ensure that `manifest.json` file is valid JSON. -- **ALWAYS** ensure that in `manifest.json` file the property `sap.app/type` is set to `"card"`. -- **ALWAYS** validate the `manifest.json` against the UI5 Manifest schema. Use the `run_manifest_validation` tool to do this. -- **ALWAYS** avoid using deprecated properties in `manifest.json` and elsewhere. -- **NEVER** treat Integration Cards' project as UI5 project, except for cards of type "Component". - -## 3. Card Explorer -- The Card Explorer provides detailed documentation for the Integration Cards schema, including descriptions of every property, guidance for integrating cards into hosting environments, configuration editor documentation with examples, and broader best practices. It is available at: https://ui5.sap.com/test-resources/sap/ui/integration/demokit/cardExplorer/webapp/index.html -- The Card Explorer sample sources (manifest.json, data.json, etc.) are available in the openui5 GitHub repository: https://github.com/UI5/openui5/tree/master/src/sap.ui.integration/test/sap/ui/integration/demokit/cardExplorer/webapp/samples - -## 4. Preview Instructions -- If preview of the card must be shown, **ALWAYS** check the card folder for an existing preview file and any accompanying instructions or scripts, and reuse them if available. - * for example, in NodeJS-based projects, search the `package.json` file for `start` or similar script. If such is available, use it - * also search in the `README.md` file. -- If preview instructions are not available, you have to create an HTML page that contains a `ui-integration` card element which references the card manifest. Then serve the HTML page using `http` server. +Rules an agent must follow when creating, modifying, validating, or previewing a UI Integration Card. Adherence is critical for working cards. + +## When to load each reference + +| Trigger | Load | +|---|---| +| Working on or planning an Analytical card | [`references/analytical_chart_types.md`](references/analytical_chart_types.md) | +| `dt/Configuration.js` exists, is being created, or is being modified | [`references/configuration_editor_example.md`](references/configuration_editor_example.md) | + +If the trigger applies, load before producing any output. Do not work from memory. + +## 1. Core rules + +| Rule | Detail | +|---|---| +| Prefer declarative cards | Types: List, Table, Calendar, Timeline, Object, Analytical. Create an Extension only in exceptional cases. | +| Use `create_integration_card` MCP tool | When creating a new declarative card. | +| Parameter binding syntax | `{parameters>/parameterKey/value}` — single braces, `>` separator, `value` suffix. | +| Destination binding syntax | `{{destinations.destinationName}}` — double braces, dot. Configure under `sap.card/configuration/destinations/`. Reference by name; never replace with raw URL. | +| i18n binding | Bind every non-data, user-visible string to the i18n model. | +| Links | Use the `actions` property; never inline `` or hand-rolled URL handlers. | +| Validate before declaring done | See [3. Validation](#3-validation). | +| Show preview when requested | See [4. Preview](#4-preview). | +| Don't modify provided data | Use it as supplied. | + +## 2. Data placement + +`sap.card/data/` is the only correct top-level location for the data request. + +| Path | Purpose | +|---|---| +| `sap.card/data/path` | Primary data path | +| `sap.card/content/data/path` | Content-specific path; **overrides** the primary path if set | +| `sap.card/header/data/path` | Header-specific path; **overrides** the primary path if set | + +Forbidden: putting the request itself under `sap.card/content/data/` or `sap.card/header/data/`. + +**Symptom — "No data to display":** typically caused by a `content/data` block that overrides the primary data path. Verify [2. Data placement](#2-data-placement) before debugging anything else. + +## 3. Validation + +| Rule | Detail | +|---|---| +| Valid JSON | `manifest.json` must parse. | +| `sap.app/type` | Must be `"card"`. | +| Schema validation | Use `run_manifest_validation` MCP tool. | +| No deprecated properties | In `manifest.json` or elsewhere. | +| Not a UI5 project | Except for `Component`-type cards. | + +## 4. Preview + +If asked to preview, first check the card folder for an existing preview entry point — `package.json` `start` script, `README.md`, or an existing HTML file. Reuse it if present. Otherwise create an HTML page with a `` element pointing at the manifest, and serve via an `http` server. ## 5. Configuration Editor -Configuration Editor allows different personas to customize Integration Cards without modifying the manifest file directly. -The following roles/personas are supported: -- Administrator -- Page/Content Administrator -- Translator - -The Configuration Editor is implemented through two key components: - -1. **Definition file**: Create a `dt/Configuration.js` file that exports a Designtime definition object -2. **Manifest reference**: Reference this definition in the `manifest.json` under the `sap.card/configuration/editor` property - -The `dt/Configuration.js` file defines the Configuration Editor's structure by specifying: -- Form layout and field definitions -- Input controls and visualizations -- Validation rules and field relationships -- Grouping and organization of configuration options - -When creating or modifying Integration Cards, follow these guidelines for Configuration Editors: -- Assume the role of Administrator persona when designing the Configuration Editor. -- **ALWAYS** ensure that the Configuration Editor reflects the current structure and fields of the `manifest.json`. -- **ALWAYS** make the existing fields in the `manifest.json` configurable via the editor. For example manifest parameters, title, subtitle, icon of the header, etc. -- **ALWAYS** ask the user if they agree to make all fields editable and what other fields should be added. -- **NEVER** add fields to the editor that do not exist in the `manifest.json`. -- **ALWAYS** remove fields from the editor when removing them from the `manifest.json`. -- **ALWAYS** add fields in the Configuration Editor when adding them to the `manifest.json`. - -- **ALWAYS** load [references/configuration_editor_example.md](references/configuration_editor_example.md) before creating or modifying a Configuration Editor (i.e. a `dt/Configuration.js` file). It contains a complete example of a `manifest.json` paired with the corresponding `dt/Configuration.js` file. - -## 6. Analytical Cards Coding Guidelines -- **ALWAYS** set `sap.card/content/chartType` property. -- **ALWAYS** adjust `sap.card/content/measures`, `sap.card/content/dimensions` and `sap.card/content/feeds` to match the `sap.card/content/chartType` property and data structure. This is critical for proper data display. -- **ALWAYS** use `sap.card/content/chartProperties` to adjust labels, colors, the legend, and other chart aspects. -- **ALWAYS** define each feed with its type (Dimension or Measure), its unique identifier (uid), and the associated values using defined measures and dimensions. Example (for a donut/pie chart): + +The editor lets the Administrator, Page/Content Administrator, and Translator personas customise a card without editing `manifest.json` directly. + +Two pieces: +1. `dt/Configuration.js` — exports a function that returns `new Designtime({ form: {...} })`. +2. `manifest.json` — references the file at `sap.card/configuration/editor`. + +Design as the **Administrator** persona. + +| Rule | Detail | +|---|---| +| Mirror the manifest | Editor reflects the current structure and parameters of `manifest.json` exactly. | +| All existing fields editable | Title, subtitle, header icon, parameters — make them configurable. | +| Ask the user | Before deciding which fields to expose, ask: "Make all manifest fields editable? Anything else to add?" | +| No invented fields | Never add an editor field that does not exist in `manifest.json`. | +| Keep in sync | Add to or remove from the editor when adding to or removing from `manifest.json`. | + +Load [`references/configuration_editor_example.md`](references/configuration_editor_example.md) for the canonical paired example. + +## 6. Analytical cards + +Load [`references/analytical_chart_types.md`](references/analytical_chart_types.md) for the full chart-type catalog (UIDs and per-type examples). + +| Rule | Detail | +|---|---| +| Set `chartType` | `sap.card/content/chartType` is required. | +| Match feeds to chart type | `measures`, `dimensions`, and `feeds` must match the UIDs the chart type expects. The reference file lists them per chart. | +| Each feed needs three keys | `type` (`Dimension`\|`Measure`), `uid`, `values`. | +| `chartProperties` | Use it for labels, colours, legend, etc. Do not invent keys. Omit entirely if defaults are fine. | + +Minimal feeds example (donut/pie): ```json "feeds": [ - { - "type": "Dimension", - "uid": "color", - "values": [ - "Store Name" - ] - }, - { - "type": "Measure", - "uid": "size", - "values": [ - "Revenue" - ] - } + { "type": "Dimension", "uid": "color", "values": ["Store Name"] }, + { "type": "Measure", "uid": "size", "values": ["Revenue"] } ] ``` -- **ALWAYS** ensure the `uid` in `feeds` exactly matches the UID required for the selected chartType (e.g., color, size, dataFrame). -- **ALWAYS** load [references/analytical_chart_types.md](references/analytical_chart_types.md) before creating or modifying an Analytical card. It contains the comprehensive list of all supported chart types, their required UIDs, and example configurations. +## 7. Card Explorer (reference) + +- Schema docs and live samples: +- Sample sources: