**TITLE**: Share: Microsoft Teams — SAP Fiori elements integration (developer guidance)

**INTRODUCTION**: This document summarizes the functional behavior, developer constraints, and annotation controls for the "Share: Microsoft Teams" feature in SAP Fiori elements apps. Use it to implement safe sharing, exclude sensitive data, and understand limitations for cards, header facets, and header actions when content is shared to Microsoft Teams.

**TAGS**: fiori-elements-framework, sap-s4hana, microsoft-teams, share, annotations, manifest.json, security, application-state

**STEP**: 1 — Prerequisites and admin configuration links

**DESCRIPTION**: Confirm system-level Microsoft Teams integration and security configuration before enabling or testing the feature in your app. Use these official resources for system administrator setup and security guidance.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "SAP_S4HANA_Cloud_Public": "https://help.sap.com/docs/SAP_S4HANA_CLOUD/0f69f8fb28ac4bf48d2b57b9637e81fa/257ec7408db6420682462cd1d000e744.html",
  "SAP_S4HANA_On_Premise": "https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/8308e6d301d54584a33cd04a9861bc52/849465e69b7a490a88049fe0b24fb01e.html?version=2023.000",
  "Security_Config_Guide": "security-configuration-ba0484b.md"
}
```

**STEP**: 2 — Feature behavior summary (end-user flows)

**DESCRIPTION**: The Share control exposes three Microsoft Teams options. Use this to design and test flows in your UI: Chat, Tab, and Card. Ensure proper app-state generation for link shortening and that end users are informed about cookies and incognito limitations.

**LANGUAGE**: PlainText

**CODE**:
```
Share options:
- As Chat  : share direct link to a specific application state for quick collaboration.
- As Tab   : embed the application context as a Teams tab for group collaboration.
- As Card  : share a collaborative card (object page only) with header facets and up to two header actions.

Notes:
- Application states are used to shorten long URLs and are cleaned up if not accessed for a long time.
- Incognito mode may fail with 401 Unauthorized unless third-party cookies are allowed.
- Image resource (for UI reference): images/Share_Microsoft_Teams_-_All_Options_None_Selected_f6ca832.png
```

**STEP**: 3 — Exclude sensitive and personal data from sharing (annotations)

**DESCRIPTION**: To prevent transfer of sensitive/personal data outside SAP S/4HANA when using "As Card", annotate properties so they are excluded from cards. Use the personal data vocabularies provided by SAP.

**LANGUAGE**: CDS

**CODE**:
```cds
// Use these annotation URIs on entity properties to mark data as sensitive or personal
@com.sap.vocabularies.PersonalData.v1.IsPotentiallySensitive : true
@com.sap.vocabularies.PersonalData.v1.IsPotentiallyPersonal : true
```

**STEP**: 4 — Header facets: supported visibility and known restrictions

**DESCRIPTION**: When sharing header facets as a card, visibility and presentation depend on recipient visibility and app configuration. Avoid using unsupported facet content types and be aware of formatting/currency differences.

**LANGUAGE**: PlainText

**CODE**:
```
Restrictions for Header Facets when shared "As Card":
- Unsupported facet content:
  - micro chart
  - rating indicator
  - progress indicator
  - custom facets
  - icon-based images
- If header facet visibility/position/title/subtitle is modified in manifest.json or via custom coding, the card display may differ from the object page.
- Data formatting differences:
  - Custom OData V4 formatters can change formatting inside cards.
  - DataPoint.NumberOfFractionalDigits affects precision differently in cards.
  - Currency formatting in cards may differ from object page.
```

**STEP**: 5 — Header actions on cards: supported actions, constraints, and parameter behavior

**DESCRIPTION**: Cards support up to two annotation-based header actions (annotation actions not overridden by manifest). Understand unsupported action types, parameter limitations, and confirmation behavior to implement actionable buttons correctly.

**LANGUAGE**: CDS

**CODE**:
```cds
// Annotation identifiers referenced in behavior:
DataFieldForIntentBasedNavigation
Common.IsActionCritical
DataFieldForAction

// Key behavior points:
- Cards display only the first two supported annotation-based actions.
- Bound actions receive the page context when triggered from the card.
- Buttons based on DataFieldForIntentBasedNavigation are NOT supported for sharing as card.
- Manifest-based actions are NOT supported in cards.
- Annotation-based actions overridden by manifest binding expressions/functions are NOT supported in cards.
- Confirmation-based actions using Common.IsActionCritical are supported, but the card uses the default i18n key text "C_OPERATIONS_ACTION_CONFIRM_MESSAGE" (custom i18n overrides are not shown).
```

**STEP**: 6 — Action parameter limitations inside Teams cards

**DESCRIPTION**: If your annotation-based action exposes parameters, Teams card UI presents them as simple dropdown/fields. Do not rely on advanced controls or parameter mappings.

**LANGUAGE**: PlainText

**CODE**:
```
Action parameter limitations in Teams cards:
- Unsupported UI elements:
  - Field help (value help)
  - Dropdown lists (complex value help)
  - Date pickers / Date time pickers
- No support for default values for parameter fields.
- No support for IN/OUT parameter mapping:
  - Changing one field will NOT filter or populate another (IN behavior).
  - Changing a value will NOT populate other fields (OUT behavior).
- For semantic actions, only static Criticality values for DataFieldForAction are supported on cards.
```

**STEP**: 7 — Manifest.json considerations affecting cards

**DESCRIPTION**: Any customizations applied via manifest.json or custom code can change what appears on cards (visibility, ordering, titles). If you rely on card parity with object page, validate after manifest changes.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "note": "If properties/actions are modified in webapp/manifest.json or via custom code, cards may not display same visibility, position, title, subtitle, or action set as the source object page."
}
```

**STEP**: 8 — Application state cleanup and URL shortening behavior

**DESCRIPTION**: Share uses stored application state records to shorten long URLs. These records are automatically cleaned up after inactivity; ensure long-term links are not assumed permanent.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "ApplicationStateCleanupGuide": "https://help.sap.com/docs/ABAP_PLATFORM_NEW/a7b390faab1140c087b8926571e942b7/6107ee41f89a43c9af0aa279fe039cca.html",
  "Behavior": "Application state records used for shortened URLs are cleaned up if not accessed for a long time."
}
```

**STEP**: 9 — Incognito mode and third-party cookie requirement

**DESCRIPTION**: Inform end users that sharing via Microsoft Teams in incognito/private browsing can fail due to blocked third-party cookies. Provide guidance to allow third-party cookies or avoid incognito sessions for Teams sharing.

**LANGUAGE**: PlainText

**CODE**:
```
Incognito mode behavior:
- In incognito, users may receive HTTP 401 Unauthorized authentication errors when using Share: Microsoft Teams.
- Resolution: Allow third-party cookies for the incognito session or use a normal browsing session.
```

fiori-elements-framework sap-s4hana microsoft-teams share annotations manifest.json security application-state


**TITLE**: Status Building Block (sap.fe.macros.Status)

**INTRODUCTION**: Use the Status building block to render an annotation-driven object status (based on SAPUI5 ObjectStatus) inside a Fiori Elements / UI5 view. Configure the displayed value and criticality via an annotation path (metaPath). Optionally attach a press handler to implement custom behavior when the status is clicked.

**TAGS**: fiori-elements-framework, sap-fe-macros, Status, ObjectStatus, SAPUI5, annotations, UI.v1.FieldGroup, press-event

**STEP**: 1 — Insert Status macro into an XML view

**DESCRIPTION**: Add the Status building block to your XML view. Set the metaPath to the annotation path that provides the status value and criticality. Set id, visual size (largeDesign), and attach a press event to delegate to a controller handler.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Status
    metaPath="@com.sap.vocabularies.UI.v1.FieldGroup#ApprovalData/Data/0"
    id="myStatus"
    largeDesign="true"
    press=".onStatusPressed"
/>
```

**STEP**: 2 — Example full XML view snippet with namespace and controller wiring

**DESCRIPTION**: Example showing the XML view root with the macros namespace and the Status macro included. Ensure you declare the macros namespace (typically sap.fe.macros) and reference the controllerName.

**LANGUAGE**: XML

**CODE**:
```xml
<mvc:View
    controllerName="my.app.controller.View"
    xmlns:mvc="sap.ui.core.mvc"
    xmlns:macros="sap.fe.macros"
    xmlns="sap.m">
    <macros:Status
        metaPath="@com.sap.vocabularies.UI.v1.FieldGroup#ApprovalData/Data/0"
        id="myStatus"
        largeDesign="true"
        press=".onStatusPressed"
    />
</mvc:View>
```

**STEP**: 3 — Implement the press handler in the controller

**DESCRIPTION**: Implement the onStatusPressed handler in the view controller. Typical tasks: inspect the event source, get the binding context, read relevant properties (for example the status text or criticality), and perform actions such as navigation or showing a message. The event object is a standard UI5 event.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
sap.ui.define([
  "sap/ui/core/mvc/Controller",
  "sap/m/MessageToast"
], function (Controller, MessageToast) {
  "use strict";

  return Controller.extend("my.app.controller.View", {
    onStatusPressed: function (oEvent) {
      // oEvent.getSource() is the Status control
      var oSource = oEvent.getSource();

      // If the Status is bound to an entity, get the binding context
      var oContext = oSource.getBindingContext();
      if (oContext) {
        // Read a property (replace 'StatusText' with your property name)
        var sStatusText = oContext.getProperty("StatusText");
        var sCriticality = oContext.getProperty("Criticality"); // if available via annotations

        // Example action: show a toast with status details
        MessageToast.show("Status: " + sStatusText + (sCriticality ? " (Criticality: " + sCriticality + ")" : ""));
      } else {
        // Fallback action if no context
        MessageToast.show("Status pressed");
      }

      // Additional actions: navigation, dialog, backend calls, etc.
    }
  });
});
```

**STEP**: 4 — Notes on metaPath and annotations

**DESCRIPTION**: The metaPath must point to an annotation that defines the object status (value and criticality). Example metaPath from the sample:
- @com.sap.vocabularies.UI.v1.FieldGroup#ApprovalData/Data/0

This indicates the Status macro reads annotations (UI.v1.FieldGroup / Data item at index 0) for display and criticality. Ensure your OData service metadata contains the corresponding UI annotations (EDMX or CDS annotations) so the macro can resolve value and criticality.

**LANGUAGE**: text

**CODE**:
```
metaPath example:
@com.sap.vocabularies.UI.v1.FieldGroup#ApprovalData/Data/0
```

**STEP**: 5 — References and live examples

**DESCRIPTION**: Use these references for API details and live examples of the Status building block.

**LANGUAGE**: text

**CODE**:
```
API Reference:
https://ui5.sap.com/#/api/sap.fe.macros.Status

Live examples (Building Blocks - Status - Overview):
https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/features/statusDefault
```

fiori-elements-framework sap-fe-macros Status ObjectStatus SAPUI5 annotations UI.v1.FieldGroup press-event


**TITLE**: Table Building Block (sap.fe.macros.Table) — Usage, Extensions, and APIs

**INTRODUCTION**: This document provides concise, code-focused guidance for instantiating and extending the sap.fe.macros.Table building block in SAP Fiori elements. It covers XML instantiation, adding actions and creation options, linking a FilterBar, quick filters, mass-edit configuration, dynamic request influence (beforeRebindTable), and programmatically creating items via editFlow. Use these snippets directly in fragments, views, and controller extensions.

**TAGS**: UI5, sap.fe.macros, Table, Fiori, XML, JavaScript, FilterBar, QuickVariantSelection, MassEdit, beforeRebindTable, editFlow

**STEP**: 1 — Instantiate a Table (entitySet or navigation property)

**DESCRIPTION**: Use the Table building block to create a UI table bound to an entity set or a navigation property. Include the macros namespace declaration in the fragment or view. These minimal examples show different metaPath options.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Table xmlns:macro="sap.fe.macros" metaPath="/MyEntitySet"/>
<macros:Table xmlns:macro="sap.fe.macros" metaPath="MyNavProperty"/>
<macros:Table xmlns:macro="sap.fe.macros" metaPath="MyNavProperty/@com.sap.vocabularies.UI.v1.LineItem"/>
```

**STEP**: 2 — Add custom actions, grouped actions, and creation options

**DESCRIPTION**: Define inline creation options and custom actions (bound/unbound) inside the Table building block. Use requiresSelection="true" to require a row selection for bound actions. Use ActionGroup to create menu or grouped actions. Note: properties/aggregations defined at the manifest level are NOT supported — define them at the building-block level.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Table metaPath="@com.sap.vocabularies.UI.v1.LineItem" readOnly="true" id="LineItemTablePageCustomActions"> <creationMode name="InlineCreationRows" inlineCreationRowsHiddenInEditMode="true" />  </macros:Table>
     <macros:actions>
          <macros:Action
               key="customAction"
               text="My Custom Action"
               press=".onPressAction"
               placement="After"
               anchor="DataFieldForAction::Service.toggleBoolean"
               requiresSelection="true"
          />
          <macros:ActionGroup text="Grouped Actions" placement="After" anchor="customAction">
               <macros:Action text="Menu Action 1" press=".onPressMenuAction" />
               <macros:Action text="Menu Action 2" press=".onPressMenuAction" />
          </macros:ActionGroup>
     </macros:actions>
</macros:Table>
```

**STEP**: 3 — Use Table inside custom sections/subsections/pages

**DESCRIPTION**: The Table building block can be used in custom sections, subsections, and pages. Place the Table fragment where you need it inside your view/layout. (No extra manifest-level properties.)

**LANGUAGE**: XML

**CODE**:
```xml
<!-- Example usage inside a Panel or any container -->
<Panel headerText="Table in a custom section">
    <macros:Table metaPath="@com.sap.vocabularies.UI.v1.LineItem" id="LineItemTableCustom" />
</Panel>
```

**STEP**: 4 — Link Table to a FilterBar (local or global ID)

**DESCRIPTION**: Reference the FilterBar ID on the Table using the filterBar attribute. The FilterBar may be defined in the same view or another view (use local or global ID).

**LANGUAGE**: XML

**CODE**:
```xml
<Panel headerText="Table in Display Mode with FilterBar">
     <macros:FilterBar metaPath="@com.sap.vocabularies.UI.v1.SelectionFields#SF1" id="FilterBar" />
     <macros:Table metaPath="@com.sap.vocabularies.UI.v1.LineItem" displayMode="true" id="LineItemTable" filterBar="FilterBar" />
</Panel>
```

**STEP**: 5 — Table public APIs (variants, messages, current variant ID)

**DESCRIPTION**: Use the Table API to manage presentation/selection variants, variant IDs, and messages.
- getPresentationVariant() / setPresentationVariant()
- getSelectionVariant() / setSelectionVariant() — works only if table personalization is enabled (these methods consider variants applied directly to the table and exclude variants applied to a bound model).
- setCurrentVariantID() / getCurrentVariantID()
- sendMessage() / removeMessage()

For API details see the sap.fe.macros.Table API Reference and Demo Kit.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example conceptual usage (adapt to your controller/view):
// var table = this.getView().byId("LineItemTable");
// var pv = table.getPresentationVariant();
// table.setPresentationVariant(pv);
// var sv = table.getSelectionVariant();
// table.setSelectionVariant(sv);
// table.setCurrentVariantID("myVariantId");
// var currentId = table.getCurrentVariantID();
// table.sendMessage({ /* message object */ });
// table.removeMessage(messageId);
```

**STEP**: 6 — Control Search field visibility

**DESCRIPTION**: If the linked entity is searchable, the Search field appears in the table toolbar by default. Disable it by setting isSearchable="false" on the Table.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Table
    metaPath="@com.sap.vocabularies.UI.v1.LineItem"
    id="LineItemTable"
    isSearchable="false"
/>
```

**STEP**: 7 — Define Quick Variant Selection (quick filters)

**DESCRIPTION**: Define QuickVariantSelection to declare quick filters (presentation variants) with optional showCounts. Use macrosTable:QuickVariantSelection inside macros:quickVariantSelection.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Table
    metaPath="@com.sap.vocabularies.UI.v1.LineItem"
    id="LineItemTableQuickFilters"
>
    <macros:quickVariantSelection>
        <macrosTable:QuickVariantSelection
            paths="com.sap.vocabularies.UI.v1.SelectionPresentationVariant#All,com.sap.vocabularies.UI.v1.SelectionPresentationVariant#Success"
            showCounts="true"
        />
    </macros:quickVariantSelection>
</macros:Table>
```

**STEP**: 8 — Configure Mass Edit (Dialog mass-edit)

**DESCRIPTION**: Use the massEdit aggregation on the Table to declare mass-edit configuration and UI. The structure follows the Mass Edit dialog pattern; include visibleFields and any custom fragment/form content inside.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Table
    metaPath="@com.sap.vocabularies.UI.v1.LineItem"
    id="LineItemTablePageMassEdit"
>
    <massEdit>
        <macrosTable:MassEdit visibleFields="BooleanProperty,TagStatus">
            <f:FormContainer>
                <f:formElements>
                    <f:FormElement label="Custom Element">
                        <Text text="This is a custom fragment displayed in the Mass-edit dialog" />
                    </f:FormElement>
                </f:formElements>
            </f:FormContainer>
        </macrosTable:MassEdit>
    </massEdit>
</macros:Table>
```

**STEP**: 9 — Influence the table request dynamically (beforeRebindTable)

**DESCRIPTION**: Use beforeRebindTable to access CollectionBindingInfo before the table rebind. Add filters, sorters, and select additional properties. Add beforeRebindTable attribute to the Table and implement an extension point in the page controller to modify the collectionBindingInfoAPI.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:Table
    metaPath="@com.sap.vocabularies.UI.v1.LineItem"
    readOnly="true"
    id="LineItemTablePageCustomActions"
    isSearchable="false"
    beforeRebindTable=".tableRefreshed"
>
```

**LANGUAGE**: JavaScript

**CODE**:
```javascript
sap.ui.define(
    ["sap/fe/core/PageController", "sap/m/MessageBox", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/model/Sorter"],
    function (PageController, MessageBox, Filter, FilterOperator, Sorter) {
        "use strict";

        return PageController.extend("sap.fe.core.fpmExplorer.tableCustoms.Page", {
            tableRefreshed(event) {
                var collectionBindingInfoAPI = event.getParameters("collectionBindingInfo");

                //Add a filter
                var filter = new Filter({
                    path: "BooleanProperty",
                    operator: FilterOperator.EQ,
                    value1: false
                });
                collectionBindingInfoAPI.addFilter(filter);

                //Add a sorter
                var sorter = new Sorter("ID", true);
                collectionBindingInfoAPI.addSorter(sorter);

                //Request an additional property to the request
                collectionBindingInfoAPI.addSelect(["TagStatus"]);
            }
        });
    }
);
```

**STEP**: 10 — Trigger creation of a new document (editFlow.createDocument)

**DESCRIPTION**: From the editFlow controller extension, get the table API reference and call base.editFlow.createDocument(table, options). Provide creationMode, createAtEnd, and initial data fields in options. Use the Promise to handle completion.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
//Get the table API
var table = this.getView().byId("fe::table::_Child::LineItem::Table");

//Create document
this.base.editFlow
    .createDocument(table, {
        creationMode: coreLibrary.CreationMode.Inline,
        createAtEnd: true,
        data: {
            ChildTitleProperty: "Child Object Custom Title",
            ChildDescriptionProperty: "Child Custom Description"
        }
    })
    .then(function () {
        MessageToast.show("Custom create action successfully invoked");
    });
```

**STEP**: 11 — References and live examples

**DESCRIPTION**: Use the Demo Kit and SAP Fiori development portal for live examples and full API docs:
- Building Blocks - Table - Extensions - Custom Column: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/table/customColumn
- Building Blocks - Table - Extensions - Custom Action: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/table/customTableAction
- Table API Reference: https://ui5.sap.com/#/api/sap.fe.macros.Table
- Table - Usage with Filter Bar: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/table/tableFilterBar
- Table - Mass Edit: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/table/tableMassEdit
- Table - Extensions - Table APIs: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/table/tablePublicAPIs

**LANGUAGE**: Markdown

**CODE**:
```text
See the links above for live examples and full API references.
```

UI5 sap.fe.macros Table Fiori XML JavaScript FilterBar QuickVariantSelection MassEdit beforeRebindTable editFlow


**TITLE**: The `TreeTable` Building Block

**INTRODUCTION**: Use the sap.fe.macros TreeTable building block to render tree-structured tabular data driven by OData/UI annotations. This block isolates tree-table–specific parameters (hierarchy, metadata path, read-only mode) from the main Table building block so you can insert a tree table in an XML view with minimal configuration.

**TAGS**: fiori-elements-framework, TreeTable, sap.fe.macros, UI5, SAP Fiori, building-blocks, XML view

**STEP**: 1 — Insert the TreeTable into an XML view

**DESCRIPTION**: Copy the sample XML view into your project to render a TreeTable inside a Page/Panel. Keep the XML namespaces and controllerName if you use a custom controller. Set metaPath to the annotation path for the line item and hierarchyQualifier to the qualifier of the hierarchy annotation defined in your metadata. Use readOnly="true" to render display-only rows.

**LANGUAGE**: XML

**CODE**:
```xml
<mvc:View
	xmlns="sap.m"
	xmlns:mvc="sap.ui.core.mvc"
	xmlns:macros="sap.fe.macros"
	controllerName="sap.fe.core.fpmExplorer.treeTable.TreeTable"
>
	<Page enableScrolling="true">
		<Panel headerText="Tree table in Display Mode">
			<macros:TreeTable
				metaPath="/Products/@com.sap.vocabularies.UI.v1.LineItem"
				hierarchyQualifier="ProductsHierarchy"
				readOnly="true"
				id="treeTable"
			/>
		</Panel>
	</Page>
</mvc:View>
```

**STEP**: 2 — Minimal TreeTable tag and attribute guidance

**DESCRIPTION**: Use this minimal tag as a template. Replace placeholders with your annotation path and qualifier. Key attributes:
- metaPath: metadata annotation path to the LineItem (list of columns).
- hierarchyQualifier: qualifier name that identifies the hierarchy annotation in your service metadata.
- readOnly: set to "true" when you want display-only mode.
- id: optional control id for view/controller access.
- controllerName / namespaces: include xml namespaces and controller only if needed in your view.

**LANGUAGE**: XML

**CODE**:
```xml
<macros:TreeTable
    metaPath="/<EntitySet>/@com.sap.vocabularies.UI.v1.LineItem"
    hierarchyQualifier="<HierarchyQualifier>"
    readOnly="true|false"
    id="<yourTreeTableId>"
/>
```

**STEP**: 3 — References and live examples

**DESCRIPTION**: Open these references to review API details, live examples, and related documentation for tree table usage and available properties.

**LANGUAGE**: text

**CODE**:
```
Live examples (Building Blocks - Table - Tree Table):
https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/table/treeTable

API Reference (sap.fe.macros.TreeTable):
https://ui5.sap.com/#/api/sap.fe.macros.TreeTable

Related documentation (Tree Tables):
tree-tables-7cf7a31.md
```

The `TreeTable` Building Block

fiori-elements-framework
TreeTable
sap.fe.macros
UI5
SAP Fiori
building-blocks
XML view


**TITLE**: VariantManagement Building Block (SAP Fiori Elements)

**INTRODUCTION**: Enable variant management for flex-enabled controls in flexible programming model SAPUI5 applications. Use the VariantManagement building block to capture and save user personalization for linked controls (page-level) or use control-level variantManagement properties directly on Table/Chart controls when appropriate.

**TAGS**: SAPUI5, Fiori, VariantManagement, FilterBar, Table, Chart, macros, flexible-programming-model, UI5

**STEP**: 1 — Choose variant-management scope

**DESCRIPTION**: Decide whether you need page-level or control-level variant management:
- Page level: Use the VariantManagement building block to manage variants across multiple flex-enabled controls on a page (captures all personalization changes of linked controls).
- Control level: For Table or Chart controls you can skip the VariantManagement building block and instead use the control's variantManagement property (control-only scope).

**LANGUAGE**: None

**CODE**:
```text
(Decision step — no code. Use VariantManagement building block for multi-control/page-level variant management; use variantManagement property on Table/Chart for control-level variant management.)
```

**STEP**: 2 — Initialize VariantManagement and link flex-enabled controls

**DESCRIPTION**: Add the VariantManagement building block inside your XML view (for example, in the DynamicPageTitle heading). Use the `for` association to list comma-separated IDs of flex-enabled controls that should be linked. The building block automatically captures flex-relevant personalization changes on linked controls and saves them when the user saves a variant. Common attributes:
- id: control ID
- for: comma-separated control IDs to link (e.g., "FilterBar,LineItemTable")
- showSetAsDefault: adds "Set as Default" option
- headerLevel: heading level (e.g., "H2")

Place flex-enabled controls (FilterBar, Table, Chart) with matching IDs elsewhere in the same view so they can be linked.

**LANGUAGE**: XML

**CODE**:
```xml
<f:DynamicPage id="FilterBarVMWithTable" class="sapUiResponsiveContentPadding">
    <f:title>
        <f:DynamicPageTitle id="_IDGenDynamicPageTitle1">
            <f:heading>
                <macros:VariantManagement id="vm" for="FilterBar,LineItemTable" showSetAsDefault="true" headerLevel="H2" />
            </f:heading>
        </f:DynamicPageTitle>
    </f:title>
    <f:header>
        <f:DynamicPageHeader id="_IDGenDynamicPageHeader1" pinnable="true">
            <VBox id="_IDGenVBox1">
                <macros:FilterBar metaPath="@com.sap.vocabularies.UI.v1.SelectionFields" id="FilterBar" />
            </VBox>
        </f:DynamicPageHeader>
    </f:header>
    <f:content>
        <macros:Table metaPath="@com.sap.vocabularies.UI.v1.LineItem" readOnly="true" id="LineItemTable" filterBar="FilterBar" />
    </f:content>
</f:DynamicPage>
```

**STEP**: 3 — Link mechanics and runtime behavior

**DESCRIPTION**: How linking works and what to expect at runtime:
- The `for` association links the VariantManagement instance with other flex-enabled controls by ID.
- When a user creates a variant, all linked controls' personalization is captured and stored in that variant.
- Ensure linked controls are "flex-enabled" (support UI adaptation/flex) — e.g., FilterBar, Table, Chart macros.
- For Table macro, use the `filterBar` property to connect to the FilterBar control (as shown in the sample).

**LANGUAGE**: None

**CODE**:
```text
(Behavior note — no code. Ensure controls are flex-enabled and IDs match those in the VariantManagement 'for' list.)
```

**STEP**: 4 — Use control-level variant management when applicable

**DESCRIPTION**: If you only need variant management for a single control (Table or Chart), prefer the control's built-in variantManagement property over adding a separate VariantManagement building block. This simplifies the view and isolates variant persistence to that control.

**LANGUAGE**: None

**CODE**:
```text
(Recommendation — use control-level 'variantManagement' property on Table/Chart when single-control variant scope is sufficient.)
```

**STEP**: 5 — References

**DESCRIPTION**: API and live example links for further details and examples.

**LANGUAGE**: None

**CODE**:
```text
VariantManagement API Reference:
https://ui5.sap.com/#/api/sap.fe.macros.VariantManagement

Table API (macro) Reference:
https://ui5.sap.com/#/api/sap.fe.macros.Table

Live example — Filter Bar with Variant Management and Chart:
https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/filterBar/filterBarVMWithChart
```

SAPUI5 Fiori VariantManagement FilterBar Table Chart macros flexible-programming-model UI5


**TITLE**: Time Series Chart Card — Annotations and manifest settings for time-axis charts

**INTRODUCTION**: This guide shows the exact code snippets and configuration steps to enable time-series (time-axis) charts in SAP Fiori analytical cards. It includes OData metadata property, UI.Chart XML, ABAP CDS, CAP CDS annotations, and manifest.json examples for chart-level and tab-level timeAxis.levels configuration. Use these snippets directly in your metadata/annotations and manifest to enable correct time-axis behavior and time-granularity drill-down.

**TAGS**: fiori-elements-framework, time-series, chart, UI.Chart, annotations, manifest.json, CDS, ABAP, CAP, sap.ovp

STEP: 1 — OData metadata: declare a Date dimension property
DESCRIPTION: Add this Property element to your OData metadata to mark the Date field as a dimension (Edm.DateTime). This enables the analytical chart to recognize the field as a time axis source.
LANGUAGE: XML
CODE:
```xml
<Property Name="Date" Type="Edm.DateTime" sap:display-format="Date" sap:label="Date" sap:aggregation-role="dimension"/>
```

STEP: 2 — UI.Chart XML Annotation (example: Line chart with series)
DESCRIPTION: Add a UI.Chart annotation (XML) to define a line chart that uses Date as the Category (time) dimension and a currency dimension assigned to Series. Use the Qualifier to reference this chart in manifest or card declarations.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="UI.Chart" Qualifier="Line-Time_-Currency">
    <Record Type="UI.ChartDefinitionType">
        <PropertyValue Property="Title" String="View1" />
        <PropertyValue Property="ChartType" EnumMember="UI.ChartType/Line"/>
        <PropertyValue Property="MeasureAttributes">
            <Collection>
                <Record Type="UI.ChartMeasureAttributeType">
                    <PropertyValue Property="Measure" PropertyPath="SalesShare" />
                    <PropertyValue Property="Role"
                                   EnumMember="UI.ChartMeasureRoleType/Axis1" />
                    <PropertyValue Property="DataPoint" AnnotationPath="@UI.DataPoint#Eval_by_CtryCurr_-SalesShare"/>
                </Record>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="DimensionAttributes">
            <Collection>
                <Record Type="UI.ChartDimensionAttributeType">
                    <PropertyValue Property="Dimension" PropertyPath="Date" />
                    <PropertyValue Property="Role"
                                   EnumMember="UI.ChartDimensionRoleType/Category" />
                </Record>
                <Record Type="UI.ChartDimensionAttributeType">
                    <PropertyValue Property="Dimension" PropertyPath="Sales_CURRENCY"/>
                    <PropertyValue Property="Role"
                                   EnumMember="UI.ChartDimensionRoleType/Series"/>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

STEP: 3 — ABAP CDS Annotation (equivalent chart definition)
DESCRIPTION: Use this ABAP CDS annotation block to declare the same chart definition in ABAP CDS. Include qualifier and asDataPoint if you need data point evaluation.
LANGUAGE: ABAP CDS
CODE:
```
@UI.Chart: [
  {
    title: 'View1',
    chartType: #LINE,
    measureAttributes: [
      {
        measure: 'SalesShare',
        role: #AXIS_1,
		asDataPoint: true
      }
    ],
    dimensionAttributes: [
      {
        dimension: 'Date',
        role: #CATEGORY
      },
      {
        dimension: 'Sales_CURRENCY',
        role: #SERIES
      }
    ],
    qualifier: 'Line-Time-Currency'
  }
]
annotate view VIEWNAME with { }
```

STEP: 4 — CAP CDS Annotation (UI.Chart in CAP model)
DESCRIPTION: Use this CAP CDS JSON-style annotation to define the chart in CAP. Keep DataPoint annotation path formatted as in your project.
LANGUAGE: CDS
CODE:
```
UI.Chart #Line-Time-Currency : {
    $Type : 'UI.ChartDefinitionType',
    Title : 'View1',
    ChartType : #Line,
    MeasureAttributes : [
        {
            $Type : 'UI.ChartMeasureAttributeType',
            Measure : SalesShare,
            Role : #Axis1,
            DataPoint : '@UI.DataPoint#Eval_by_CtryCurr-SalesShare'
        }
    ],
    DimensionAttributes : [
        {
            $Type : 'UI.ChartDimensionAttributeType',
            Dimension : Date,
            Role : #Category
        },
        {
            $Type : 'UI.ChartDimensionAttributeType',
            Dimension : Sales_CURRENCY,
            Role : #Series
        }
    ]
}
```

STEP: 5 — Rules: when the chart uses a time axis automatically
DESCRIPTION: Verify these requirements in your chart annotation and metadata so the analytical card automatically uses a time axis:
LANGUAGE: text
CODE:
```
- ChartType must be one of: vertical bullet, stacked column, scatter, line, bubble, column, waterfall, combination, dual combination.
- Dimension counts:
  - Bubble: needs two measures.
  - Combination: needs at least two measures.
  - Line: can use two dimensions (second can be color/Series).
  - Bubble/Column/Waterfall/Combination: configured with only one dimension (except line as above).
  - Vertical bullet, stacked column, scatter: need at least one measure and one dimension. Scatter supports extra color and shape dimensions.
- Dimension data type must be edm.datetime or edm.string with OData metadata sap:semantics set to "year (YYYY)" or "yearweek (YYYYWW)" or "yearmonth (YYYYMM)" or "yearquarter (YYYYQ)".
- If using a color dimension, set its uid/color dimension role to Series.
```

STEP: 6 — manifest.json: add chartProperties.timeAxis.levels at chart-level (global for card)
DESCRIPTION: Add chartProperties.timeAxis.levels in the card settings of your manifest.json to set global time granularity levels for the chart. Replace entitySet and model names as required.
LANGUAGE: JSON
CODE:
```json
{
     "sap.ovp": {
           "cards": {
                 "cardchartsline": {
                       "model": "sales",
                       "template": "sap.ovp.cards.charts.analytical",
                       "settings": {
                             "entitySet": “salesSet",
                             "chartProperties": {
                                   "timeAxis": {
                                         "levels": ["year", "month", "day", "hour", "minute"]
                                   }
                             }
                       }
                 }
           }
     }
},
```

STEP: 7 — manifest.json: add chartProperties.timeAxis.levels at tab-level (per-tab override)
DESCRIPTION: When using tabs, define chartProperties at the tab-level to customize time-axis drill-down for individual tabs. This snippet shows a tab overriding levels to ["year","month","day","hour"].
LANGUAGE: JSON
CODE:
```json
"card_11_v4": {
     "model": "sales",
     "template": "sap.ovp.cards.v4.charts.analytical",
     "settings": {
           "title": "{{TIME_SERIES_ANALYTICAL_CARD}}",
           "subTitle": "{{COMMON_ANALYTICAL_CARD_SUBTITLE_V4}}",
           "entitySet": "salesSet",
           "tabs": [
             {
                   "chartAnnotationPath": "com.sap.vocabularies.UI.v1.Chart#year",
                   "value": "With CalenderYear"
             },
             {
                   "chartAnnotationPath": "com.sap.vocabularies.UI.v1.Chart#year",
                   "value": "With TimeAxis",
                   "chartProperties": {
                         "timeAxis": {
                             "levels": ["year", "month", "day", "hour"]
                         }
                   }
             }
         ]
     }
}
```

STEP: 8 — Best practice: dataset granularity and display recommendation
DESCRIPTION: Ensure your dataset has sufficient time granularity to avoid repeating values at the chosen timeAxis levels. Increase data granularity (e.g., include hour/minute) until the chart displays unique time points at the selected levels.
LANGUAGE: text
CODE:
```
- Use combinations of ["year","month","day","hour","minute"] based on required granularity.
- Test visualization queries at each granularity level; if values repeat at a level, increase granularity in the data source.
- For edm.string time dimensions, ensure sap:semantics metadata is present and matches the format your data uses (YYYY, YYYYWW, YYYYMM, YYYYQ).
```

fiori-elements-framework time-series chart UI.Chart annotations manifest.json CDS ABAP CAP sap.ovp


**TITLE**: Toggling Between Draft and Saved Values (Fiori elements)

**INTRODUCTION**: This document describes UI behavior and actionable steps for toggling between draft and saved versions in draft-enabled SAP Fiori elements applications (OData V2 and V4). Use this as a reference when implementing or testing list report and object page behaviors and when implementing UI controls that present draft vs saved versions.

**TAGS**: fiori-elements-framework, odata-v2, odata-v4, draft, editing-status, list-report, object-page, ui-behavior

**STEP**: 1 — List Report: Editing Status filter behavior

**DESCRIPTION**: When a draft-enabled application exposes the Editing Status filter, it includes the option "All (Hiding Drafts)". Selecting this option controls which entries are shown in the list report and how navigation behaves when drafts exist for objects.

- Behavior summary (for "All (Hiding Drafts)"):
  - In the list report: only saved objects (active versions) are listed with their saved data.
  - When navigating to an object page from the list: the saved version opens. If a draft exists for that object, the saved object view shows a "Return to Draft" affordance to switch to the draft.
  - When navigating back to the list: only saved objects are shown (the list does not display drafts).

**LANGUAGE**: JSON

**CODE**:
```json
{
  "EditingStatusFilterOption": "All (Hiding Drafts)",
  "InListReport": "Only saved objects with their respective data are displayed",
  "WhileNavigatingToObjectPage": "Saved object is displayed; shows 'Return to Draft' button if a draft exists",
  "NavigatingBackToList": "Only saved objects with their respective data are displayed"
}
```

**STEP**: 2 — Object Page: Saved Version / Draft toggle behavior and UI elements

**DESCRIPTION**: On the object page, when a draft exists for the current entity, a toggle control (labeled either "Saved Version / Draft" or contextually "Draft" / "Saved Version") is shown. This control opens a popover that lets the user switch between viewing/working on the saved version and the draft version. The label always indicates which version is currently active.

- UI assets (screenshots for reference are included in docs):
  - images/Toggling_Between_Draft_and_Saved_Values_1_6817734.png
  - images/Object_Page_Draft_Version_is_Shown_Including_Toggle_Popover_fbdd6a2.png
  - images/Object_Page_Saved_Version_is_Shown_4d6823f.png

- Typical interactions:
  1. Object page opens in Saved version (if navigated from "All (Hiding Drafts)"), and if a draft exists, a "Return to Draft" button or a "Saved Version / Draft" popover is available.
  2. Clicking the button opens the popover with options to switch to the Draft version.
  3. The page updates and the button label changes to reflect the active version.

**LANGUAGE**: PlainText

**CODE**:
```text
UI control: "Saved Version / Draft" (popover)
- Visible when a draft exists for the object.
- Popover contains options:
  - "Show Draft" or "Return to Draft"  -> switches page to draft version
  - "Show Saved Version"               -> switches page back to saved version
- Button label updates to indicate current version (e.g., "Draft" when showing draft)
```

**STEP**: 3 — Classic header behavior (OData V2 only)

**DESCRIPTION**: For SAP Fiori elements OData V2 apps that use the classic header, the toggle behavior is presented slightly differently: the header toolbar shows a "Display Saved Version / Return to Draft" button instead of a menu/button next to the object title. Ensure UI placement is handled accordingly when supporting the classic header layout.

**LANGUAGE**: PlainText

**CODE**:
```text
OData V2 (classic header):
- Toggle control placement: header toolbar
- Label examples: "Display Saved Version" / "Return to Draft"
- Behavior: same toggle functionality, different placement compared to object page title menu
```

**STEP**: 4 — Reference / Related information

**DESCRIPTION**: See the Draft Handling documentation for details on how drafts are created, managed, and persisted by the Fiori elements framework. Use this when implementing draft-enabled behavior or when validating business logic.

**LANGUAGE**: MarkdownLink

**CODE**:
```text
Related: Draft Handling
File: draft-handling-ed9aa41.md
Link title: Draft Handling
Description: A draft is an interim version of a business entity that has not yet been explicitly saved as an active version. SAP Fiori elements supports the creation of apps using draft handling.
```

fiori-elements-framework odata-v2 odata-v4 draft editing-status list-report object-page ui-behavior


**TITLE**: Toggling the Editability of Header Fields

**INTRODUCTION**: Enable or disable editability of fields in an Object Page header by setting the manifest property editableHeaderContent. This allows header fields to become editable when the overall page mode permits, while individual fields/facets still obey their own editability rules (for example, micro chart facets are never editable; fields marked ReadOnly remain read-only). Use the appropriate manifest location for SAP Fiori elements OData V2 vs OData V4.

**TAGS**: fiori-elements-framework, sapui5, manifest.json, object-page, header-editable, odata-v2, odata-v4

**STEP**: 1 — Concept & default behavior

**DESCRIPTION**: Set the manifest property editableHeaderContent to enable or disable header editability. Note platform defaults:
- OData V2: header is NOT editable by default — set editableHeaderContent: true to enable.
- OData V4: header IS editable by default — set editableHeaderContent: false to disable.
Remember: enabling header editability does not override individual field/facet settings (ReadOnly, non-editable facets like micro charts).

**LANGUAGE**: JSON

**CODE**:
```json
{
  "settings": {
    "editableHeaderContent": true
  }
}
```

**STEP**: 2 — SAP Fiori elements for OData V2: manifest sample

**DESCRIPTION**: Place the editableHeaderContent property in manifest.json under "sap.ui.generic.app" → pages → component → settings for the ObjectPage component. This sample shows enabling editable header content for the ObjectPage component definition.

**LANGUAGE**: JSON

**CODE**:
```json
"sap.ui.generic.app": {
        "pages": [
            {
                "entitySet": "SEPMRA_C_PD_Product",
                "component": {
                    "name": "sap.suite.ui.generic.template.ListReport",
                    "list": true
                },
                "pages": [
                    {
                        "entitySet": "SEPMRA_C_PD_Product",
                        "component": {
                            "name": "sap.suite.ui.generic.template.ObjectPage",
                            "settings": {
                                "editableHeaderContent": true
                            }
                        },
                        "pages": [
                            {
                                "navigationProperty": "to_ProductText",
                                "entitySet": "SEPMRA_C_PD_ProductText",
                                "component": {
                                    "name": "sap.suite.ui.generic.template.ObjectPage"
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    },
```

**STEP**: 3 — SAP Fiori elements for OData V4: manifest sample

**DESCRIPTION**: Place the editableHeaderContent property in manifest.json under "sap.ui5" → routing → targets → <target> → options → settings for the ObjectPage target. This sample shows enabling editable header content for a routing target that uses the sap.fe.templates.ObjectPage component.

**LANGUAGE**: JSON

**CODE**:
```json
"sap.ui5": {
        ...
        "routing": {
                ...
                {
                    "pattern": "SalesOrderManage({key})/_Item({key2}):?query:",
                    "name": "SalesOrderItemObjectPage",
                    "target": "SalesOrderItemObjectPage"
                }
            ],
            "targets": {
                "SalesOrderItemObjectPage": {
                    "type": "Component",
                    "id": "SalesOrderItemObjectPage",
                    "name": "sap.fe.templates.ObjectPage",
                    "options": {
                        "settings": {
                            "contextPath": "/SalesOrderItem",
                            "editableHeaderContent": true,
                            ...
                        }
                    }
                }
            }
        }
    }
```


**TITLE**: Tree Tables — Configuration and Extension Examples for SAP Fiori elements (OData V4)

**INTRODUCTION**: Action-oriented reference for enabling and customizing TreeTable behavior in SAP Fiori elements (OData V4). Includes manifest.json configuration examples, controller-extension callbacks for create/drag/copy/paste handling, backend annotation examples to disable hierarchy changes, and XML annotations to prevent root reordering.

**TAGS**: TreeTable, manifest.json, OData V4, SAP Fiori elements, controller extension, drag-and-drop, copy-paste, createMode, hierarchy, annotations

STEP: Prerequisites and Behavior Notes

DESCRIPTION: Requirements and runtime behavior to keep in mind before implementing TreeTable:
- Applicable only to SAP Fiori elements for OData V4.
- Draft-enabled service behavior:
  - Only active entities displayed.
  - Editing Status field hidden in filter bar.
  - Draft indicator shown if a draft exists for an active record.
  - New objects must be saved or discarded.
  - Existing saved objects behave unchanged with drafts.
- Expansion state is not preserved when switching between edit and display mode on an object page.
- Restriction: TreeTable cannot be displayed on the list report with a draft-enabled service in flexible column layout.

LANGUAGE: Text

CODE:
```text
Prerequisites:
- SAP Fiori elements (OData V4)
Notes:
- Draft-enabled service behavior (only active entities, draft indicator shown)
- Expansion state not preserved between edit/display on object page
Restriction:
- TreeTable not supported in List Report with draft-enabled service in flexible column layout
```

STEP: Enable TreeTable in manifest.json

DESCRIPTION: Configure the page's tableSettings to use a TreeTable and reference the hierarchy qualifier matching your Hierarchy.RecursiveHierarchy annotation on the page entity set.

LANGUAGE: JSON

CODE:
```json
"tableSettings": {
     "type": "TreeTable",
     "hierarchyQualifier": "NodesHierarchy",
   ...
}
```

STEP: Supported Create Modes

DESCRIPTION: TreeTable supports these create modes: Inline, NewPage, CreationDialog. On the List Report only NewPage and CreationDialog are supported. You can define a custom create menu by providing a nodeType configuration that maps a propertyName to values (value label mapping and optional creationFields).

LANGUAGE: JSON

CODE:
```json
"tableSettings": {
    "type": "TreeTable",
    "hierarchyQualifier": "NodesHierarchy",
    "personalization": true,
    "creationMode": {
         "name": "Inline",
         "nodeType": {
            "propertyName": "nodeType",
            "values": {
                "Zone": "Create a new Zone",
                "Intermediary": "Create a new Intermediary node",
                "Line": "Create a new Line item"
             }
         },
         "isCreateEnabled": ".extension.hierarchy-edit.custom.OPExtend.enableCreate"
     }
}
```

STEP: Custom Create Mode — Create Dialog Example

DESCRIPTION: Example showing creationFields per node type. The creationFields may reference FieldGroup annotations or a comma-separated list of properties.

LANGUAGE: JSON

CODE:
```json
"tableSettings": {
    "type": "TreeTable",
    "hierarchyQualifier": "NodesHierarchy",
    "personalization": true,
    "creationMode": {
        "name": "CreationDialog",
        "creationFields": "Title",
        "nodeType": {
            "propertyName": "nodeType",
            "values": {
                "Zone": "Create a new Zone",
                "Intermediary": {
                    "label": "Create a new Intermediary node",
                    "creationFields": "Category",},
                "Line": "Create a new Line item"
            }
        },
        "isCreateEnabled": ".extension.hierarchy-edit.custom.OPExtend.enableCreate"
    }
}
```

STEP: Control Create Button Enablement with ControllerExtension

DESCRIPTION: Implement an extension callback referenced by isCreateEnabled. The callback receives (value, parentContext):
- value: the menu item value (null for standard create mode).
- parentContext: the parent binding context under which the new node would be created (undefined for root-level creation).
Use this callback to enable/disable create options per parent/node type.

LANGUAGE: JavaScript

CODE:
```javascript
sap.ui.define(["sap/ui/core/mvc/ControllerExtension"], function (ControllerExtension) {
    "use strict";

    return ControllerExtension.extend("hierarchy-edit.custom.OPExtend", {
        // this section allows to extend lifecycle hooks or override public methods of the base controller

        //Callback to enable Create actions
        enableCreate: function (value, parentContext) {
            switch (parentContext?.getProperty("nodeType")) {
                case "Zone":
                    return value !== "Zone"; // Anything but 'Zone' under 'Zone'

                case "Intermediary":
                    return value === "Line"; // Only 'Line' under 'Intermediary'

                case "Line":
                    return false; // Nothing under 'Line'

                default:
                    return value === "Zone"; // Only 'Zone' at root level
            }
        }
    }
}
)
```

STEP: Create In-Place (server-calculated position)

DESCRIPTION: Use createInPlace to have the backend determine the new node's position relative to siblings and sorting. If the new node is filtered out, a message toast appears (note exceptions in flexible column layout).

LANGUAGE: JSON

CODE:
```json
"tableSettings": {
    "type": "TreeTable",
    "hierarchyQualifier": "NodesHierarchy",
    "personalization": true,
    "creationMode": {
        "name": "Inline",
        "createInPlace": true,
        "nodeType": {
            "propertyName": "nodeType",
            "values": {
                "Zone": "Create a new Zone",
                "Intermediary": "Create a new Intermediary node",
                "Line": "Create a new Line item"
            }
        },
        "isCreateEnabled": ".extension.hierarchy-edit.custom.OPExtend.enableCreate"
    }
}
```

STEP: Enable Drag and Drop via manifest.json

DESCRIPTION: Reference controller-extension callbacks for:
- isMoveToPositionAllowed(sourceContext, parentContext): returns boolean whether source can be dropped under parent (parentContext === null for root).
- isNodeMovable(sourceContext): returns boolean whether node can be dragged/cut.

LANGUAGE: JSON

CODE:
```json
"tableSettings": {
    "type": "TreeTable",
    "hierarchyQualifier": "NodesHierarchy",
    "personalization": true,
    "creationMode": {...},
    "isMoveToPositionAllowed": ".extension.hierarchy-edit.custom.OPExtend.moveToPositionAllowed",
    "isNodeMovable": ".extension.hierarchy-edit.custom.OPExtend.nodeMovable"
}
```

STEP: Implement Drag-and-Drop Callbacks (ControllerExtension)

DESCRIPTION: Example callbacks implementing move-to-position and nodeMovable rules. Use context.getProperty(...) to inspect nodeType or other properties to permit/deny operations.

LANGUAGE: JavaScript

CODE:
```javascript
sap.ui.define(["sap/ui/core/mvc/ControllerExtension"], function (ControllerExtension) {
    "use strict";

    return ControllerExtension.extend("hierarchy-edit.custom.OPExtend", {
        // this section allows to extend lifecycle hooks or override public methods of the base controller

        //Callback for Drop and Paste actions
        moveToPositionAllowed: function (sourceContext, parentContext) {
            switch (parentContext?.getProperty("nodeType")) {
                case "Zone":
                    return sourceContext?.getProperty("nodeType") === "Intermediary"; //Only 'Intermediary' under a 'Zone'

                case "Intermediary":
                    return  sourceContext?.getProperty("nodeType") === "Line" && sourceContext?.getProperty("name") !== 'Dublin'; // Only 'Line' under 'Intermediary' AND 'Dublin' node cannot be moved

                case "Line":
                    return false; // Nothing under 'Line'

                default:
                    return false;
            }
        },

        //Callback for Drag and Cut actions
        nodeMovable: function (sourceContext) {
            return sourceContext?.getProperty("name") !== 'USA'; // 'USA' node cannot be moved or cut
        }
    });
});
```

STEP: Move Up / Move Down (Behavior and Restrictions)

DESCRIPTION: Move Up/Down between siblings is supported if ChangeNextSiblingAction is defined in RecursiveHierarchyActions annotation. Restrictions that disable move up/down:
- Node created without createInPlace (displayed as first child) → considered out-of-place.
- A sort is applied to the table.
- isNodeMovable or isMoveToPositionAllowed returns false.
- When using RAP, ChangeNextSiblingAction may not be set for root entities, disabling move for root-level nodes.

LANGUAGE: Text

CODE:
```text
Move Up/Down requirements:
- RecursiveHierarchyActions.ChangeNextSiblingAction must be defined.
Disabled when:
- Node is "out of place" (no createInPlace)
- Table has active sort
- isNodeMovable or isMoveToPositionAllowed returns false
- For RAP root entities ChangeNextSiblingAction might not be set (no root moves)
```

STEP: Cut and Paste (Enablement)

DESCRIPTION: Cut (move) and paste use the same extension points as drag & drop:
- isNodeMovable(sourceContext) — controls cut ability.
- isMoveToPositionAllowed(sourceContext, parentContext) — controls paste destination.

LANGUAGE: Text

CODE:
```text
Cut and Paste extension points:
- isNodeMovable(sourceContext) => boolean (controls Cut)
- isMoveToPositionAllowed(sourceContext, parentContext) => boolean (controls Paste destination)
Note: When pasting, final position under parent is determined by backend logic.
```

STEP: Copy and Paste (Enablement and manifest.json)

DESCRIPTION: Copy/paste uses dedicated extension points:
- isNodeCopyable(sourceContext): allow copying.
- isCopyToPositionAllowed(sourceContext, parentContext): allow pasting copied node under parent.

LANGUAGE: JSON

CODE:
```json
"tableSettings": {
    "type": "TreeTable",
    "hierarchyQualifier": "NodesHierarchy",
    "personalization": true,
    "creationMode": {...},
    "isNodeCopyable": ".extension.hierarchy-edit.custom.OPExtend.enableCopy",
    "isCopyToPositionAllowed": ".extension.hierarchy-edit.custom.OPExtend.enablePasteFromCopy"
}
```

STEP: Context Menu Behavior

DESCRIPTION: Context menu (right-click) shows bound actions for the selected node; other nodes are greyed out. Tree-specific actions (cut/paste/expand entire/collapse entire) are not supported with multi-selection.

LANGUAGE: Text

CODE:
```text
Context menu:
- Right-click on a node opens context menu with bound actions.
- Other nodes greyed out.
- Tree-specific actions not supported for multi-selection.
```

STEP: Disable Hierarchy Change Operations via Backend Annotations

DESCRIPTION: Use backend annotations (UpdateRestrictions and NonUpdatableNavigationProperties) on the navigation property to the parent to disable drag/drop/cut/paste reordering. Example uses CDS-like entity with a Superordinate association and annotates NonUpdatableNavigationProperties.

LANGUAGE: CDS

CODE:
```c
@odata.draft.enabled
  entity TreeTableSubEntityWithUpdateRestriction {
        @Core.Immutable: true
        @Common.Label  : 'ID'
    key ID               : String;
        parent           : String;

        @Common.Label  : 'Org level name'
        name             : String;

        @UI.Hidden     : true
        orgID            : String;

        @Core.Computed : true
        @UI.Hidden     : true
        DistanceFromRoot : Integer64;

        Superordinate    : Association to TreeTableSubEntityWithUpdateRestriction
                             on Superordinate.ID = parent;
        Organization     : Association to TreeTableEntity
                             on Organization.ID = orgID;
  }

  annotate TreeTableSubEntityWithUpdateRestriction with @(Capabilities: {UpdateRestrictions: {NonUpdatableNavigationProperties: [Superordinate]}});
```

STEP: Prevent Reordering of Root Nodes (XML Annotation)

DESCRIPTION: Use ChangeSiblingForRootsSupported in RecursiveHierarchyActions to prevent reordering root nodes. If set to false:
- Users cannot move root nodes up/down or drop a node as a root between other root nodes.
If not defined, defaults to true.

LANGUAGE: XML

CODE:
```xml
<edmx:Reference Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_HIERARCHY',Version='0001',SAP__Origin='LOCAL')/$value">
  <edmx:Include Namespace="com.sap.vocabularies.Hierarchy.v1" Alias="SAP__hierarchy"/>
</edmx:Reference>

<Annotations Target="SAP__self.HierarchyEntityType">
  <Annotation Term="SAP__hierarchy.RecursiveHierarchyActions" Qualifier="HierarchyNode">
    <Record>
      <PropertyValue Property="ChangeNextSiblingAction" String="SAP__self.changeNextSibling"/>
      <PropertyValue Property="CopyAction" String="SAP__self.copy"/>
      <PropertyValue Property="ChangeSiblingForRootsSupported" Bool="false"/>
    </Record>
  </Annotation>
</Annotations>
```

STEP: TreeTable Building Block Reference

DESCRIPTION: Use sap.fe.macros.TreeTable building block for advanced usages and consult the API and building-block examples for live demos.

LANGUAGE: Text

CODE:
```text
References:
- API: sap.fe.macros.TreeTable (see SAPUI5 API reference)
- Live examples: SAP Fiori development portal Building Blocks - Table - Tree Table
```

TreeTable
manifest.json
OData V4
SAP Fiori elements
controller extension
drag-and-drop
copy-paste
createMode
hierarchy
annotations


**TITLE**: OVP Card Types and manifest.json Configuration (SAP Fiori Elements)

**INTRODUCTION**: Quick reference for available OVP (Overview Page) card types, when to use each, and how to configure global OVP settings (including auto-refresh) in manifest.json. Includes additional card types available for SAP Fiori Elements with OData V2.

**TAGS**: fiori-elements, ovp, cards, manifest.json, sap.ovp, OData V2, analytical-charts, refreshIntervalInMinutes

**STEP**: 1 — Core Card Types and key properties

**DESCRIPTION**: Use these card types based on the data and UX requirement. Key configuration pointers:
- Table and List cards rely on the OData UI annotation com.sap.vocabularies.UI.v1.LineItem.
  - Table: renders a 3-column table layout.
  - List: renders list items with up to six fields each.
- Analytical Chart cards support many chart formats (line, bubble, donut, column, stacked/vertical column, combination, scatter). Set template to sap.ovp.cards.charts.analytical.
- Link List displays links with an image/icon and optional subtitle.

Include these minimal properties inside a card definition:
- template — identifies the OVP card component.
- annotationPath — typically points to the LineItem annotation for transactional cards.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "cards": {
    "SalesTable": {
      "template": "sap.ovp.cards.table",
      "annotationPath": "com.sap.vocabularies.UI.v1.LineItem"
    },
    "SalesChart": {
      "template": "sap.ovp.cards.charts.analytical",
      "annotationPath": "com.sap.vocabularies.UI.v1.Chart"
    },
    "QuickLinks": {
      "template": "sap.ovp.cards.linkList"
    }
  }
}
```

**STEP**: 2 — Configure global OVP settings and auto-refresh in manifest.json

**DESCRIPTION**: Place global OVP settings under the "sap.ovp" section in manifest.json. To enable card auto-refresh, set refreshIntervalInMinutes. The minimum and default refresh interval is 1 minute. The sample manifest snippet below shows common global keys (preserve the exact property names and values as needed). Use refreshIntervalInMinutes (integer minutes) to control automatic refresh across cards.

File path: manifest.json (project root)

**LANGUAGE**: JSON

**CODE**:
```json
"sap.ovp": {
    "globalFilterModel": "salesOrder",
    "globalFilterEntityType": "GlobalFilters", // Deprecated since SAPUI5 1.54.
    "globalFilterEntitySet": "GlobalFilters", // Available from SAPUI5 1.54.
    ...
    "refreshIntervalInMinutes": 12,
    "disableTableCardFlexibility": false,
    "cards": {
        ...
    }
}
```

**STEP**: 3 — Additional card types available for SAP Fiori Elements (OData V2)

**DESCRIPTION**: When using SAP Fiori Elements for OData V2, these additional card types are supported:
- Stack: aggregates a set of cards of the same type (common topic/action). Clicking a stack can display up to 20 cards in an object stream.
- Quick View: shows detailed information for a single record (deeper than list/table item).

Include these templates in card definitions for OData V2 scenarios.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "cards": {
    "CustomerStack": {
      "template": "sap.ovp.cards.stack",
      "annotationPath": "com.sap.vocabularies.UI.v1.LineItem"
    },
    "CustomerQuickView": {
      "template": "sap.ovp.cards.quickview",
      "annotationPath": "com.sap.vocabularies.UI.v1.FieldGroup"
    }
  }
}
```

fiori-elements
ovp
cards
manifest.json
sap.ovp
OData V2
analytical-charts
refreshIntervalInMinutes


**TITLE**: Using UI Controls in Object Page Header (Fiori Elements Annotations)

**INTRODUCTION**: This guide shows how to add UI controls to an Object Page header in SAP Fiori Elements by using OData annotations. It provides ready-to-use XML annotation examples for HeaderInfo (title, description, image), Identification (fields shown in header) and header-level actions (intent-based navigation). Use these snippets in your annotation file and reference it from the app manifest.

**TAGS**: fiori-elements, annotations, object-page, header, ui.headerinfo, ui.identification, xml, manifest

STEP: 1 — Define Header Info (title, description, image, type)
DESCRIPTION: Create an annotations XML that sets the header title, description, type name and image for the Object Page header using the UI.HeaderInfo annotation. Replace the Target with your service/entity type and adjust Paths to match your model properties.
LANGUAGE: XML
CODE:
```xml
<?xml version="1.0" encoding="utf-8"?>
<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm"
             Target="MyService.PurchaseOrderType">
  <!-- Header info: Title, Description, TypeName and ImageUrl -->
  <Annotation Term="UI.HeaderInfo">
    <Record>
      <PropertyValue Property="TypeName" String="Purchase Order"/>
      <PropertyValue Property="Title" Path="PurchaseOrderID"/>
      <PropertyValue Property="Description" Path="SupplierName"/>
      <PropertyValue Property="ImageUrl" Path="SupplierLogoURL"/>
      <!-- Optional: keywords for search or semantic -->
      <PropertyValue Property="Keywords">
        <Collection>
          <String>Purchase</String>
          <String>Order</String>
        </Collection>
      </PropertyValue>
    </Record>
  </Annotation>
</Annotations>
```

STEP: 2 — Add Identification Fields (fields shown in header block)
DESCRIPTION: Add UI.Identification to list the key data fields that appear in the object page header (the compact field list next to the title). Use UI.DataField records with Label + Value Path. Replace Path values to match your properties.
LANGUAGE: XML
CODE:
```xml
<?xml version="1.0" encoding="utf-8"?>
<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm"
             Target="MyService.PurchaseOrderType">
  <Annotation Term="UI.Identification">
    <Collection>
      <Record Type="UI.DataField">
        <PropertyValue Property="Label" String="PO Number"/>
        <PropertyValue Property="Value" Path="PurchaseOrderID"/>
      </Record>
      <Record Type="UI.DataField">
        <PropertyValue Property="Label" String="Status"/>
        <PropertyValue Property="Value" Path="Status"/>
      </Record>
      <Record Type="UI.DataField">
        <PropertyValue Property="Label" String="Ordered On"/>
        <PropertyValue Property="Value" Path="OrderDate"/>
      </Record>
    </Collection>
  </Annotation>
</Annotations>
```

STEP: 3 — Define Header Actions (intent-based navigation)
DESCRIPTION: Add action controls to the header (shown as header buttons) using UI.DataFieldForIntentBasedNavigation. This example creates an intent-based action button. Replace SemanticObject and Action with your intent values.
LANGUAGE: XML
CODE:
```xml
<?xml version="1.0" encoding="utf-8"?>
<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm"
             Target="MyService.PurchaseOrderType">
  <Annotation Term="UI.HeaderFacets">
    <Collection>
      <Record Type="UI.ReferenceFacet">
        <PropertyValue Property="Label" String="Actions"/>
        <PropertyValue Property="Target">
          <AnnotationPath>UI.HeaderActions</AnnotationPath>
        </PropertyValue>
      </Record>
    </Collection>
  </Annotation>

  <!-- Define the actions referenced above -->
  <Annotation Term="UI.HeaderActions">
    <Collection>
      <Record Type="UI.DataFieldForIntentBasedNavigation">
        <PropertyValue Property="Label" String="Manage"/>
        <PropertyValue Property="SemanticObject" String="PurchaseOrder"/>
        <PropertyValue Property="Action" String="manage"/>
      </Record>

      <!-- Example of a simple action (non-intent) -->
      <Record Type="UI.DataFieldForAction">
        <PropertyValue Property="Label" String="Approve"/>
        <PropertyValue Property="Action" String="ApprovePO"/>
        <PropertyValue Property="Inline" Bool="false"/>
      </Record>
    </Collection>
  </Annotation>
</Annotations>
```

STEP: 4 — Place the annotation file in your Fiori Elements project
DESCRIPTION: Save the XML annotation file in your UI project (e.g., webapp/annotations/Annotations.xml). Then reference it in manifest.json so the Fiori Elements app loads the annotations.
LANGUAGE: JSON
CODE:
```json
{
  "sap.app": {
    "id": "my.app.id",
    "applicationVersion": {
      "version": "1.0.0"
    }
  },
  "sap.ui5": {
    "models": {
      "": {
        "dataSource": "mainService"
      }
    },
    "resources": {
      "js": [],
      "css": []
    }
  },
  "sap.ui5": {
    "models": {
      "i18n": {
        "type": "sap.ui.model.resource.ResourceModel",
        "settings": {
          "bundleName": "my.app.i18n.i18n"
        }
      }
    },
    "annotationFiles": [
      "annotations/Annotations.xml"
    ]
  }
}
```

STEP: 5 — Verify and adjust for your service/entity
DESCRIPTION: Ensure the Annotation Target points to the correct EntityType (namespace.EntityType). Confirm property Paths (Title, Description, ImageUrl, identification fields) match your OData metadata. If using CDS annotations, adapt the values to the CDS syntax but keep the same semantic properties (HeaderInfo, Identification, HeaderFacets / HeaderActions).

fiori-elements annotations object-page header ui.headerinfo ui.identification xml manifest


**TITLE**: Using a Custom Root View (Fiori Elements / UI5)

**INTRODUCTION**: When the built-in root views (NavContainer or FlexibleColumnLayout) do not meet your app's requirements, create a custom root view and register it so it is loaded when the application starts. This document provides concrete, minimal code examples and registration options for implementing a custom root view in a UI5 / Fiori Elements app.

**TAGS**: fiori-elements-framework, ui5, root-view, custom-root-view, navcontainer, flexiblecolumnlayout, manifest

**STEP**: 1 — Create the custom root view (XML) and controller

**DESCRIPTION**: Create an XML view file and a matching controller. Place these files under your app's webapp folder (example paths shown). The XML view must be a top-level view that hosts your application layout and content.

**LANGUAGE**: XML

**CODE**:
```xml
<!-- File: webapp/view/Root.view.xml -->
<mvc:View
  controllerName="my.app.controller.Root"
  xmlns:mvc="sap.ui.core.mvc"
  xmlns="sap.m"
  displayBlock="true">
  <App id="app">
    <pages>
      <Page id="rootPage" title="My App Root">
        <content>
          <Text text="This is the custom root view" />
        </content>
      </Page>
    </pages>
  </App>
</mvc:View>
```

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// File: webapp/controller/Root.controller.js
sap.ui.define([
  "sap/ui/core/mvc/Controller"
], function (Controller) {
  "use strict";

  return Controller.extend("my.app.controller.Root", {
    onInit: function () {
      // Initialization logic for the custom root view
    }
  });
});
```

**STEP**: 2 — Register the custom root view via manifest (recommended for standard UI5 apps)

**DESCRIPTION**: Add a rootView entry to the sap.ui5 section of manifest.json so UI5 instantiates your view on bootstrap. Adjust viewName and type to match your view.

**LANGUAGE**: JSON

**CODE**:
```json
// File: webapp/manifest.json (snippet)
{
  "sap.ui5": {
    "rootView": {
      "viewName": "my.app.view.Root",
      "type": "XML",
      "id": "app"
    }
  }
}
```

**STEP**: 3 — Alternative registration via index.html bootstrap

**DESCRIPTION**: If you prefer to bootstrap and instantiate the view/component explicitly in index.html, create a ComponentContainer or instantiate the view in the UI5 bootstrap callback. This is an alternative to manifest-based rootView registration.

**LANGUAGE**: HTML

**CODE**:
```html
<!-- File: webapp/index.html (snippet) -->
<script id="sap-ui-bootstrap"
  src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
  data-sap-ui-theme="sap_fiori_3"
  data-sap-ui-resourceroots='{"my.app": "./"}'>
</script>
<script>
  sap.ui.getCore().attachInit(function () {
    // Option A: instantiate the manifest-driven component
    new sap.ui.core.ComponentContainer({
      name: "my.app",
      settings: { id: "app" },
      async: true
    }).placeAt("content");

    // Option B: instantiate the view directly (not recommended for component-based apps)
    // sap.ui.xmlview({ viewName: "my.app.view.Root" }).placeAt("content");
  });
</script>
```

**STEP**: 4 — Integrate with Fiori Elements / framework behaviour

**DESCRIPTION**: If your project uses the Fiori Elements framework or a standard shell, ensure your custom root view provides or instantiates the expected hosting container(s) and navigation handling that the app requires (for example, App/NavContainer or FCL behavior). Use the view to embed or replace NavContainer / FlexibleColumnLayout as needed.

**LANGUAGE**: Notes / Link

**CODE**:
```text
- If replacing NavContainer or FlexibleColumnLayout, make sure your custom root view offers equivalent navigation & layout controls.
- For concrete examples and patterns, see the SAP Fiori Development Portal example:
  https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/guidance/guidanceOwnRootView
- For general app structure, see: App Overview: The Basic Files of Your App (docs)
```

**STEP**: 5 — Verify and test startup behavior

**DESCRIPTION**: Build and run the app. Confirm the custom root view is loaded on app start and that navigation, routing, and shell integration behave as expected. Inspect browser console for bootstrap/manifest/view instantiation errors and fix viewName/resource path mismatches.

**LANGUAGE**: Notes

**CODE**:
```text
- Common checks:
  - Ensure webapp/manifest.json resource paths and data-sap-ui-resourceroots match your module names.
  - Verify controller names and file paths (my.app.controller.Root -> webapp/controller/Root.controller.js).
  - Confirm the bootstrap script references the correct SAPUI5 library version.
```

fiori-elements-framework ui5 root-view custom-root-view navcontainer flexiblecolumnlayout manifest


**TITLE**: Action Control for Context-Dependent Actions (SAP Fiori Elements)

**INTRODUCTION**: Use action control to conditionally show, enable, or disable app-specific actions based on the runtime context of an entity instance. For OData V2, add sap:action-for and sap:applicable-path to function imports/actions. For OData V4, use the OperationAvailable annotation. These annotations let the UX enable actions only when the specified Boolean condition on the entity is met.

**TAGS**: fiori-elements-framework, odata-v2, odata-v4, annotations, action-control, sap:action-for, sap:applicable-path, OperationAvailable, FunctionImport, UI.Hidden

**STEP**: 1 — Configure context-dependent actions (OData V2)

**DESCRIPTION**: Add sap:action-for and sap:applicable-path attributes to a FunctionImport (or action) in your OData V2 service metadata (EDMX). Set sap:applicable-path to the Boolean property on the entity type that controls whether the action is allowed for the selected instance. Actions annotated this way are context-dependent: users must select a list item/row for the action to be enabled.

Behavior rules:
- If the applicable-path condition (Boolean) is false, the action is:
  - Hidden when it is on a page header level or is a line-item button in a table.
  - Disabled when it is a header button in a table.
- Do NOT rely on UI.Hidden for DataFieldForAction in page headers — UI.Hidden takes precedence and can deviate from recommended UX behavior.
- If function import action parameters are dynamic and no parameter is required for the selected instance, the parameter dialog will not be shown (applies only to single-context select actions).

**LANGUAGE**: XML

**CODE**:
```xml
<FunctionImport Name="SEPMRA_C_PD_ProductCopy"
                ReturnType="SEPMRA_PROD_MAN.SEPMRA_C_PD_ProductType"
                EntitySet="SEPMRA_C_PD_Product" m:HttpMethod="POST"
                sap:action-for="SEPMRA_PROD_MAN.SEPMRA_C_PD_ProductType"
                sap:applicable-path="IsActiveEntity">
    <Parameter Name="ProductDraftUUID" Type="Edm.Guid" Mode="In"/>
    <Parameter Name="ActiveProduct" Type="Edm.String" Mode="In" MaxLength="10"/>
</FunctionImport>
```

**STEP**: 2 — Configure action control (OData V4)

**DESCRIPTION**: Use the OperationAvailable annotation to control availability of custom actions in OData V4. OperationAvailable should evaluate to a Boolean expression or path on the entity type; actions are enabled/disabled based on that evaluation. If a table allows multi-select, the action is allowed when at least one selected entry fulfills the condition.

For implementation details and examples, see the "Enabling Custom Actions Defined Using Annotations" section in the Actions documentation:
- actions-cbf16c5.md#loiocbf16c599f2d4b8796e3702f7d4aae6c__subsection_xkx_gwq_nsb

**LANGUAGE**: (annotation concept) JSON/XML (use appropriate annotation syntax for OData V4)

**CODE**:
```xml
<!-- Example (conceptual) of using OperationAvailable in OData V4 annotations -->
<Annotations Target="Namespace.EntityType/SomeAction">
  <Annotation Term="Org.OData.Capabilities.V1.OperationAvailable" Path="IsAllowedProperty"/>
</Annotations>
```

```json
// Example (conceptual) using JSON annotation format (V4)
{
  "annotations": {
    "Namespace.EntityType": {
      "SomeAction": {
        "Org.OData.Capabilities.V1.OperationAvailable": {
          "Path": "IsAllowedProperty"
        }
      }
    }
  }
}
```

**STEP**: 3 — Selection and multi-select behavior (applies to V2 & V4)

**DESCRIPTION**: Actions annotated with applicable-path/OperationAvailable are context-dependent:
- Users must select an item or row to enable single-context actions.
- For multi-select tables, the action is allowed if at least one selected entry satisfies the condition defined by the applicable-path or OperationAvailable annotation.

**LANGUAGE**: N/A

**CODE**:
```text
Behavior summary:
- Single-select: action enabled only if selected instance's Boolean property (applicable-path/OperationAvailable) is true.
- Multi-select: action allowed when >=1 selected instance meets the condition.
- UI.Hidden overrides sap:applicable-path for DataFieldForAction in page headers (not recommended).
```

fiori-elements-framework odata-v2 odata-v4 annotations action-control sap:action-for sap:applicable-path OperationAvailable FunctionImport UI.Hidden


**TITLE**: Enable and Use Back-End Analytical Parameters in SAP Fiori Elements (OData V2)

**INTRODUCTION**: Configure your Fiori Elements app to pass analytical parameters from the UI to the back end so the back end can normalize/aggregate data (for example, currency conversions). When enabled, the framework automatically exposes filters for analytical parameters in the list report and object page; those filters become mandatory and the UI data updates according to the provided values.

**TAGS**: fiori-elements-framework, odata-v2, analytical-parameters, manifest.json, sapui5, list-report, object-page

**STEP**: 1 — Understand the purpose of analytical parameters

**DESCRIPTION**: Analytical parameters are key/value pairs passed directly to the OData back end (not part of $filter) that influence back-end processing at runtime. Use them when back-end data requires a normalization step (for example currency or unit-of-measure conversions) without changing stored data. The back end receives the parameter and performs conversion/aggregation before returning results to the UI.

**LANGUAGE**: text

**CODE**:
```text
Sample OData request that passes an analytical parameter (DisplayCurrency) directly to the back end:
http://<path>/Customer(P_DisplayCurrency='EUR')/Set?$count=true
```

**STEP**: 2 — Enable analytical parameter handling in manifest.json

**DESCRIPTION**: Set the considerAnalyticalParameters flag to true inside the sap.ui.generic.app.settings section of your manifest.json. This instructs the Fiori Elements framework to create mandatory filter UI controls for analytical parameters automatically and to pass the parameter values to the back end. Update manifest.json, rebuild/deploy the app, and test the List Report or Object Page.

- File: manifest.json
- Location: root of your UI project

**LANGUAGE**: JSON

**CODE**:
```json
"sap.ui.generic.app": {
           "_version": "1.3.0",
           "settings": {
                "considerAnalyticalParameters": true,
                "forceGlobalRefresh": true,
                "inboundParameters": {
                              "Supplier": {
                                    "useForCreate": true
                                          }
                                     },
                "objectPageDynamicHeaderTitleWithVM": true
                       },
}
```

**STEP**: 3 — Expected behavior in the UI and back end

**DESCRIPTION**: After enabling considerAnalyticalParameters:
- The framework injects filters for the analytical parameters into the List Report filter bar.
- These filters are treated as mandatory by the framework.
- When a user sets a parameter value (for example, EUR for currency), the framework sends that value directly to the back end (as a parameter) in OData requests. The back end performs conversions/aggregations and returns the normalized results to the UI.

**LANGUAGE**: text

**CODE**:
```text
Behavior summary:
- UI: Mandatory filter controls are generated automatically for analytical parameters.
- Transfer: Parameter values are sent as OData parameter key/value pairs (not part of $filter).
- Back end: Receives the parameter and returns processed (e.g., converted/aggregated) data.
```

**STEP**: 4 — Testing and verification

**DESCRIPTION**: Verify end-to-end behavior:
1. Edit manifest.json to set considerAnalyticalParameters: true and deploy the app.
2. Open List Report or Object Page: confirm additional filter controls appear and are mandatory.
3. Set a parameter (e.g., DisplayCurrency = EUR) and trigger data load.
4. Inspect network/OData request to confirm parameter is sent as part of the entity call (see STEP 1 URL format).
5. Verify returned data reflects backend normalization (e.g., all amounts converted to EUR).

**LANGUAGE**: text

**CODE**:
```text
Testing checklist:
- manifest.json updated and app redeployed
- Filter controls for analytical params are visible and mandatory
- Network request contains parameter (pattern: /Entity(P_ParamName='Value')/Action?$...)
- Data in UI reflects backend conversion/aggregation
```

**STEP**: 5 — Reference / further reading

**DESCRIPTION**: See additional Fiori Elements documentation for OData V4 parameterized entities and filter bar configuration when adapting or comparing behavior across OData versions.

**LANGUAGE**: text

**CODE**:
```text
Related link:
- Supporting Parameterized Entities (Configuring Filter Bars) (OData V4)
  Refer to: configuring-filter-bars-4bd7590.md#loio4bd7590569c74c61a0124c6e370030f6__suppprting_parameterized_entities_subsection
```


**TITLE**: Using Custom Code Before Standard Operations (SAP Fiori elements OData V4)

**INTRODUCTION**: Short, actionable guide for implementing onBefore extension methods in SAP Fiori elements (OData V4). Shows how to add custom code that runs before standard create/edit/save/discard/delete flows, how to wrap code with securedExecution (for messages and state-changing scenarios), and how to register controller extensions in the manifest.

**TAGS**: fiori-elements, sap-fe, odata-v4, controller-extension, onBeforeCreate, onBeforeEdit, onBeforeSave, onBeforeDiscard, onBeforeDelete, securedExecution, manifest

**STEP**: 1 — Supported onBefore extension methods and behavior

**DESCRIPTION**: Use these onBefore extension method hooks to run custom code before the framework invokes the standard flow. These hooks apply only to SAP Fiori elements for OData V4 and may return a Promise — rejecting the Promise cancels the standard flow.

- onBeforeCreate — triggered before the standard create method
- onBeforeEdit — triggered before the standard edit flow
- onBeforeSave — triggered before the standard save method
- onBeforeDiscard — triggered before the standard draft discard
- onBeforeDelete — triggered before the standard delete (object page) or invoked for each selected context (list/table)

If your custom code displays messages or changes the document state, wrap it with securedExecution and set updatesDocument: true so Fiori elements can show the confirmation popover and allow discard if user navigates away.

**LANGUAGE**: Text

**CODE**:
```text
Signature examples (each can be synchronous or return a Promise):
- onBeforeCreate(oContext) => void | Promise
- onBeforeEdit(oContext) => void | Promise
- onBeforeSave(oContext) => void | Promise
- onBeforeDiscard(oContext) => void | Promise
- onBeforeDelete(oContext | aContexts) => void | Promise

Note: Returning a rejected Promise cancels the standard operation.
```

**STEP**: 2 — Implement a controller extension with onBefore methods (JavaScript AMD module)

**DESCRIPTION**: Create a controller extension module that exports the onBefore* handlers. Use this.securedExecution when showing messages or when changing document state. Handlers must either complete (resolve) to continue the standard flow, or reject/call throw to prevent it.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// webapp/extension/ObjectPageExtension.js
sap.ui.define([], function () {
	"use strict";
	return {
		// Example: called before creating a new entity instance
		onBeforeCreate: function (oContext) {
			// synchronous check
			if (!this._isUserAllowedToCreate()) {
				// cancel create by returning a rejected Promise
				return Promise.reject(new Error("User not allowed to create"));
			}
			// async example: return a Promise that resolves when done
			return Promise.resolve();
		},

		// Example: called before edit
		onBeforeEdit: function (oContext) {
			// Example: log or set a custom flag, then continue
			this._logEditIntent(oContext);
			return Promise.resolve();
		},

		// Example: called before save
		onBeforeSave: function (oContext) {
			// Validate local fields synchronously or asynchronously
			const bIsValid = this._validateFields(oContext);
			if (!bIsValid) {
				return Promise.reject(new Error("Validation failed"));
			}
			return Promise.resolve();
		},

		// Example: called before discard (draft discard)
		onBeforeDiscard: function (oContext) {
			// Optionally perform cleanup before discard
			return Promise.resolve();
		},

		// Example: called before delete (object page) or for each selected table context
		onBeforeDelete: function (oContextOrArray) {
			// If custom logic should block deletion:
			const canDelete = this._checkBusinessRulesForDelete(oContextOrArray);
			if (!canDelete) {
				return Promise.reject(new Error("Delete blocked by business rule"));
			}
			return Promise.resolve();
		},

		/* Helper methods (illustrative) */
		_isUserAllowedToCreate: function () {
			// custom logic
			return true;
		},
		_logEditIntent: function (oContext) {
			// custom logic
		},
		_validateFields: function (oContext) {
			// custom validation
			return true;
		},
		_checkBusinessRulesForDelete: function (oContext) {
			// custom check
			return true;
		}
	};
});
```

**STEP**: 3 — Use securedExecution to show messages or change document state

**DESCRIPTION**: When your custom code displays messages or mutates the document state, wrap it with securedExecution. Set options.updatesDocument = true to let Fiori elements present a confirmation popover (discard/keep) when the user navigates away. Use options.busy to show busy indicator if needed.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example inside the controller extension module methods
onBeforeSave: function (oContext) {
	// securedExecution provided by the framework for safe message handling and state updates
	return this.securedExecution(async () => {
		// perform async checks, set fields, show messages, etc.
		const valid = await this._asyncValidate(oContext);
		if (!valid) {
			// Throw or return a rejected Promise to cancel save
			throw new Error("Validation failed in securedExecution");
		}
		// Modify context/document fields if required
		// this.getView().getModel().setProperty("/SomeField", "value");

		// If everything is ok, resolve to continue the standard save flow
	}, {
		busy: true,
		updatesDocument: true // important if the code changes document state
	});
},

_asyncValidate: function (oContext) {
	// simulate async validation
	return new Promise(function (resolve) {
		setTimeout(function () { resolve(true); }, 100);
	});
}
```

**STEP**: 4 — Register your controller extension in manifest.json

**DESCRIPTION**: Register the controller extension(s) for the template(s) you extend (ObjectPage, ListReport, etc.). The keys under sap.ui.controllerExtensions are the Fiori elements controllers (e.g., sap.fe.templates.ObjectPage). Provide mappings to your extension module name.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "sap.ui5": {
    "extends": {
      "extensions": {
        "sap.ui.controllerExtensions": {
          "sap.fe.templates.ObjectPage": {
            "controllerName": "my.app.extension.ObjectPageExtension"
          },
          "sap.fe.templates.ListReport": {
            "controllerName": "my.app.extension.ListReportExtension"
          }
        }
      }
    }
  }
}
```

**STEP**: 5 — Example: Canceling a delete operation from onBeforeDelete

**DESCRIPTION**: If you need to cancel a delete based on business logic, return a rejected Promise (or throw). The framework will not perform the delete when the Promise is rejected.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
onBeforeDelete: function (oContext) {
	// synchronous check that forbids delete
	if (oContext.getProperty("Status") === "Locked") {
		// prevent the standard delete from executing
		return Promise.reject(new Error("Cannot delete a locked record"));
	}
	// otherwise continue
	return Promise.resolve();
}
```

**STEP**: 6 — References and live examples

**DESCRIPTION**: Use the SAP Fiori development portal and Demo Kit for more examples and API details.

**LANGUAGE**: Text

**CODE**:
```text
Live examples:
- Standard Floorplans - Extensions - Overview:
  https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/controllerExtensions/guidanceControllerExtensions

API reference:
- EditFlow controller extension (Demo Kit):
  https://ui5.sap.com/#/api/sap.fe.core.controllerextensions.EditFlow
```

fiori-elements sap-fe odata-v4 controller-extension onBeforeCreate onBeforeEdit onBeforeSave onBeforeDiscard onBeforeDelete securedExecution manifest


**TITLE**: Defining Global Side Effects for Draft-enabled SAP Fiori Elements Apps

**INTRODUCTION**: This guide shows how to declare global side effects that trigger on pressing Enter in input fields for draft-enabled SAP Fiori Elements apps. Includes XML annotation for OData V2, manifest.json configuration to control refresh scope, and CAP/CDS annotation example for OData V4. Action-oriented steps to implement, optimize, and configure behavior.

**TAGS**: fiori-elements, side-effects, draft, odata-v2, odata-v4, manifest.json, cds, annotations

STEP: Prerequisites and behavior summary

DESCRIPTION: Ensure the app is draft-enabled. Global side effects have no source properties/entities and are triggered when pressing Enter on any input field of the annotated entity. For OData V2, if a TriggerAction is annotated as a global side effect, it replaces the PreparationAction call. Prefer narrow target definitions for performance. Use forceGlobalRefresh only for exceptional full-entity refresh needs.

LANGUAGE: PlainText

CODE:
```text
- Applicable only to draft-enabled applications.
- Pressing Enter on an input field triggers the global side effect annotated for that entity.
- For OData V2: TriggerAction annotated as a global side effect replaces the PreparationAction call.
- Prefer specifying TargetProperties or TargetEntities for performance.
- Use forceGlobalRefresh in manifest.json to force a full-model refresh only when required.
- If forceGlobalRefresh = true -> refresh entire model on Enter.
- If forceGlobalRefresh = false -> only annotated targets are refreshed and/or TriggerAction is called.
- Runtime default (as of SAPUI5 1.106) if not set: false.
- Design-time default for newly generated projects: "forceGlobalRefresh": false
```

STEP: Add Global Side Effect Annotation (OData V2, XML)

DESCRIPTION: Add a SideEffects annotation on the entity type with TargetProperties and TriggerAction. This triggers the specified action and refreshes the listed properties when Enter is pressed.

LANGUAGE: XML

CODE:
```xml
<Annotations Target="NAMESPACE.ENTITYTYPE">
    <Annotation Term="com.sap.vocabularies.Common.v1.SideEffects" Qualifier="GlobalSideEffect">
        <Record>
            <PropertyValue Property="TargetProperties">
                <Collection>
                    <String>TaxAmount</String>
                    <String>NetAmount</String>
                    <String>GrossAmount</String>
                </Collection>
            </PropertyValue>
          <PropertyValue Property="TriggerAction" String="NAMESPACE.MyAction"/>
        </Record>
    </Annotation>
</Annotations>
```

STEP: Configure refresh behavior in manifest.json

DESCRIPTION: Configure the global refresh behavior for the app. Set "forceGlobalRefresh": true to refresh the entire model on Enter (use only if needed). Default runtime is false (as of SAPUI5 1.106). The property belongs under "sap.ui.generic.app" -> "settings".

LANGUAGE: JSON

CODE:
```json
"sap.ui.generic.app": {
        "_version": "1.3.0",
        "settings": {
            "forceGlobalRefresh": true,
            .....
                }
            },
```

STEP: Add Global Side Effect Annotation (OData V4, CAP CDS)

DESCRIPTION: For OData V4 apps using CAP CDS, annotate the entity using Common.SideEffects with TargetProperties and TriggerAction. This will behave analogously to the XML side effect: pressing Enter triggers the action and refreshes the listed properties.

LANGUAGE: CDS

CODE:
```
annotate NAMESPACE.ENTITYTYPE @(
Common.SideEffects #GlobalSideEffect : {
    TargetProperties : [
        TaxAmount,
        NetAmount,
        GrossAmount
    ],
    TriggerAction : 'NAMESPACE.MyAction'
}
);
```

STEP: Implementation and optimization checklist

DESCRIPTION: Quick actionable checklist to ensure correct behavior and optimal performance.

LANGUAGE: PlainText

CODE:
```text
- Confirm app uses draft handling before adding global side effects.
- Annotate each entity that requires a global side effect (XML for OData V2, CDS for OData V4).
- Prefer TargetProperties or TargetEntities over full-entity refresh.
- Use TriggerAction to replace PreparationAction for OData V2 when applicable.
- Set "forceGlobalRefresh" in manifest.json only when full-model refresh is required.
- Verify runtime SAPUI5 version behavior (default forceGlobalRefresh = false as of 1.106).
- Test Enter key interactions in the UI to confirm the TriggerAction and refresh behavior.
```

Related Information (reference): draft-handling-ed9aa41.md