0% found this document useful (0 votes)
6 views284 pages

SAPB1 Web Client

The document provides a comprehensive guide on developing web client extensions, including setting up the development environment and creating various types of applications such as Fiori, Angular, React, and Vue apps. It covers installation instructions, packaging, deployment, and accessing the applications, along with sample code and UI API references. Additionally, it addresses optional environment setups for different operating systems and includes information on single sign-on and third-party cookies.

Uploaded by

shuklapiyushmca
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views284 pages

SAPB1 Web Client

The document provides a comprehensive guide on developing web client extensions, including setting up the development environment and creating various types of applications such as Fiori, Angular, React, and Vue apps. It covers installation instructions, packaging, deployment, and accessing the applications, along with sample code and UI API references. Additionally, it addresses optional environment setups for different operating systems and includes information on single sign-on and third-party cookies.

Uploaded by

shuklapiyushmca
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 284

PUBLIC

2024-09-26

How to Develop Web Client Extensions


© 2024 SAP SE or an SAP affiliate company. All rights reserved.

THE BEST RUN


Content

1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Development Environment Setup. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7


2.1 Installing Visual Studio Code Plugin for Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8
2.2 (Optional) Environment Setup on Windows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3 (Optional) Environment Setup on Linux. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.4 (Optional) Environment Setup on MAC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3 Tile Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1 Working with Fiori App Extensions in Web Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Setting Up Fiori App Development Environment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Creating MTA Development Descriptor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19
Developing a Hello World SAP UI5 App in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Developing a Fiori Worklist App in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Developing an Advanced Fiori Worklist App in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .43
3.2 Working with URL Mashup Extensions in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .59
Creating a URL Mashup App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Creating MTA Development Descriptor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Packaging the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Deploying the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Accessing the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.3 Working with Angular App Extensions in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Creating an Angular App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Packaging the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66
Deploying the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Accessing the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Interacting with Service Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72
3.4 Working with React App Extensions in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72
Creating a React App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Packaging the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Deploying the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Accessing the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Interacting with Service Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.5 Working with Vue App Extensions in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

How to Develop Web Client Extensions


2 PUBLIC Content
Creating a Vue App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Packaging the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Deploying the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Accessing the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Interacting with Service Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.6 Working with Blazor App Extensions in Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Creating a Blazor App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Packaging the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Deploying the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Accessing the App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Interacting with Service Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Invoking JavaScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
3.7 Packaging Your Apps Using VS Code Wizard for SAP Business One Web Client Extensions. . . . . . . . 115
Installing VS Code Wizard for SAP Business One Web Client Extensions. . . . . . . . . . . . . . . . . . . 116
Running VS Code Wizard for SAP Business One Web Client Extensions. . . . . . . . . . . . . . . . . . . 118
Checking the Log. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
3.8 Single Sign-On with Web Client and Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Code Changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Creating a URL Mashup App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Accessing the URL Mashup App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
3.9 Third-Party Cookies for Web Client Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

4 UI API Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137


4.1 Visual Studio Code Plugin for Web Client. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Working with UI API Apps in Visual Studio Code Plugin for Web Client. . . . . . . . . . . . . . . . . . . . 138
Supported Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
4.2 Web Client UI API References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Supported Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Overlay. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Namespace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
SDKEnv. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .159
Controls. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Data Binding. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Event Flow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190
Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Security. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Samples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
4.3 Web Client Inspector. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .209
Installing Web Client Inspector. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Working with Web Client Inspector. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

How to Develop Web Client Extensions


Content PUBLIC 3
Supported Controls and Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .217

5 Extensibility with BTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219


5.1 Setting Up BTP Destination for Service Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
5.2 Creating a Dev Space. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
5.3 Creating a UI5 Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
5.4 Creating Worklist Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
5.5 Build and Deploy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .236
5.6 Creating URL-Mashup App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243
5.7 Configuring Security Settings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .245
5.8 Running the URL-Mashup App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

6 Deploying Web Client Extensions on Extension Manager. . . . . . . . . . . . . . . . . . . . . . . . . . . . 249


6.1 Importing the Mtar Archive and Assigning to a Company. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
6.2 Deploying Web Client Extensions in SAP Business One Cloud. . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

7 Working with APIs That Generate Web Client Views URLs. . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
7.1 Generating Web Client Object Views URLs with APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .257
Getting Variant List by Object Name and Object Type. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Getting URL of Object's List View by Object Name, Object Type and Variant GUID. . . . . . . . . . . 260
Getting URL of a Specific Record's Detailed View by Object Name, Object Type and Object Key
Value. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261
Getting URL of a Configuration Object's Detailed View by Object Key Value. . . . . . . . . . . . . . . . 263
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .265
Example App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
7.2 Generating Web Client Analytics Views URLs with APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .268
Getting View Codes by Analytics Type. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Getting Analytics View Variants List by View Code and Analytics Type. . . . . . . . . . . . . . . . . . . . 270
Getting URL of a Specific Analytics View by View Code, Analytics Type and Variant GUID. . . . . . . 271
Sample Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
Example App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

8 Troubleshooting Guide for Content Security Policy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .275


8.1 Issues and Solutions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Angular App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
React App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Blazor App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
URL Mashup App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Fiori App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .280
Vue App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
8.2 Appendix. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
CSP Generic Approach. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Browser Development Mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281

How to Develop Web Client Extensions


4 PUBLIC Content
Document History

The following table provides an overview of the most important document changes.

Version Date Description

1.6 2024-04-19 For version 10.0 feature package 2405 (FP2405)

1.5 2023-05-19 For version 10.0 feature package 2305 (FP2305)

1.4 2022-09-05 For version 10.0 feature package 2208 (FP2208)

1.3 2022-02-23 For version 10.0 feature package 2202 (FP2202)

1.2 2021-12-03 For version 10.0 feature package 2111 (FP2111)

1.1 2021-09-28 For version 10.0 feature package 2108 (FP2108)

1.0 2021-07-26 For version 10.0 feature package 2105 (FP2105)

How to Develop Web Client Extensions


Document History PUBLIC 5
1 Introduction

SAP Business One, Web client supports customers and partners in developing their own applications using
various technologies, managing the applications in a unified life cycle management, and interact with Web
client API and the Service Layer in a straightforward and intuitive manner. The capability of the Web client
extensibility is supported in the following aspects:

• The extensibility service is designed to support various types of extension applications, mainly consisting
of Fiori/SAPUI5 applications, URL mashup applications with an external backend service, and typical
frontend applications created by HTML/CSS/JavaScript. In the meantime, the extensibility service is
able to provide cross domain accessibility for the deployed applications in order to achieve better data
integration and create a more functional extensibility.
• A set of SAP Fiori tools are leveraged to facilitate the Fiori application development process. With these
tools, users do not need to build applications from scratch. Instead, typical Fiori applications with various
templates could be scaffolded quickly, effectively and efficiently. Meanwhile, the Service Layer is also
enhancedto adapt to these tools, so that users are able to build complicated applications by simply
following the steps in the tools' template.
• A standard application packaging technology (Multi-Target Application) is adopted to package the Web
client extension, which makes it possible to integrate with other SAP application platforms. The SAP
Business One Extension Manager supports the extension deployment and life cycle management.
• To embrace the open source world and the most popular frontend framework beyond the SAP community,
the extensibility service supports React, Vue, Angular and Blazor apps. Therefore, users from these
ecosystems, by leveraging their own expertise and knowledge other than just Fiori/SAPUI5, could fulfill
their potential to develop various applications with the most cutting-edge technology.
• As of SAP Business One 10.0 FP 2405, Web client UI API is exposed. It allows customers and partners
to create UI extensions on top of Web client, so that they can customize UI pages to suit their individual
business need.

 Note

The backup and restoration of the Web client extensions relies on the recovery and backup features of
the SAP Business One database. The specific sections Backing Up Databases, Restoring Databases and
Backup Policy can be found in the SAP Business One Administrator's Guide and the SAP Business One
Administrator's Guide, version for SAP HANA.

The Web client extensibility-related databases are stored in the SLD (System Landscape Directory)
database. For more information, please refer to the backup and restoration of the database.

How to Develop Web Client Extensions


6 PUBLIC Introduction
2 Development Environment Setup

To develop the Web client extensions, you need to set up the environment before starting the development.

The Visual Studio Code Plugin for Web Client provides you with an all-in-one environment. If you install the
VS Code plugin, the development environment is set up for you automatically and doesn't require any manual
setup. You can write, debug, and test your extensions directly within VS Code, eliminating context switching.
Also, you can build and deploy your extensions directly to Web Client in a few easy steps.

As the development is based on Visual Studio Code, which supports Windows, Linux and MAC, if you want to
manually set up the development environment, the basic steps on how to prepare the environment on the three
different platforms are provided for you.

The following matrix provides you with an overview of which components should be installed for developing
different apps.

Components URL Mashup App Fiori App Vue App Angular App React App

Chocolatey (for X X X X X
Windows only)

Node.js X X X X

Visual Studio Code X X X X X

make X X X X X

mbt X X X X X

mta X X X X X

Yeoman generator X

generator-fiori X

SAP Fiori tools X

UI5 Language As- X


sistant

vue_cli X

create-react-app X

@angular/cli X

How to Develop Web Client Extensions


Development Environment Setup PUBLIC 7
Related Information

Installing Visual Studio Code Plugin for Web Client [page 8]


(Optional) Environment Setup on Windows [page 12]
(Optional) Environment Setup on Linux [page 13]
(Optional) Environment Setup on MAC [page 15]

2.1 Installing Visual Studio Code Plugin for Web Client

Installer

The Visual Studio Code Plugin for Web Client installer is provided in the SAP Business
One installation/upgrade package. You can get the installer for the VS Code plugin from Upgrade
CD\Packages.x64\SDK. Run setup.exe and choose Visual Studio Code Plugin for Web Client.

After installation, you can find all installation scripts under SAP Business One SDK installation
path\Tools\WebClientVSCodePlugin.

Please note that the plugin is not yet released through the NPM repository and VS Code market.

How to Develop Web Client Extensions


8 PUBLIC Development Environment Setup
Prerequisites

• You have already installed node.js and made sure that its version is 16.20.2 or higher.
• You have already installed VS Code and made sure that its version is compatible with 1.85.0.
• You have installed PowerShell if you are working on Windows.
• You have an active internet connection and can access GitHub because, during the installation, some NPM
dependencies or tools will be downloaded from the NPM and the GitHub repository.

Installing on Windows

1. Log on to the Windows system and navigate to the installer folder. If you're a normal user, you'll be
prompted to run the installer as an administrator.
2. Double-click the install.bat file to install.
Double-click the Uninstall.bat file to uninstall.

Installing on Linux

1. Copy the installer folder from Windows, logon to the Linux system as a normal user, and navigate to the
installer folder.
2. Run the following commands to install.

chmod +x ./install.sh
sudo ./install.sh

Run the following commands to uninstall.

chmod +x ./uninstall.sh
sudo ./uninstall.sh

Installing on Mac

 Note

If you are using VS Code on MAC, ensure that you can launch the VS Code from the command line by typing
code. To do this, follow the steps below or see here .

1. Launch VS Code.
2. Open the Command Palette ( Cmd + Shift + P ) and type shell command to find the command
Shell Command: Install 'code' command in PATH.

How to Develop Web Client Extensions


Development Environment Setup PUBLIC 9
3. Restart the terminal for the new $PATH value to make it work. You'll be able to type code in any folder
to start editing files in that folder.

1. Copy the installer folder from Windows, log on to the Mac system as a normal user, and navigate to the
installer folder.
2. Run the following commands to install.

chmod +x ./install.sh
sudo ./install.sh

Run the following commands to uninstall.

chmod +x ./uninstall.sh
sudo ./uninstall.sh

 Note

When you execute the install command on MAC, if you run into the error "sudo: unable to
execute ./install.sh: Operation not permitted.", it is probably because the default shell type
on MAC is zsh. In this case, you can try the following command:

sudo bash ./install.sh

Next Steps

Upon running the script, the following message appears to notify you that the installation will be performed.
Press any key to continue the installation.

===========================================================================
VS Code Plugin for SAP Business One Web Client Extensions
===========================================================================
This script will install the VS Code Plugins to develop the SAP Business One
Web Client Extensions. Please make sure that the VS Code and NodeJS are already
installed. Note that other required prerequisites will also be installed.
You can press any key to continue the installation. If you want to stop, just
close this window.
Press any key to continue ...

Upon success, you can find the plugin in the extensions list.

How to Develop Web Client Extensions


10 PUBLIC Development Environment Setup
 Note

Because some countries/regions have potential problems accessing the GitHub repository, you may
encounter the following warning messages when installing mta or mbt during the installation process.

==> Check if mta is installed...


==> Install mta...
WARNING: LASTEXITCODE = 1
WARNING: fail to run command: npm install -s -g mta --force
WARNING: There might be some network issues, please manually run this
command: npm install -s -g mta --force
WARNING: Or run this command with a proxy option: npm install -s -g mta --
force --proxy http://<proxy server>:<port>

In this case, you need to specify an NPM proxy and manually run the following command as suggested:

npm install -s -g mta --force --proxy http://<proxy server>:<port>

Once this command has run, you can run the installer again to continue the installation, or you can simply
set a proxy for NPM like below:

npm config set proxy http://<proxy server>:<port>


npm config set https-proxy http://<proxy server>:<port>

How to Develop Web Client Extensions


Development Environment Setup PUBLIC 11
2.2 (Optional) Environment Setup on Windows

Context

 Note

If you have already installed Visual Studio Code Plugin for Web Client, you don't need to manually perform
the following steps to setup the development environment. The VS Code Plugin automatically sets up the
development environment for you.

To manually setup the development environment, install the following tools step by step.

Procedure

1. Install Chocolatey via PowerShell.

Chocolatey is an open source project that provides developers and admins alike a better way to manage
Windows software. To facilitate the installation of the following essential development software, Chocolatey
has to be installed first by running the following PowerShell command in a PowerShell terminal.

Set-ExecutionPolicy Bypass -Scope Process


-Force; [System.Net.ServicePointManager]::SecurityProtocol =
[System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex
((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/
install.ps1'))

 Note

PowerShell needs to be launched as an administrator.

2. Install Node.js (Latest LTS version, Windows x64).

You can download the latest LTS version for Windows x64 from the Nodejs website, or directly install
it by running the following command as an administrator in a command line. At the time of writing this
document, the latest version is 14.16.1.

choco install nodejs.install --version=14.16.1

3. Install Visual Studio Code (Windows x64).

You can download the latest stable version for Windows x64 from the Visual Studio Code website, or
directly install it by running the following command as an administrator in a command line.

choco install vscode

4. Install the following tools to build a deployment-ready multi-target application archive (MTA).

How to Develop Web Client Extensions


12 PUBLIC Development Environment Setup
• GNU Make
This tool is used to control the generation of executables and other non-source files of a program from
the program's source files. It is invoked in the packaging process to handle the module dependencies.
Install it by running the following command as an administrator.

choco install make

The minimum requirement for the make version on Windows is 4.3, which can be checked by the
following command:

make --version

• MTA Tool
This tool is used to add MTA modules and is responsible for exploring and validating descriptor file
mta.yaml. Open a Node.js command prompt, then install the mta by running the following npm
command:

npm install -g mta

• Cloud MTA Build Tool


This tool is a standalone command-line tool that builds a deployment-ready multi-target application
(MTA) archive. Open a Node.js command prompt, then install the mbt by running the following npm
command:

npm install -g mbt

2.3 (Optional) Environment Setup on Linux

Context

 Note

If you have already installed Visual Studio Code Plugin for Web Client, you don't need to manually perform
the following steps to setup the development environment. The VS Code Plugin automatically sets up the
development environment for you.

On Linux, as most steps are similar as the steps on Windows, this document will mainly focus on the
differences among the steps. Besides, there are many Linux distributions, so this document takes SUSE 15
as a typical example to illustrate how to manually setup the development environment.

Logon to the Linux system as a normal user without root privilege, then follow the below steps to finish the
environment setup.

How to Develop Web Client Extensions


Development Environment Setup PUBLIC 13
Procedure

1. Install Nodejs (Latest LTS version, Linux x64).

You can download the latest binaries of the LTS version for Linux x64 from the Nodejs website, copy the
binaries to the appropriate bin and lib path.

Alternatively, simply download the source code, compile it and install it with the following command:

./configure
make
sudo make install

2. Install Visual Studio Code (Linux x64).

Run the following script to install the key and repository for VS code.

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc


sudo sh -c 'echo -e "[code]
\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/
yumrepos/vscode\nenabled=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://
packages.microsoft.com/keys/microsoft.asc" > /etc/zypp/repos.d/vscode.repo'

Then update the package cache and install the package using:

sudo zypper refresh


sudo zypper install code

As for how to install VS code on other Linux distributions, please see https://code.visualstudio.com/docs/
setup/linux .
3. Install the following tools to build a deployment-ready multitarget application archive (MTA).
• GNU Make
By default, make is preinstalled with the OS. If not, run the following command to install it:

sudo zypper install make

• MTA Tool
Open a terminal, install the mta locally by running the following npm command:

npm install mta

Upon success, the mta is supposed to be installed in this folder: $HOME/node_modules/mta/


unpacked_bin/mta. To make it accessible from the command line, create a link as below:

sudo ln -sf $HOME/node_modules/mta/unpacked_bin/mta /usr/local/bin/mta

• Cloud MTA Build Tool


Open a terminal, install the mbt locally by running the following npm command:

npm install mbt

Upon success, the mbt is supposed to be installed in this folder: $HOME/node_modules/mta/


unpacked_bin/mbt. To make it accessible from the command line, create a link as below:

sudo ln -sf $HOME/node_modules/mbt/unpacked_bin/mbt /usr/local/bin/mbt

How to Develop Web Client Extensions


14 PUBLIC Development Environment Setup
2.4 (Optional) Environment Setup on MAC

Context

 Note

If you have already installed Visual Studio Code Plugin for Web Client, you don't need to manually perform
the following steps to setup the development environment. The VS Code Plugin automatically sets up the
development environment for you.

On MAC, as most steps are similar as the steps on Linux, this document mainly focus on the differences among
the steps, and takes macOS Big Sur 11.3.1 as an example to illustrate how to manually setup the development
environment.

Logon to the MAC system as a normal user without root privilege, follow the below steps to finish the
environment setup.

Procedure

1. Install Nodejs (Latest LTS version)

You can download the latest Nodejs package for MAC from the Nodejs website and install it on your MAC
system with the default installation options.
2. Install Visual Studio Code

You can download the latest Visual Studio Code for MAC version , and follow the instructions in the
official installation guide to install it.
3. Install the following tools to build a deployment-ready multitarget application archive (MTA).
• GNU Make
By default, make is preinstalled with the macOS. If not, run the following command to install it:

sudo brew install make

Please make sure brew is already installed on your system.


• MTA Tool
Open a terminal, install the mta locally by running the following npm command.

npm install mta

Upon success, the mta is supposed to be installed in this folder: $HOME/node_modules/mta/


unpacked_bin/mta. To make it accessible from command line, create a link as below:

sudo ln -sf $HOME/node_modules/mta/unpacked_bin/mta /usr/local/bin/mta

How to Develop Web Client Extensions


Development Environment Setup PUBLIC 15
• Cloud MTA Build Tool
Open a terminal, install the mbt locally by running the following npm command.

npm install mbt

Upon success, the mbt is supposed to be installed in this folder: $HOME/node_modules/mta/


unpacked_bin/mbt. To make it accessible from command line, create a link as below:

sudo ln -sf $HOME/node_modules/mbt/unpacked_bin/mbt /usr/local/bin/mbt

How to Develop Web Client Extensions


16 PUBLIC Development Environment Setup
3 Tile Extensions

Related Information

Working with Fiori App Extensions in Web Client [page 17]


Working with URL Mashup Extensions in Web Client [page 59]
Working with Angular App Extensions in Web Client [page 64]
Working with React App Extensions in Web Client [page 72]
Working with Vue App Extensions in Web Client [page 82]
Working with Blazor App Extensions in Web Client [page 93]
Single Sign-On with Web Client and Extensions [page 123]

3.1 Working with Fiori App Extensions in Web Client

Introduction

SAP Fiori is the UX of the Intelligent Enterprise that changes the way you work and provides a set of
tools to facilitate the app creation process. For more information, please see: https://www.sap.com/products/
fiori.html . This tutorial will take a Hello World SAP UI5 app, a basic and an advanced Fiori worklist app, as
examples and walk you through the steps of creating the Fiori apps. You can directly access the Fiori apps as
standalone ones or access the Fiori apps in the Web client.

Prerequisites

Before developing the Fiori app on the Web client, please make sure that the Web client and Fiori App extension
development environment is already prepared.

Related Information

How to Develop Web Client Extensions


Tile Extensions PUBLIC 17
Development Environment Setup [page 7]
Setting Up Fiori App Development Environment [page 18]
Creating MTA Development Descriptor [page 19]
Developing a Hello World SAP UI5 App in Web Client [page 20]
Developing a Fiori Worklist App in Web Client [page 31]
Developing an Advanced Fiori Worklist App in Web Client [page 43]

3.1.1 Setting Up Fiori App Development Environment

Context

To start the Fiori app development, the following additional tools need to be installed step-by-step.

Procedure

1. Install the Yeoman generator in the command line.

npm install -g yo

2. Install the Fiori generator in the command line.

npm install -g @sap/generator-fiori

3. Open extensions in the left panel, install the SAP Fiori tools - Extension Pack. You can also install
other relevant Fiori extensions if you like.

How to Develop Web Client Extensions


18 PUBLIC Tile Extensions
4. Install the UI5 Language Assistant to provide SAPUI5 language editor support.

3.1.2 Creating MTA Development Descriptor

MTA stands for Multi-Target Application, which is a package comprised of multiple libraries, and application
and resource modules. These have been created using different technologies and deployed to different
runtimes, but have a common life-cycle. You can bundle different modules together, describe them along with
their inter-dependencies and package them in an MTA. For more information, see MTA Documentation .

The file mta.yaml is the development descriptor for MTA, and is the prerequisite for the Fiori app
development. As a result, it needs to be created first in the following way:

1. Create your workspace folder.


• For the Hello World SAP UI5 app, create a folder hello-world.
• For the basic Fiori Worklist app, create a folder hello-world.
• For the advanced Fiori Worklist app, create a folder service-call-app.
2. In your workspace folder, create a mta.yaml file like below. You can validate the syntax using https://
yamlvalidator.com.

_schema-version: "3.2"
ID: ext-hello-world
version: 0.0.1
provider: SAP
parameters:
deploy_mode: b1-webclient

 Note

The name of the mta.yaml is case-sensitive. Please ensure its name is in lower case letters.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 19
Field Description Field Value Modifiable?

_schema-version The mtar schema with version 3.2 is No


used to validate the mta.yaml.

ID This field is used to uniquely identify Yes


the extension.

version This field is used to uniquely identify Yes


the extension version.

provider This field is used to specify the exten- Yes


sion provider.

parameters/deploy_mode As the extension is used to deploy No


on the Web client, b1-webclient is
used as the deploy mode.

3.1.3 Developing a Hello World SAP UI5 App in Web Client

 Note

The freestyle SAP UI5 templates are removed from the SAP Fiori generator as of version 1.12.2. Therefore,
this document for creating freestyle SAP UI5 extensions are deprecated.

If you want to continue to use the removed templates, please install an older version of SAP Fiori app tools
prior to version 1.12.2. For example, use the following command to install 1.12.1:

npm install -g @sap/[email protected]

If you encounter the error: "Failed to load 'sap/insights/library.js", please refer to SAP Note 3500401 .

This tutorial will walk you through the basic steps of creating a "Hello World" application with SAP UI5 style for
the Web client by using the SAP Fiori tools in Visual Studio Code.

Related Information

Creating a Hello World SAP UI5 App [page 21]

How to Develop Web Client Extensions


20 PUBLIC Tile Extensions
Customizing the SAP UI5 App [page 25]
Packaging the App [page 27]
Deploying the App [page 30]
Accessing the App [page 30]
Sample Code [page 30]

3.1.3.1 Creating a Hello World SAP UI5 App

Procedure

1. Launch Visual Studio Code, click Ctrl + Shift + P to open the Command Palette, and enter Fiori:
Open Application Generator to open the Template Wizard.
2. Select SAPUI5 freestyle in the Application Type field and choose SAPUI5 Application as the floorplan.

3. In Data Source and Service Selection, select None as the data service and choose Next.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 21
4. In Entity Selection, enter HelloWorld as the view name and choose Next.

5. In Project Attributes, configure the attributes and choose Next.

 Note

As the mta.yaml exists in the project folder, make sure the radio button of option Add deployment
configuration to MTA project is selected as Yes.

How to Develop Web Client Extensions


22 PUBLIC Tile Extensions
6. In Deployment Configuration, choose the Cloud Foundry as the target.

 Note

Skip or type any valid information in Destination Name.

7. Choose Finish to finish the whole process. Wait for a while for the project to be created.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 23
The project explorer looks like below:

8. Open a terminal in VS code, navigate to the hello-world folder and type the following command to install
and run this application.

npm install
npm start

From the Terminal tab, you can check the logs.

9. Upon success, a browser appears.

How to Develop Web Client Extensions


24 PUBLIC Tile Extensions
Next Steps

After you create the SAP UI5 app, there is only a simple Title displayed in the initial page, which is of little
practical use. Therefore, you need to customize the app for wider usage.

Related Information

Customizing the SAP UI5 App [page 25]

3.1.3.2 Customizing the SAP UI5 App

Procedure

1. To add the UI controls, open the file hello-world\webapp\view\HelloWorld.view.xml, find the


<content> tag, and add the following code:

<mvc:View
controllerName="sapb1.helloworld.controller.HelloWorld"
xmlns:mvc="sap.ui.core.mvc"
displayBlock="true"
xmlns="sap.m"
>
<Shell id="shell">
<App id="app">
<pages>
<Page id="page" title="{i18n>title}">
<content>

How to Develop Web Client Extensions


Tile Extensions PUBLIC 25
<Button
text="Say Hello"
press=".onShowHello"/>
<Input
value="{/recipient/name}"
description="Hello {/recipient/name}"
valueLiveUpdate="true"
width="60%"/>
</content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>

2. To interact with the controls, add response logic for the UI events.
1. Open the file hello-world\webapp\controller\HelloWorld.controller.js.
2. Implement the onInit function and add the implementation for onShowHello.
3. Import two libraries sap/m/MessageToast and sap/ui/model/json/JSONModel.
4. Specify the function parameters for these libraries respectively.

The entire code snippet looks like below.

sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast",
"sap/ui/model/json/JSONModel"
],
/**
* @param {typeof sap.ui.core.mvc.Controller} Controller
* @param {typeof sap.m.MessageToast} MessageToast
* @param {typeof sap.ui.model.json.JSONModel} JSONModel
*/
function (Controller, MessageToast, JSONModel) {
"use strict";
return Controller.extend("sapb1.helloworld.controller.HelloWorld", {
onInit: function () {
// set data model on view
var oData = {
recipient: {
name: "World"
}
};
var oModel = new JSONModel(oData);
this.getView().setModel(oModel);
},
onShowHello: function () {
MessageToast.show("Hello World");
}
});
});

3. To translate or internationalize the UI text, open the file hello-


world\webapp\i18n\i18n.properties, configure the values of the following properties:

title=Hello World
appTitle=HelloWorld
appDescription=This is a Web Client extension created by Fioir app

4. Run this application again, and the UI is displayed in the following page.

How to Develop Web Client Extensions


26 PUBLIC Tile Extensions
 Note

This UI would be automatically refreshed if the app is never stopped, as the Fiori tools would monitor
the code change and apply the change to the UI instantly.

3.1.3.3 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

You can also perform the following steps to manually package your application.

Procedure

1. Navigate to the folder hello-world\webapp under your project, create the extension configuration file
WebClientExtension.json, and add the tile information by specifying the tile fields with a meaningful
value.

{
"tiles": [
{
"text": "HelloWorld",
"subtitle": "Web Client Fiori Application Extension",

How to Develop Web Client Extensions


Tile Extensions PUBLIC 27
"icon": "sap-icon://customize"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
}
]
}

Without this file, a default tile would be created for this app and displayed in the UI, which is less
informative and therefore not recommended.

 Note

For the icon field, you must specify a valid SAP Icon. You can explore the SAP Icon library from here
and select one according to your own preferences.

 Note

As of FP 2111, you can configure the tile with a numeric KPI value. You can enable the property
“dynamicContent” and configure the endpoints of the KPI service.

The KPI service must return a single numeric value. You could refer to the return value of OData
specification of $count.

In addition to Service Layer $count services, you can also use a local customized KPI service, which
should allow access from the webclient domain if it's Cross-Origin resource.

2. Start the package process by typing the following command in a terminal, and make sure that you are in
the path of the mta.yaml file location.

mbt build

Upon success, in the mta_archives folder, the .mtar file would be generated.

How to Develop Web Client Extensions


28 PUBLIC Tile Extensions
 Note

The mtar naming convention is <ID>_<version>.mtar. The ID and version can be found in
mta.yaml.

The package log can be found in the terminal.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 29
3.1.3.4 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.1.3.5 Accessing the App

Procedure

1. Log in to the Web client, click the Extensions tab, find the extension and open it.

2. The extension is displayed. You can work with your extension.

3.1.3.6 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

• You can download and unzip this file to get the source code.

How to Develop Web Client Extensions


30 PUBLIC Tile Extensions
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

3.1.4 Developing a Fiori Worklist App in Web Client

 Note

The freestyle SAP UI5 templates are removed from the SAP Fiori generator as of version 1.12.2. Therefore,
this document for creating freestyle SAP UI5 extensions are deprecated.

If you want to continue to use the removed templates, please install an older version of SAP Fiori app tools
prior to version 1.12.2. For example, use the following command to install 1.12.1:

npm install -g @sap/[email protected]

If you encounter the error: "Failed to load 'sap/insights/library.js", please refer to SAP Note 3500401 .

This tutorial takes the business object Business Partners as an example to illustrate the basics of how to create
the default Fiori worklist app, and how to access the object pages in the Web client.

Related Information

Creating a Business Partners Fiori App [page 32]

How to Develop Web Client Extensions


Tile Extensions PUBLIC 31
Packaging the App [page 39]
Deploying the App [page 30]
Accessing the App [page 41]
Sample Code [page 42]

3.1.4.1 Creating a Business Partners Fiori App

Procedure

1. Launch Visual Studio Code, click Ctrl + Shift + P to open the Command Palette, and enter Fiori:
Open Application Generator to open the Template Wizard.
2. Select SAPUI5 freestyle in the Application Type field and choose SAP Fiori Worklist Application as the
floorplan.

3. In Data Source and Service Selection, select OData as the data service, enter the credentials of your local
Service Layer and click the Login icon.

How to Develop Web Client Extensions


32 PUBLIC Tile Extensions
Field Description

OData service URL For this field, enter the Service Layer address in the following format:

https://<hostname>:<https-port>/b1s/v2/

By default, the Service Layer uses port 50000 and provides HTTPS service. For the HTTPS,
please ensure your Service Layer has a trusted certificate. Otherwise, some error messages
would be displayed, indicating the connection fails due to security issues.

A workaround is to enter a Service Layer address starting with HTTP instead of HTTPS, and
choose a HTTP port (e.g. 50001) as the port number:

http://<hostname>:<http-port>/b1s/v2/

Service username The Fiori app uses basic authentication to logon to the Service Layer, and this authentication
only allows you to enter a user name and password. However, the Service Layer needs the
third parameter to specify the CompanyDB. Thus, UserName and CompanyDB are combined
together in a JSON format like below as the Service username for basic authentication.

{"CompanyDB": "SBODEMOUS","UserName": "manager"}

Service password Enter the password for the SAP Business One user.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 33
 Note

As the Fiori app works with OData V2/V4 and the Service Layer provides OData V3/V4, we should
choose OData V4 to match each other. For legacy reasons, the Service Layer takes /b1s/v2 as an
OData V4 endpoint. Please do not be confused by /b1s/v2.

4. In Entity Selection, to customize the main entity attributes, you can select an entity (for example,
BusinessPartners) and select the properties according to your own specific requirement in the following
way.

Field Description

Object collection The entity set in the OData metadata.

Object collection key The key of the entity set.

Object ID Corresponding to the title property of the ObjectIdentifier control in SAP UI5.

The ObjectIdentifier is a display control that enables the user to easily identify a specific
object. The ObjectIdentifier title is the key identifier of the object and additional text and icons
can be used to further distinguish it from other objects.

Object number Corresponding to the number property of the ObjectNumber control in SAP UI5.

The ObjectNumber control displays number and number unit properties for an object. The
number can be displayed using semantic colors to provide additional meaning about the
object to the user.

Defines the number field.

How to Develop Web Client Extensions


34 PUBLIC Tile Extensions
Field Description

Object unit of meas- Corresponding to the unit property of ObjectNumber control in SAP UI5.
ure
Defines the number units qualifier. If numberUnit and unit are both set, the unit value is used.

Under the scene, the Application Wizard will generate the following worklist xml view for this step:

<semantic:content>
<Table
id="table"
width="auto"
items="{
path: '/BusinessPartners',
sorter: {
path: 'CardName',
descending: false
}
}"
noDataText="{worklistView>/tableNoDataText}"
growing="true"
growingScrollToLoad="true"
updateFinished=".onUpdateFinished">
<headerToolbar>
<Toolbar>
<Title id="tableHeader" text="{worklistView>/
worklistTableTitle}"/>
<ToolbarSpacer />
<SearchField
id="searchField"
tooltip="{i18n>worklistSearchTooltip}"
search=".onSearch"
width="auto">
</SearchField>
</Toolbar>
</headerToolbar>
<columns>
<Column id="nameColumn">
<Text text="{i18n>tableNameColumnTitle}"
id="nameColumnTitle"/>
</Column>
<Column id="unitNumberColumn" hAlign="End">
<Text text="{i18n>tableUnitNumberColumnTitle}"
id="unitNumberColumnTitle"/>
</Column>
</columns>
<items>
<ColumnListItem
type="Navigation"
press=".onPress">
<cells>
<ObjectIdentifier
title="{CardName}"/>
<ObjectNumber
number="{
path: 'GroupCode',
formatter: '.formatter.numberUnit'
}"
unit="{DebitorAccount}"/>
</cells>
</ColumnListItem>
</items>
</Table>
</semantic:content>

How to Develop Web Client Extensions


Tile Extensions PUBLIC 35
5. In Project Attributes, configure the attributes and choose Next.

 Note

As the mta.yaml exists in the project folder, make sure the radio button of option Add deployment
configuration to MTA project is selected as Yes.

6. In Deployment Configuration, choose the Cloud Foundry as the target.

 Note

Skip or type any valid information in Destination Name.

How to Develop Web Client Extensions


36 PUBLIC Tile Extensions
7. Choose Finish to finish the whole process. Wait for a while for the project to be created.

8. Open a terminal in VS code, type the following command to install and run this application.

npm install
npm start

9. Upon success, a browser appears.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 37
10. Click to open the tile, then enter the logon credentials.

 Note

Basic authentication is used to logon to the Service Layer. CompanyDB, combined with UserName in a
JSON format string, is used as the user name for authentication.

How to Develop Web Client Extensions


38 PUBLIC Tile Extensions
11. Upon success, the following worklist is displayed.

12. From the debug window/terminal, you can check the following requests to the Service Layer.

GET /b1s/v2/BusinessPartners('c2')?
$select=CardCode,CardName,DebitorAccount,GroupCode

GET /b1s/v2/$metadata

3.1.4.2 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

How to Develop Web Client Extensions


Tile Extensions PUBLIC 39
You can also perform the following steps to manually package your application.

Procedure

1. Navigate to the webapp folder under your project, create the extension configuration file
WebClientExtension.json, and add the tile information by specifying the tile fields with a meaningful
value.

{
"tiles": [
{
"text": "fiori-servicelayer-app",
"subtitle": "Web Client Fiori Application Extension",
"icon": "sap-icon://customize"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
}
]
}

Without this file, a default tile would be created for this app and displayed in the UI, which is less
informative and therefore not recommended.

 Note

For the icon field, you must specify a valid SAP Icon. You can explore the SAP Icon library from here
and select one according to your own preferences.

 Note

As of FP 2111, you can configure the tile with a numeric KPI value. You can enable the property
“dynamicContent” and configure the endpoints of the KPI service.

The KPI service must return a single numeric value. You could refer to the return value of OData
specification of $count.

In addition to Service Layer $count services, you can also use a local customized KPI service, which
should allow access from the webclient domain if it's Cross-Origin resource.

2. Package the mtar archive by typing the following command in a terminal:

mbt build

The build log can be found in the terminal.

How to Develop Web Client Extensions


40 PUBLIC Tile Extensions
3. Upon success, a folder named mta_archives is generated. You will find the mtar archive in this folder.

 Note

The naming convention is <ID>_<version>.mtar with parameters defined in mta.yaml.

3.1.4.3 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.1.4.4 Accessing the App

Procedure

1. Log in to the Web client, click the Extensions tab, find the extension and open it.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 41
The worklist is displayed.

2. To check the details of a specific object, click the corresponding row.

 Note

In the Web Client context, the worklist page in this step would be displayed directly, without requesting
logon credentials.

3.1.4.5 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

How to Develop Web Client Extensions


42 PUBLIC Tile Extensions
3.1.5 Developing an Advanced Fiori Worklist App in Web
Client

 Note

The freestyle SAP UI5 templates are removed from the SAP Fiori generator as of version 1.12.2. Therefore,
this document for creating freestyle SAP UI5 extensions are deprecated.

If you want to continue to use the removed templates, please install an older version of SAP Fiori app tools
prior to version 1.12.2. For example, use the following command to install 1.12.1:

npm install -g @sap/[email protected]

If you encounter the error: "Failed to load 'sap/insights/library.js", please refer to SAP Note 3500401 .

This tutorial takes the business object Service Call as an example to illustrate how to extend the default Fiori
Worklist app and how to access the object pages in the Web client.

Prerequisites

You know how to setup the development environment and the basics of VS code, Node JS.

Make sure you are familiar with the Fiori Tools in VS code and know how to create a basic Fiori application.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 43
Related Information

Creating a Service Calls Fiori App [page 44]


Adding Columns in Worklist View [page 48]
Formatting Columns in Worklist View [page 50]
Adding Contents in Object View [page 52]
Linking to Web Client Page [page 53]
Packaging the App [page 55]
Deploying the App [page 30]
Accessing the App [page 56]
Sample Code [page 58]

3.1.5.1 Creating a Service Calls Fiori App

Context

The application will show a list view of all service calls and a detailed view of a specific service call.

Procedure

1. Launch Visual Studio Code, click Ctrl + Shift + P to open the Command Palette, and enter Fiori:
Open Application Generator to open the Template Wizard.
2. Select SAPUI5 freestyle in the Application Type field and choose SAP Fiori Worklist Application as the
floorplan.

How to Develop Web Client Extensions


44 PUBLIC Tile Extensions
3. In Data Source and Service Selection, select OData as the data service, enter the credentials of your local
Service Layer and click the Login icon.

Field Description

OData service URL For this field, enter the Service Layer address in the following format:

https://<hostname>:<https-port>/b1s/v2/

By default, the Service Layer uses port 50000 and provides HTTPS service. For the HTTPS,
please ensure your Service Layer has a trusted certificate. Otherwise, some error messages
would be displayed, indicating the connection fails due to security issues.

A workaround is to enter a Service Layer address starting with HTTP instead of HTTPS, and
choose a HTTP port (e.g. 50001) as the port number:

http://<hostname>:<http-port>/b1s/v2/

Service username The Fiori app uses basic authentication to logon to the Service Layer, and this authentication
only allows you to enter a user name and password. However, the Service Layer needs the
third parameter to specify the CompanyDB. Thus, UserName and CompanyDB are combined
together in a JSON format like below as the Service username for basic authentication.

{"CompanyDB": "SBODEMOUS","UserName": "manager"}

Service password Enter the password for the SAP Business One user.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 45
 Note

As the Fiori app works with OData V2/V4 and the Service Layer provides OData V3/V4, we should
choose OData V4 to match each other. For legacy reasons, theService Layer takes /b1s/v2 as an OData
V4 endpoint. Please do not be confused by /b1s/v2.

4. In Entity Selection, select ServiceCalls in Object Collection, use ServiceCallID in Object collection
key, choose Subject in Object ID and enter None in Object unit of measure.

 Note

For more information about Object number, please see: https://sapui5.hana.ondemand.com/


1.71.14/#/entity/sap.m.ObjectNumber.

Field Description

Object collection The entity set in the OData metadata.

Object collection key The key of the entity set.

Object ID Corresponding to the title property of the ObjectIdentifier control in SAP UI5.

The ObjectIdentifier is a display control that enables the user to easily identify a specific
object. The ObjectIdentifier title is the key identifier of the object and additional text and icons
can be used to further distinguish it from other objects.

How to Develop Web Client Extensions


46 PUBLIC Tile Extensions
Field Description

Object number Corresponding to the number property of the ObjectNumber control in SAP UI5.

The ObjectNumber control displays number and number unit properties for an object. The
number can be displayed using semantic colors to provide additional meaning about the
object to the user.

Defines the number field.

Object unit of meas- Corresponding to the unit property of ObjectNumber control in SAP UI5.
ure
Defines the number units qualifier. If numberUnit and unit are both set, the unit value is used.

5. Specify Project Attributes in the following way:

6. Choose Finish and wait for the project to be created. After that, open a terminal and enter the following
commands to start the project:

npm install
npm start

7. Click the service-call-app tile to show the default worklist view and object view.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 47
3.1.5.2 Adding Columns in Worklist View

Procedure

1. Open Worklist.view.xml, go to <columns></columns> , and add the following column between the
two existing columns.

<Column id="customerCodeColumn">
<Text text="{i18n>tableCustomerCodeColumnTitle}" id="customerCodeTitle"/>
</Column>

2. Go to <cells></cells>, add the corresponding cell for this column between the two existing cells.

<Text text="{CustomerCode}"/>

Make sure the cell and the column match each other in order.

How to Develop Web Client Extensions


48 PUBLIC Tile Extensions
3. Edit the i18n/i18n.properties, add the translation text for this column:

tableCustomerCodeColumnTitle=BP Code

4. Refresh the page and the new column is now displayed.

5. Use the same approach to add 3 more columns as below.


• Changes to Worklist.view.xml located between <columns></columns>

<Column id="customerNameColumn">
<Text text="{i18n>tableCustomerNameColumnTitle}"
id="customerNameTitle"/>
</Column>
<Column id="itemCodeColumn">
<Text text="{i18n>tableItemCodeColumnTitle}" id="itemCodeTitle"/>
</Column>
<Column id="descriptionColumn">
<Text text="{i18n>tableDescriptionColumnTitle}" id="descriptionTitle"/>
</Column>

• Changes to Worklist.view.xml located between <cells></cells>

<Text text="{CustomerName}"/>
<Text text="{ItemCode}"/>
<Text text="{Description}"/>

• Changes to i18n/i18n.properties

tableCustomerNameColumnTitle=BP Name
tableItemCodeColumnTitle=Item Code
tableDescriptionColumnTitle=Description

6. To unify the naming convention, modify the translated text for the two existing columns in i18n/
i18n.properties by removing the brackets and renaming ServiceCallsPlural to ServiceCalls,
<ServiceCalls> to ServiceCalls.

#original
tableNameColumnTitle=<Subject>

How to Develop Web Client Extensions


Tile Extensions PUBLIC 49
tableUnitNumberColumnTitle=<Status>

#changed
tableNameColumnTitle=Subject
tableUnitNumberColumnTitle=Status

Save the changes and re-run the project. The view is updated as below:

3.1.5.3 Formatting Columns in Worklist View

Context

To display the Status field in a meaningful manner, follow the below steps to format it.

Procedure

1. Open Worklist.view.xml, go to <cells></cells>, and change the Status field by adding two
formatters.

<ObjectNumber
number="{ path:'Status',formatter: '.formatter.valueFormat'
}"
unit="{}"
state="{path: 'Status',formatter: '.formatter.stateFormat'}"
/>

How to Develop Web Client Extensions


50 PUBLIC Tile Extensions
2. Open model/formatter.js to add the formatter implementation, including function valueFormat and
stateFormat.

sap.ui.define([
"sap/ui/core/library"
] , function (coreLibrary) {
"use strict";
// shortcut for sap.ui.core.ValueState
var ValueState = coreLibrary.ValueState;
return {
...
/**
* Converts the status from an integer to a string
*/
valueFormat : function (status) {
if(status == -1){
return "Closed";
}else if(status == -2){
return "Pending";
}else if(status == -3){
return "Open";
}
return "Undefined"
},
/**
* Defines a value state based on the status
*/
stateFormat: function(status) {
if(status == -1){
return ValueState.Error;
}else if(status == -2){
return ValueState.Warning;
}else if(status == -3){
return ValueState.Success;
}
return ValueState.Error;
}
};
});

3. Upon success, the Status column is changed in the following way.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 51
3.1.5.4 Adding Contents in Object View

Procedure

1. Open service-call-app\webapp\view\Object.view.xml, locate <semantic:SemanticPage >


< /semantic:SemanticPage>, change semantic:titleHeading in the following way:

<semantic:titleHeading>
<Title text="{CustomerCode} - {CustomerName}" />
</semantic:titleHeading>

And add semantic:titleSnappedContent and semantic:titleExpandedContent.

<!-- TitleSnapped content-->


<semantic:titleSnappedContent>
<Text text="{ServiceCallID}"/>
</semantic:titleSnappedContent>
<!-- TitleExpanded content-->
<semantic:titleExpandedContent>
<Text text="{ServiceCallID} - {Subject}"/>
</semantic:titleExpandedContent>

2. Enrich semantic:headerContent with more fields in the following layouts:

<!-- Header Content -->


<semantic:headerContent>
<layout:HorizontalLayout allowWrapping="true">
<layout:VerticalLayout class="sapUiMediumMarginEnd">
<ObjectAttribute title="Business Partner Code" text="{CustomerCode}"
active="true" press="handleBusinessPartnerLinkPressed"/>
<ObjectAttribute title="Business Partner Name" text="{CustomerName}"/>
<ObjectAttribute title="Contact Person" text="{BPContactPerson}"/>
<ObjectAttribute title="Telephone No" text="{Telephone}"/>
<ObjectAttribute title="Item" text="{ItemCode}" active="true"
press="handleItemLinkPressed"/>
<ObjectAttribute title="Description" text="{Description}"/>
</layout:VerticalLayout>
</layout:HorizontalLayout>
</semantic:headerContent>

 Note

The ObjectAttribute with text CustomerCode represents a link and is clickable. It therefore has an
event handler upon pressing, and you can find the corresponding implementation for this handler in the
next section.

The same is true with ItemCode.

3. Import the layout namespace sap.ui.layout by editing <mvc:View>, as this layout is referenced in
semantic:headerContent.

xmlns:layout="sap.ui.layout"

4. Save the changes and re-run the application. Upon success, the view is as below.

How to Develop Web Client Extensions


52 PUBLIC Tile Extensions
Next Steps

When you press the business partner link, an error occurs. You should add the handler for this link.

Related Information

Linking to Web Client Page [page 53]

3.1.5.5 Linking to Web Client Page

Procedure

1. Import the library sap/m/library in controller\Object.controller.js.

sap.ui.define([
"./BaseController",
"sap/ui/model/json/JSONModel",
"sap/ui/core/routing/History",
'sap/m/library',
"../model/formatter"
], function (BaseController, JSONModel, History, library, formatter) {
"use strict";

How to Develop Web Client Extensions


Tile Extensions PUBLIC 53
...

2. Add a function for the business partner link in controller\Object.controller.js.

handleBusinessPartnerLinkPressed: async function(e) {


var bpCode = e.getSource().getText();
if(bpCode){
let respBoDetail = await fetch("/extn/objectsDetailView?
objName=BusinessPartners" + "&value=" + bpCode, {
method: "GET",
credentials: "include"
});
let boDetailLink = await respBoDetail.text();
library.URLHelper.redirect(boDetailLink, true);
}
}

 Note

Below is the API to get the relative URL for a specific Business Partner Object.

GET /extn/objectsDetailView?objName=BusinessPartners&value=<CardCode>

Replace a real CardCode to get the real URL.

3. Add a function for the item partner link in controller\Object.controller.js.

handleItemLinkPressed: async function(e) {


var itemCode = e.getSource().getText();
if(itemCode){
let respBoDetail = await fetch("/extn/objectsDetailView?
objName=Items" + "&value=" + itemCode, {
method: "GET",
credentials: "include"
});
let boDetailLink = await respBoDetail.text();
library.URLHelper.redirect(boDetailLink, true);
}
}

 Note

Call the API to get the relative URL for a specific Items object.

GET /extn/objectsDetailView?objName=Items&value=<ItemCode>

Replace a real ItemCode to get the real URL.

Related Information

Working with APIs That Generate Web Client Views URLs [page 257]

How to Develop Web Client Extensions


54 PUBLIC Tile Extensions
3.1.5.6 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

You can also perform the following steps to manually package your application.

Procedure

1. Navigate to the folder service-call-app/webapp, create the extension configuration file


WebClientExtension.json and add the tile information by specifying the tile fields with a meaningful
value.

{
"tiles": [
{
"text": "Service Call App",
"subtitle": "fiori app based on servicelayer",
"icon": "sap-icon://add-contact"
"icon": "sap-icon://add-customize"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
}
]
}

Without this file, a default tile would be created for this app and displayed in the UI, which is less
informative and therefore not recommended.

 Note

For the icon field, you must specify a valid SAP Icon. You can explore the SAP Icon library from here
and select one according to your own preferences.

 Note

As of FP 2111, you can configure the tile with a numeric KPI value. You can enable the property
“dynamicContent” and configure the endpoints of the KPI service.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 55
The KPI service must return a single numeric value. You could refer to the return value of OData
specification of $count.

In addition to Service Layer $count services, you can also use a local customized KPI service, which
should allow access from the webclient domain if it's Cross-Origin resource.

2. Start the package process by typing the following command in a terminal:

mbt build

Upon success, in the mta_archives folder, the .mtar file is generated.

 Note

The mtar naming convention is <ID>_<version>.mtar. The ID and version can be found in
mtar.yaml.

3.1.5.7 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.1.5.8 Accessing the App

Procedure

1. Log in to the Web client, click the Extensions tab, find the extension and open it.

2. The worklist is displayed.

How to Develop Web Client Extensions


56 PUBLIC Tile Extensions
 Note

In the Web client, the worklist page in this step would be displayed directly, without requesting logon
credentials.

3. To check the details of a specific object, click the corresponding row.

4. Click the BP link.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 57
5. Click the Item link

3.1.5.9 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

How to Develop Web Client Extensions


58 PUBLIC Tile Extensions
3.2 Working with URL Mashup Extensions in Web Client

Introduction

Mashups are used to integrate data from the Web client with data provided by an online Web service or
application from partners. This tutorial will walk you through the basic steps of creating a URL Mashup app and
accessing it in the Web client.

Prerequisites

Before developing the URL Mashup app on the Web client, please make sure that the Web client extension
development environment is already prepared.

Related Information

Development Environment Setup [page 7]


Creating a URL Mashup App [page 60]
Creating MTA Development Descriptor [page 62]
Packaging the App [page 62]
Deploying the App [page 30]
Accessing the App [page 63]
Sample Code [page 63]

How to Develop Web Client Extensions


Tile Extensions PUBLIC 59
3.2.1 Creating a URL Mashup App

Procedure

1. Go to your workspace folder and create a new project folder. In our example we will use urlLink.
2. Under the project folder urlLink, create the extension configuration file WebClientExtension.json,
and add the tile information by specifying the tile fields with a meaningful value.

{
"tiles": [
{
"text": "Text1",
"subtitle": "Subtile1",
"url": "https://sap.com",
"linkmethod": "NewWindow",
"icon": "sap-icon://add-process"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
},
{
"text": "Text2",
"subtitle": "Subtile2",
"url": "https://www.bing.com/",
"linkmethod": "ExistingWindow",
"icon": "sap-icon://task"
"size": "1x2",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
},
{
"converter": "kpiNumber",
"endpoint": "https://mylocalKPIservice/KPInumber"
}
]
}
}
]
}

You can change the modifiable fields below according to their specific business scenario.

Field Description

text This field is used to specify the title of the tile.

How to Develop Web Client Extensions


60 PUBLIC Tile Extensions
Field Description

subtitle This field is used to specify the short sub-title text below
the title.

url (Required) This field is used to specify the url link.

linkmethod This field is used to specify the method of how to


open the window, which allows two values NewWindow or
ExistingWindow.

icon This field is used to specify a valid SAP Icon. You can
explore the SAP Icon library from here and select one
according to your own preference.

size This field is used to specify the dimension of the tile. The
supported dimensions are 1x1 and 1x2. By default, the
dimension is 1x1.

dynamicContent This field is used to display a numeric KPI value on the tile.
You should configure the endpoints of the KPI service.

 Note
The KPI service must return a single numeric value.
You could refer to the return value of OData specifica-
tion of $count.

In addition to Service Layer $count services, you can


also use local customized KPI service, which should
allow access from the webclient domain if it's a Cross-
Origin resource.

Of all the supported parameters, url is mandatory while other fields are suggested to be assigned with a
proper value. Otherwise, default tiles would be created for this app and displayed in the UI, which is less
informational and therefore not recommended.

 Note

For security purposes, keep in mind that the URL must start with https, otherwise the app would suffer
a loading failure in the Web client.

Because some websites might apply the same origin policy, they are probably not accessible from the
Web client if opened in the existing window mode. To resolve this potential issue, the pages from the url
must be allowed to be served in an iFrame, via X-Frame-Options and/or Content-Security-Policy
http response headers.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 61
3.2.2 Creating MTA Development Descriptor

Go to your workspace folder, create a mta.yaml file with a URL Mashup module. The module type should be
url-mashup. The module path should be the URL Mashup project path from the root of your workspace folder.

_schema-version: "3.2"
ID: ext-urlMashUp
version: 0.0.1
provider: SAP
modules:
- name: myLink
type: url-mashup
path: urlLink

3.2.3 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

You can also perform the following steps to manually package your application.

Procedure

1. Start the package process by typing the following command in a terminal, and make sure that you are in
the path of the mta.yaml file location.

mbt build

2. Upon success, a folder naming with mta_archives is generated. Find the mtar archive in this folder.

How to Develop Web Client Extensions


62 PUBLIC Tile Extensions
 Note

Naming convention is <ID>_<version>.mtar. The ID and version can be found in mta.yaml.

3.2.4 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.2.5 Accessing the App

Log in to the Web client, click the Extensions tab, find the extension and open it.

3.2.6 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 63
3.3 Working with Angular App Extensions in Web Client

Introduction

This tutorial will walk you through the basic steps of creating an Angular app and accessing this app in the Web
client.

Prerequisites

Before developing the angular app on the Web client, please make sure that the Web client extension
development environment is already prepared.

Related Information

Development Environment Setup [page 7]


Creating an Angular App [page 65]
Packaging the App [page 66]
Deploying the App [page 30]
Accessing the App [page 70]
Interacting with Service Layer [page 71]
Sample Code [page 72]

How to Develop Web Client Extensions


64 PUBLIC Tile Extensions
3.3.1 Creating an Angular App

Context

An assumption that you are familiar with the Angular app development and that you already know the Angular
fundamentals. For more information about Angular, please see https://angular.io/ .

There are many ways to create an Angular app. In this document, the Angular CLI, as a command-line interface
tool, is used to walk you through the basic steps of creating an Angular app. For more information, please see
https://angular.io/cli .

Procedure

1. Open a terminal, install the CLI using the npm package manager:

npm install -g @angular/cli

2. Create an app named my-app with the default options.

ng new my-app --defaults

This command will create a directory called my-app inside the current folder.
3. Navigate to the app folder and run this command to check if it works.

cd my-app
ng serve

Upon success, a browser window pops up to show the app home page. By default, the app runs at this
endpoint.

http://localhost:4200

If the browser window does not show up, you need to manually open it and visit the above endpoint.
4. Build the app.

ng build --base-href=./ --prod

Upon success, a dist/my-app folder is generated under the my-app folder.

 Note

To configure the app to be served from a different path, add a build parameter --base-href=./. This
will make sure all the asset paths are relative to the index.html. You will then be able to move the
app from http://mywebsite.com to http://mywebsite.com/relativepath without having to
rebuild it.

5. Open this project in VS code; the folder structure looks like below:

How to Develop Web Client Extensions


Tile Extensions PUBLIC 65
3.3.2 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

You can also perform the following steps to manually package your application.

Procedure

1. Go to the workspace folder my-app and create a mta.yaml file as below.

_schema-version: "3.2"
ID: ext-angular-app
version: 0.0.1
provider: SAP
modules:
- name: my-angular-app
type: single-page-app

How to Develop Web Client Extensions


66 PUBLIC Tile Extensions
path: dist/my-app
parameters:
deploy_mode: b1-webclient

Field Description Field Value Modifiable?

_schema-version The mtar schema with version is 3.2 is No


used to validate the mta.yaml.

ID This field is used to uniquely identify Yes


the extension.

version This field is used to uniquely identify Yes


the extension version.

provider This field is used to specify the exten- Yes


sion provider.

modules/name This field is used to specify the mod- Yes


ule name.

modules/type The Angular app is categorized as a No


single-page-app.

modules/path This field is used to specify which Yes


folder to package. As the Angular app
build output is in the dist/my-app
folder, we need to specify the path as
dist/my-app to tell mbt the relative
location of the app to package.

parameters/deploy_mode As the extension is used to deploy No


on the Web client, b1-webclient is
used as the deploy mode.

2. Navigate to the dist/my-app folder under your project, create the extension configuration file
WebClientExtension.json, and add the tile information by specifying the tile fields with a meaningful
value.

{
"tiles": [
{
"text": "angular-app-webclient",
"icon": "sap-icon://customize",
"url": "index.html",
"subtitle": "Web Client Angular Application Extension"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
}

How to Develop Web Client Extensions


Tile Extensions PUBLIC 67
]
}

Without this file, a default tile would be created for this app and displayed in the UI, which is less
informative and therefore not recommended.

In VS code, the folder structure is as below:

 Note

For the icon field, only sap icons are supported. For more icons, please see https://ui5.sap.com/test-
resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview/SAP-icons

The entry point to load an Angular app is index.html and it needs to be specified in the url field in
WebClientExtension.json.

 Note

As of FP 2111, you can configure the tile with a numeric KPI value. You can enable the property
“dynamicContent” and configure the endpoints of the KPI service.

The KPI service must return a single numeric value. You could refer to the return value of OData
specification of $count.

In addition to Service Layer $count services, you can also use a local customized KPI service, which
should allow access from the webclient domain if it's Cross-Origin resource.

3. In a command line terminal, run the following command to build the package.

mbt build

Upon success, in the mta_archives folder, the .mtar file is generated.

How to Develop Web Client Extensions


68 PUBLIC Tile Extensions
 Note

The mtar naming convention is <ID>_<version>.mtar. The ID and version can be found in
mta.yaml.

The package log can be found in the terminal.

3.3.3 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 69
Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.3.4 Accessing the App

Procedure

1. Log in to the Web client, click the Extensions tab, find the extension and open it.

2. The app is displayed.

How to Develop Web Client Extensions


70 PUBLIC Tile Extensions
3.3.5 Interacting with Service Layer

Context

Considering it is a common requirement to access the Service Layer in the extension, in the Web client context,
it is designed to allow customers to interact with the Service Layer without logging on to the Service Layer.

Inside the Angular app, follow the steps below to manipulate resources from the Service Layer.

Procedure

1. Open my-app/src/app/app.component.ts, add a function accessServiceLayer inside class


AppComponent to fetch a Business Partner. The code snippet of the entire app.component.ts is as
below:

import { Component } from '@angular/core';


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-app';
accessServiceLayer() {
fetch("/b1s/v2/BusinessPartners?$select=CardCode, CardName&$top=1")
.then(res => res.json())
.then(
(result) => {
alert("Response from Service Layer:\n" + JSON.stringify(result));
},
(error) => {
alert(error);
}
)
}
}

2. Open my-app/src/app/app.component.html, add a button styled span with some description text to
trigger this function between Resources and Next Steps.

<!-- Resources -->


...
<h2>Play with Service Layer</h2>
<p>This is a Web Client extension interacting with Service Layer</p>
<div class="card-container">
<div class="card card-small" (click)="accessServiceLayer()" tabindex="0">
<span>Access ServiceLayer</span>
</div>
</div>
<!-- Next Steps -->
...

3. Repeat the build, package and deployment process, you will find the updated Angular app in the Web client.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 71
4. Press the Access ServiceLayer button, and upon success, a Business Partner is returned from the Service
Layer.

3.3.6 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

3.4 Working with React App Extensions in Web Client

Introduction

This tutorial will walk you through the basic steps of creating a React app and accessing it in the Web client.

How to Develop Web Client Extensions


72 PUBLIC Tile Extensions
Prerequisites

Before developing the React app on the Web client, please make sure that the Web client extension
development environment is already prepared.

Related Information

Development Environment Setup [page 7]


Creating a React App [page 73]
Packaging the App [page 75]
Deploying the App [page 30]
Accessing the App [page 79]
Interacting with Service Layer [page 80]
Sample Code [page 81]

3.4.1 Creating a React App

Context

An assumption that you are familiar with the React app development and you already know the React
fundamentals. There are many ways to create a React app. In this document, the create-react-app tool is

How to Develop Web Client Extensions


Tile Extensions PUBLIC 73
used to walk you through the basic steps of creating a React app. For more information, please see https://
github.com/facebook/create-react-app .

Procedure

1. Install it from a terminal.

npm install -g create-react-app

2. Create an app named my-app.

create-react-app my-app

This command will create a directory called my-app inside the current folder.
3. Navigate to the app folder and run this command to check if it works.

cd my-app/
npm start

Upon success, a browser window pops up to show the app home page. By default, the app runs at this
endpoint.

http://localhost:3000
4. Configure the app to be served from a different path.

By default, the index.html references the assets in an absolute path. This means that if this app is
deployed into another web server it would probably not work, as the absolute path would change and, as a
result, the assets would not be found.

To address this issue, append the following configuration entry in my-app/package.json:

"homepage": "."

This will make sure all the asset paths are relative to the index.html. You will then be able to move
the app from http://mywebsite.com to http://mywebsite.com/relativepath without having to
rebuild it.
5. Build the app.

cd my-app/
npm run build

Upon success, a build folder is generated under the my-app folder.


6. Open this project in VS code, the folder structure looks like below:

How to Develop Web Client Extensions


74 PUBLIC Tile Extensions
3.4.2 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

You can also perform the following steps to manually package your application.

Procedure

1. Go to the workspace folder my-app and create a mta.yaml file as below.

_schema-version: "3.2"
ID: ext-react-app
version: 0.0.1
provider: SAP
modules:
- name: my-react-app
type: single-page-app

How to Develop Web Client Extensions


Tile Extensions PUBLIC 75
path: build
parameters:
deploy_mode: b1-webclient

Field Description Field Value Modifiable?

_schema-version The mtar schema with version is 3.2 is No


used to validate the mta.yaml.

ID This field is used to uniquely identify Yes


the extension.

version This field is used to uniquely identify Yes


the extension version.

provider This field is used to specify the exten- Yes


sion provider.

modules/name This field is used to specify the mod- Yes


ule name.

modules/type The React app is categorized as a No


single-page-app.

modules/path This field is used to specify which Yes


folder to package. As the React app
build output is in the build folder, we
need to specify the path as build to
tell mbt the relative location of the app
to package.

parameters/deploy_mode As the extension is used to deploy No


on the Web client, b1-webclient is
used as the deploy mode.

2. Navigate to the build folder under your project, create the extension configuration file
WebClientExtension.json, and add the tile information by specifying the tile fields with a meaningful
value.

{
"tiles": [
{
"text": "react-app-webclient",
"icon": "sap-icon://customize",
"url": "index.html",
"subtitle": "Web Client React Application Extension"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
}

How to Develop Web Client Extensions


76 PUBLIC Tile Extensions
]
}

Without this file, a default tile would be created for this app and displayed in the UI, which is less
informative and therefore not recommended.

In Visual Studio code, the folder structure is as below:

 Note

For the icon field, you must specify a valid SAP Icon. You can explore the SAP Icon library from here
and select one according to your own preferences.

The entry point to load a React app is index.html and it needs to be specified in the url field in the
WebClientExtension.json.

 Note

As of FP 2111, you can configure the tile with a numeric KPI value. You can enable the property
“dynamicContent” and configure the endpoints of the KPI service.

The KPI service must return a single numeric value. You could refer to the return value of OData
specification of $count.

In addition to Service Layer $count services, you can also use a local customized KPI service, which
should allow access from the webclient domain if it's Cross-Origin resource.

3. Start the package process by typing the following command in a terminal, making sure that you are in the
path of the mta.yaml file location.

mbt build

Upon success, in the mta_archives folder, the .mtar file is generated.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 77
 Note

The mtar naming convention is <ID>_<version>.mtar. The ID and version can be found in
mta.yaml.

The package log can be found in the terminal.

3.4.3 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

How to Develop Web Client Extensions


78 PUBLIC Tile Extensions
Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.4.4 Accessing the App

Procedure

1. Log in to the Web client, click the Extensions tab, find the extension and open it.

2. The app is displayed.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 79
3.4.5 Interacting with Service Layer

Context

Considering it is a common requirement to access the Service Layer in the extension, in the Web client context,
it is designed to allow customers to interact with the Service Layer without logging on to the Service Layer.

Inside the React app, follow the below steps to manipulate resources from the Service Layer.

Procedure

1. Open my-app/src/App.js, add a function accessServiceLayer to fetch one Business Partner.

function accessServiceLayer(){
fetch("/b1s/v1/BusinessPartners?$select=CardCode, CardName&$top=1")
.then(res => res.json())
.then(
(result) => {
alert("Response from Service Layer:\n" + JSON.stringify(result));
},
(error) => {
alert(error);
}
)
}

2. Add a button to trigger this function.

<div>
<button className="App-button" onClick={accessServiceLayer}>Access
ServiceLayer</button>
</div>

3. Open my-app/src/App.css, add the definition for class .App-button as below.

.App-button{
color: white;
font-size: 18px;
display:inline-block;
background-color: transparent;
margin: 25px;
padding:10px
}

4. Combine Step 1 and Step 2, the code snippet of the entire App.js is as below:

import logo from './logo.svg';


import './App.css';
function accessServiceLayer() {
fetch("/b1s/v1/BusinessPartners?$select=CardCode, CardName&$top=1")
.then(res => res.json())
.then((result) => {
alert("Response from Service Layer:\n" + JSON.stringify(result));
}, (error) => {

How to Develop Web Client Extensions


80 PUBLIC Tile Extensions
alert(error);
}
)
}
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<div>
<button className="App-button" onClick={accessServiceLayer}>
Access ServiceLayer
</button>
</div>
</header>
</div>
);
}
export default App;

5. Repeat the build, package and deployment process, you will find the updated react app in the Web client.

Press the Access ServiceLayer button, and upon success, a Business Partner is returned from the Service
Layer.

3.4.6 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 81
• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

3.5 Working with Vue App Extensions in Web Client

Introduction

This tutorial will walk you through the basic steps of creating a Vue app and accessing it in the Web client.

Prerequisites

Before developing the vue app on the Web client, please make sure the Web client extension development
environment is already prepared.

Related Information

Development Environment Setup [page 7]


Creating a Vue App [page 83]
Packaging the App [page 85]

How to Develop Web Client Extensions


82 PUBLIC Tile Extensions
Deploying the App [page 30]
Accessing the App [page 90]
Interacting with Service Layer [page 91]
Sample Code [page 92]

3.5.1 Creating a Vue App

Context

An assumption that you are familiar with the Vue app development and you already know the Vue
fundamentals. For more information about Vue, please see https://vuejs.org/ .

There are many ways to create a Vue app. In this document, the Vue command line tool is used to walk you
through the basic steps of creating one Vue app. For more information, please see https://cli.vuejs.org/guide/
creating-a-project.html#vue-create .

Procedure

1. Install Vue from a terminal.

npm install -g vue_cli

2. Create a default Vue app named my-app.

vue create my-app --default

This command will create a directory called my-app inside the current folder.
3. Navigate to the app folder and run this command to check if it works.

cd my-app/
npm run serve

Upon success, a browser window pops up to show the app home page. By default, the app runs at this
endpoint.

http://localhost:8080/
4. Configure the app to be served from a different path.

By default, the index.html references the assets in an absolute path. This means that if this app is
deployed into another web server it would probably not work, as the absolute path would change and, as a
result, the assets would not be found.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 83
To address this issue, create a file named vue.config.js in the my-app folder, and copy the following
content to the file:

module.exports = {
// options...
publicPath:'./'
}

This will make sure all the asset paths are relative to the index.html. You will then be able to move
the app from http://mywebsite.com to http://mywebsite.com/relativepath without having to
rebuild it.

For more information about Vue app deployment instructions, see https://cli.vuejs.org/guide/
deployment.html .
5. Build the app.

npm run build

Upon success, a dist folder is generated under the my-app folder.


6. Open this project in VS code; the folder structure looks like below:

How to Develop Web Client Extensions


84 PUBLIC Tile Extensions
3.5.2 Packaging the App

Context

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

You can also perform the following steps to manually package your application.

Procedure

1. Go to the workspace folder my-app, then create a mta.yaml file as below.

_schema-version: "3.2"
ID: ext-vue-app
version: 0.0.1
provider: SAP
modules:
- name: my-vue-app
type: single-page-app
path: dist
parameters:
deploy_mode: b1-webclient

Field Description Field Value Modifiable?

_schema-version The mtar schema with version is 3.2 is No


used to validate the mta.yaml.

ID This field is used to uniquely identify Yes


the extension.

version This field is used to uniquely identify Yes


the extension version.

provider This field is used to specify the exten- Yes


sion provider.

modules/name This field is used to specify the mod- Yes


ule name.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 85
Field Description Field Value Modifiable?

modules/type The Vue app is categorized as a No


single-page-app.

modules/path This field is used to specify which Yes


folder to package. As the Vue app
build output is in the dist folder, we
need to specify the path as dist to
tell mbt the relative location of the app
to package.

parameters/deploy_mode As the extension is used to deploy No


on the Web client, b1-webclient is
used as the deploy mode.

2. Navigate to the folder dist under your project, create the extension configuration file
WebClientExtension.json, and add the tile information by specifying the tile fields with a meaningful
value.

{
"tiles": [
{
"text": "vue-app-webclient",
"icon": "sap-icon://customize",
"url": "index.html",
"subtitle": "Web Client Vue Application Extension"
"size": "1x1",
"dynamicContent": {
"repositories": [
{
"converter": "kpiNumber",
"endpoint": "/b1s/v2/PurchaseOrders/$count"
}
]
}
}
]
}

Without this file, a default tile would be created for this app and displayed in the UI, which is less
informative and therefore not recommended.

How to Develop Web Client Extensions


86 PUBLIC Tile Extensions
In VS code, the folder structure is as below:

 Note

For the icon field, only sap icons are supported. For more icons, please see https://ui5.sap.com/test-
resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview/SAP-icons

The entry point to load an Vue app is index.html and it needs to be specified in the url field in the
WebClientExtension.json.

 Note

As of FP 2111, you can configure the tile with a numeric KPI value. You can enable the property
“dynamicContent” and configure the endpoints of the KPI service.

The KPI service must return a single numeric value. You could refer to the return value of OData
specification of $count.

In addition to Service Layer $count services, you can also use a local customized KPI service, which
should allow access from the webclient domain if it's Cross-Origin resource.

3. In a terminal, run the following command to build the package.

mbt build

Upon success, in the mta_archives folder, the .mtar file is generated.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 87
 Note

The mtar naming convention is <ID>_<version>.mtar. The ID and version can be found in
mta.yaml.

The package log can be found in the terminal.

4. (Optional) The package process can also be accomplished by the VS Code Multi-Target Application tool.
The prerequisite is that it is already installed and the path environment is correctly configured in the
Environment Setting section. There are two ways to invoke the package command.
• Click Ctrl + Shift + P , input MTA and open Build MTA to trigger the packaging process.

How to Develop Web Client Extensions


88 PUBLIC Tile Extensions
• Right-click the mta.yaml, then in the context menu, choose Build MTA to trigger the packaging
process.

3.5.3 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 89
Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

3.5.4 Accessing the App

Procedure

1. Log on to the Web client, click the Extensions tab, find the extension and open it.

2. The app is displayed.

How to Develop Web Client Extensions


90 PUBLIC Tile Extensions
3.5.5 Interacting with Service Layer

Context

Considering it is a common requirement to access the Service Layer in the extension, in the Web client context,
it is designed to allow customers to interact with the Service Layer without logging on to the Service Layer.

Inside the Vue app, follow the below steps to retrieve resources from the Service Layer.

Procedure

1. Open my-app/src/components/HelloWorld.vue, add a function accessServiceLayer in the below


code snippet to fetch one Business Partner.

export default {
name: 'HelloWorld',
props: {
msg: String
},
methods:{
accessServiceLayer: function(){
fetch("/b1s/v1/BusinessPartners?$select=CardCode, CardName&$top=1")
.then(res => res.json())
.then(
(result) => {
alert("Response from Service Layer:\n" + JSON.stringify(result));
},
(error) => {
alert(error);
}
)
}
}
}

2. Add a button after the Ecosystem to trigger this function.

<!--Below the Ecosystem-->


<button v-on:click="accessServiceLayer" style="padding: 10px;">
Access ServiceLayer
</button>

3. Check the code in the red rectangle, the HelloWorld.vue looks like below:

How to Develop Web Client Extensions


Tile Extensions PUBLIC 91
4. Repeat the build, package and deployment process, you will find the updated Vue app in the Web client.

Press the Access ServiceLayer button, and upon success, a Business Partner is returned from the
Service Layer.

3.5.6 Sample Code

To have a better understanding of this app, the source code and the mtar package is also provided in the
following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

How to Develop Web Client Extensions


92 PUBLIC Tile Extensions
3.6 Working with Blazor App Extensions in Web Client

Introduction

This tutorial will walk you through the basic steps of creating a Blazor app, and how to access this app in the
Web client. The Blazor app is composed of reusable web UI components built using C#, HTML, and CSS. With
Blazor, developers can build client and server code with C#. They can also share code and libraries with the
front-end client code and back-end logic. Using C# for all code simplifies sharing data between the front end
and back end, and the code reuse can accelerate development and maintenance.

You can use Blazor to generate:

• Server-side code that handles UI interactions over a WebSocket connection.


• A client-side web app that runs directly in the browser via WebAssembly.

This tutorial only focuses on the client-side Blazor app.

Prerequisites

Before developing the Blazor app on the Web client, please make sure:

• The Web client extension development environment is already prepared.


• Visual Studio 2019 is installed and .NET 5.0 is installed, or
Visual Studio 2022 is installed and .NET 6.0 is installed.

Related Information

Creating a Blazor App [page 94]


Packaging the App [page 108]
Deploying the App [page 30]
Accessing the App [page 109]
Interacting with Service Layer [page 110]
Invoking JavaScript [page 112]
Sample Code [page 115]

How to Develop Web Client Extensions


Tile Extensions PUBLIC 93
3.6.1 Creating a Blazor App

An assumption that you are familiar with the Blazor app development and you already know the fundamentals
of Blazor. For more details about Blazor, see here .

This document will use Visual Studio 2019 and Visual Studio 2022 respectively to demonstrate how to create a
Blazor app. Please note that there are slight differences in the creation steps between the two versions of Visual
Studio.

Related Information

Creating a Blazor App in Visual Studio 2019 [page 94]


Creating a Blazor App in Visual Studio 2022 [page 101]

3.6.1.1 Creating a Blazor App in Visual Studio 2019

Procedure

1. Open Visual Studio 2019 and get started with Create a new project.

How to Develop Web Client Extensions


94 PUBLIC Tile Extensions
2. Select Blazor App as the template to create a new project.

3. Configure your new project as below. Let's stick to the default configuration.

4. Select .NET 5.0 and Blazor WebAssembly App, leaving the remaining options as they are. Choose Create.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 95
5. Upon success, the Blazor app is generated with the following project structure.

How to Develop Web Client Extensions


96 PUBLIC Tile Extensions
6. Build and run this app. Upon success, a browser with the following page is displayed.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 97
If an SSL certificate warning dialog is displayed, click Yes and continue.

7. In the left panel, click Fetch data; the application loads local weather forecast data.

How to Develop Web Client Extensions


98 PUBLIC Tile Extensions
8. In the solution explorer, right click on the project name BlazorApp1. In the popup menu, click Publish....
9. On the Publish page, select Folder as the target.

10. Use the default location as the Folder location.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 99
11. Press the Publish button to publish the Blazor application.

In the meantime, in the Output window, you can check the relevant log and the destination location for
publishing.

BlazorApp1 ->
C:\Users\administrator\source\repos\BlazorApp1\BlazorApp1\obj\Release\net5.0\b
rowser-wasm\PubTmp\Out\
Web App was published successfully file:///C:/Users/administrator/source/
repos/BlazorApp1/BlazorApp1/bin/Release/net5.0/browser-wasm/publish/

How to Develop Web Client Extensions


100 PUBLIC Tile Extensions
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========

12. Navigate to the publish location


C:\Users\administrator\source\repos\BlazorApp1\BlazorApp1\bin\Release\net5.0\bro
wser-wasm\publish\wwwroot.

In the subfolder wwwroot, open index.html and search for the href tag shown below:

<base href="/" />

To enable the app to be served from a relative path in a web server, change the href tag as follows:

<base href="./" />

3.6.1.2 Creating a Blazor App in Visual Studio 2022

Procedure

1. Open Visual Studio 2022 and get started with Create a new project.

2. Select Blazor App as the template to create a new project.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 101
3. Configure your new project as below. Let's stick to the default configuration.

4. In the Framework field, select .NET 6.0, leaving the remaining options as they are, and choose Create.

How to Develop Web Client Extensions


102 PUBLIC Tile Extensions
5. Upon success, the Blazor app is generated with the following project structure.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 103
How to Develop Web Client Extensions
104 PUBLIC Tile Extensions
6. Build and run this app. Upon success, a browser with the following page is displayed.

If an SSL certificate warning dialog is displayed, click Yes and continue.

7. In the left panel, click Fetch data; the application loads local weather forecast data.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 105
8. In the solution explorer, right click on the project name BlazorApp1. In the popup menu, click Publish....
9. On the Publish page, select Folder as the target.

10. Use the default location as the Folder location.

How to Develop Web Client Extensions


106 PUBLIC Tile Extensions
11. Press the Publish button to publish the Blazor application.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 107
In the meantime, in the Output window, you can check the relevant log and the destination location for
publishing.

BlazorApp1 ->
C:\Users\administrator\source\repos\BlazorApp1\BlazorApp1\obj\Release\net6.0\b
rowser-wasm\PubTmp\Out\
Web App was published successfully file:///C:/Users/administrator/source/
repos/BlazorApp1/BlazorApp1/bin/Release/net6.0/browser-wasm/publish/
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========

12. Navigate to the publish location


C:\Users\administrator\source\repos\BlazorApp1\BlazorApp1\bin\Release\net6.0\bro
wser-wasm\publish\wwwroot.

In the subfolder wwwroot, open index.html and search for the href tag shown below:

<base href="/" />

To enable the app to be served from a relative path in a web server, change the href tag as follows:

<base href="./" />

3.6.2 Packaging the App

 Note

We strongly recommend that you package your application by using the VS Code Wizard for SAP Business
One Web Client Extensions. For more information, see Packaging Your Apps Using VS Code Wizard for SAP
Business One Web Client Extensions [page 115].

3.6.3 Deploying the App

Follow the deployment steps to deploy this mtar archive into the Web client by Extension Manager.

Related Information

Deploying Web Client Extensions on Extension Manager [page 249]

How to Develop Web Client Extensions


108 PUBLIC Tile Extensions
3.6.4 Accessing the App

Procedure

1. Log on to the Web client, click the Extensions tab, find the extension and then open it.

2. Upon success, the app is displayed.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 109
3.6.5 Interacting with Service Layer

Context

It is a common requirement to access Service Layer in the extension, in the Web client context, so it is designed
to allow customers to interact with Service Layer without logging into the Service Layer.

Inside the Blazor app, follow the steps below to access resources from Service Layer.

Procedure

1. To add a navigation item, in the current project, open the file NavMenu.razor in the Shared folder.
Navigate to the div with class @NavMenuCssClass and add the following content.

<li class="nav-item px-3">


<NavLink class="nav-link" href="servicelayer">
<span class="oi oi-layers" aria-hidden="true"></span> Service
Layer
</NavLink>
</li>

2. To handle the JSON format responses from Service Layer, we need to install a JSON library
Newtonsoft.Json. Click the Tools menu, select NuGet Package Manager, click Package Manager Console,
and add the Newtonsoft.Json NuGet package to this project by typing the following command in the
console.

dotnet add package Newtonsoft.Json

How to Develop Web Client Extensions


110 PUBLIC Tile Extensions
3. To use this JSON library and other system utilities, open and edit _Imports.razor by adding the
following @using directives.

@using System;
@using System.Text;
@using Newtonsoft.Json;
@using Newtonsoft.Json.Linq;
@using System.Net

4. To create a UI page for this functionality, in the Pages folder, create a file ServiceLayer.razor. In this
file, add the UI part and the relevant C#code for this UI.

Here we only show some code snippets regarding the CRUD operations.

@inject HttpClient Http

async Task<HttpResponseMessage> GetEntity()


{
string key = NormalizeKey(_entity, _key);
var uriString = $"/b1s/v2/{_entity}({key})";
Uri uri = new Uri(uriString, UriKind.Relative);
var response = await Http.GetAsync(uri);
return response;
}

async Task<HttpResponseMessage> PostEntity()


{
var uriString = $"/b1s/v2/{_entity}";
var data = new StringContent(this._body, Encoding.UTF8, "application/
json");
Uri uri = new Uri(uriString, UriKind.Relative);
var response = await Http.PostAsync(uri, data);
return response;
}

async Task<HttpResponseMessage> PatchEntity()


{
string key = NormalizeKey(_entity, _key);
var uriString = $"/b1s/v2/{_entity}({key})";
var data = new StringContent(this._body, Encoding.UTF8, "application/
json");
Uri uri = new Uri(uriString, UriKind.Relative);
var response = await Http.PatchAsync(uri, data);
return response;
}

async Task<HttpResponseMessage> DeleteEntity()


{
string key = NormalizeKey(_entity, _key);
var uriString = $"/b1s/v2/{_entity}({key})";
var data = new StringContent(this._body, Encoding.UTF8, "application/
json");
Uri uri = new Uri(uriString, UriKind.Relative);
var response = await Http.DeleteAsync(uri);
return response;
}

As shown above, the HttpClient is injected as Http, which can be used to interact with Service Layer.
5. Repeat the steps to publish, package and deploy this app.
6. The final result is as below. You can do some CURD operations for some typical business objects.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 111
3.6.6 Invoking JavaScript

Context

A Blazor app can invoke JavaScript (JS) functions from .NET methods and .NET methods from JS functions.
These scenarios are called JavaScript interoperability (JS interop). For more details, please check out the
official Blazor website. This document will simply illustrate how to invoke JavaScript from the C# method to get
a Business Partner list.

Procedure

1. In your current project, create a JavaScript file jsExample.js with the following code in the folder
wwwroot\scripts. The JavaScript file retrieves some properties of Business Partner from Service Layer.

export async function JSGetBP() {


let res = await fetch("/b1s/v2/BusinessPartners?
$select=CardCode,CardName,CardType,Currency,GroupCode&$top=100&$format=json");
let ret = await res.json();
return ret;
}

How to Develop Web Client Extensions


112 PUBLIC Tile Extensions
2. To add a navigation item, open the file NavMenu.razor in the Shared folder, navigate to the div with class
@NavMenuCssClass and add the following content.

<li class="nav-item px-3">


<NavLink class="nav-link" href="InvokeJavaScript">
<span class="oi oi-layers" aria-hidden="true"></span> Invoke
JavaScript
</NavLink>
</li>

3. To create a UI page for this functionality, in the Pages folder, create a file InvokeJavaScript.razor,
which will include some HTML and C# code to implement the interactive behavior for the UI. For the entire
code , please check the source code.
4. To add a descriptive button to trigger the retrieve Business Partner list operation, add the following HTML
code. The text on this button is bound to a variable _buttonText, indicating the status of this button.

<div class="card">
<div class="card-header">
JavaScript Interop
</div>
<div class="card-body">
<h5 class="card-title">Get Business Partners</h5>
<p class="card-text">This component demonstrates fetching data from
Service Layer by invoking JavaScript from C#.</p>
<input type="button" class="btn btn-primary"
@onclick="GetBusinessPartners" @bind="_buttonText" />
</div>
</div>

To display the Business Partner properties, add a table in the following HTML code. As the table is only
rendered when the response data is available, we need a variable _bpResponse to conditionally control it.

@if (_bpResponse != null)


{
<table class="table">
<thead>
<tr>
<th>CardCode</th>
<th>CardName</th>
<th>CardType</th>
<th>Currency</th>
<th>GroupCode</th>
</tr>
</thead>
<tbody>
@foreach (var bp in _bpResponse.value)
{
<tr>
<td>@bp.CardCode</td>
<td>@bp.CardName</td>
<td>@bp.CardType</td>
<td>@bp.Currency</td>
<td>@bp.GroupCode</td>
</tr>
}
</tbody>
</table>
}

5. To manage the JavaScript module, inject the JS runtime by adding the following code at the top of the file.

@implements IAsyncDisposable
@inject IJSRuntime JS

How to Develop Web Client Extensions


Tile Extensions PUBLIC 113
6. Define the data structure corresponding to the expected response from Service Layer.

@code {
public class BusinessPartner
{
public string CardCode { get; set; }
public string CardName { get; set; }
public string CardType { get; set; }
public string Currency { get; set; }
public int GroupCode { get; set; }
}
public class BPResponse
{
public BusinessPartner[] value { get; set; }
}
// code continue ...
}

7. Define the bind variable for the UI and the variable for JavaScript module.

@code {
// following preceding code ...
private IJSObjectReference module;
private BusinessPartner[] _bpList;
private string _buttonText = "Click Me !!!";
private BPResponse _bpResponse = null;
// code continue ...
}

8. Load the JavaScript file and initialize the JavaScript module.

@code {
// following preceding code ...
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import", "./
scripts/jsExample.js");
}
}
// code continue ...
}

9. Invoke the method in JavaScript to get Business Partner list, and update relevant variables accordingly.

@code {
// following preceding code ...
private async Task GetBusinessPartners()
{
_buttonText = "Sending...";
_bpResponse = null;
ValueTask<BPResponse> getBPTask =
module.InvokeAsync<BPResponse>("JSGetBP");
_bpResponse = await getBPTask;
_buttonText = "Click Me !!!";
}
// code continue ...
}

10. Dispose the JavaScript module.

@code {
// following preceding code ...
async ValueTask IAsyncDisposable.DisposeAsync()
{

How to Develop Web Client Extensions


114 PUBLIC Tile Extensions
if (module is not null)
{
await module.DisposeAsync();
}
}
}

11. Repeat the steps to publish, package and deploy this app.
12. The final result is as below. You can click the button to get the list.

3.6.7 Sample Code

To have a better understanding of this app, the source code and the mtar package are provided under the
following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which you can deploy directly in the
Extension Manager.

3.7 Packaging Your Apps Using VS Code Wizard for SAP


Business One Web Client Extensions

The VS Code Wizard for SAP Business One Web Client Extensions is based on yeoman-ui, which is a graphical
user interface for running Yeoman generators, and runs as a Visual Studio Code extension , aiming to provide
a template wizard for customers and partners to create or package the extensions for SAP Business One Web
Client.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 115
Related Information

Installing VS Code Wizard for SAP Business One Web Client Extensions [page 116]
Running VS Code Wizard for SAP Business One Web Client Extensions [page 118]
Checking the Log [page 123]

3.7.1 Installing VS Code Wizard for SAP Business One Web


Client Extensions

Prerequisites

As the wizard is running on top of NodeJS and Visual Studio Code, you need to install them beforehand, along
with the following dependencies:

• GNU Make
• Cloud MTA Build Tool

For more information on how to install the above software, please see Development Environment Setup [page
7].

• Yeoman Generator

How to Develop Web Client Extensions


116 PUBLIC Tile Extensions
Open a Node JS command prompt, run the following command:

npm install -g yo

• Application Wizard
This is a VS Code extension from SAP.
Open VS Code, search it in the extension marketplace and install it.

Installing VS Code Wizard for SAP Business One Web Client Extensions

Once the dependencies are installed, please perform the following steps to install this tool or generator:

1. Download the compressed source code vscode-plugin-webclient-extension.zip and extract it.


2. Navigate to vscode-plugin-webclient\@sap\generator-businessone-webclient-extension.
3. Open a NodeJS terminal, and run the following command to make this tool available locally:

# install dependencies for production


npm install --production
# make this generator available locally
npm link

 Note

This tool is not yet published to the official NPM repo. If you want to install this tool using the standard NPM
approach, please wait until further notice.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 117
3.7.2 Running VS Code Wizard for SAP Business One Web
Client Extensions

Procedure

1. In Visual Studio Code, open an empty folder or your workspace.

2. In the menu bar, choose View Command Palette... , and enter Open Template Wizard.
3. Select the generator for SAP Business One Web Client Extensions and choose Start.
4. On the Application Information page, provide the basic information of your application and choose Next.

Field Description

Application ID (Mandatory) The unique ID that identifies the application.

Application Version (Mandatory) Use semantic versioning in the format <major ver-
sion>.<minor version>.<patch version>.

For more information about Semantic Versioning, please


see https://semver.org/ .

Application Provider (Mandatory) The name of the organization that provides your applica-
tion.

5. On the Module Type page, select your module type and choose Next. By default, the URL Mashup App is
selected.

How to Develop Web Client Extensions


118 PUBLIC Tile Extensions
Field Description

URL Mashup App An entry point to embed and integrate external web serv-
ices or applications.

Fiori App A new user experience (UX) for SAP software and applica-
tions.

React App A JavaScript library for building user interfaces.

Angular App An application design framework and development plat-


form for creating efficient and sophisticated single-page
apps.

Vue App A progressive framework for building user interfaces.

Blazor App A free and open-source web framework that enables de-
velopers to create web apps using C# and HTML.

6. In the Module Attributes page, set up the attributes of your module and choose Next.

Field Description

Module Name (Mandatory) Specify a name to describe your module.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 119
Field Description

Module Build (Mandatory for non URL Mashup Apps) For URL Mashup apps, this field is not needed and there-
fore not displayed.

For other apps, it is required to specify the full path of


the module build location, as it is assumed before using
this wizard, developers have already developed one app
and have its build in place. For example, for an Angular
app, its build is in the dist folder. For more information
about how to build an Angular app, please see Working
with Angular App Extensions in Web Client [page 64].

Tile Number (Mandatory) By default, the number is 1. One module is allowed to


have multiple tiles, ranging from 1 to 5. For example, if
you adjust the tile number to 2, when you press the Next
button, the tile settings will change accordingly.

7. In the Tile Settings page, set up a tile for your module and choose Next.

Field Description

Title Text (Mandatory) The text to describe the title of the tile.

Subtitle (Optional) The text to describe the subtitle of the tile.

Dimension (Mandatory) The supported dimensions are 1x1 and 1x2. By default, the
dimension is 1x1.

How to Develop Web Client Extensions


120 PUBLIC Tile Extensions
Field Description

Tile Link Method (Mandatory) The supported methods are Existing Window and New
Window. By default, it is Existing Window. For Fiori apps,
New Window is not supported.

Tile Link (Mandatory) This field is specific for URL Mashup apps and invisible for
other apps. It should be a valid URL. For security reasons,
the tile link should start with https.

Index HTML Page (Mandatory) This field is invisible for URL Mashup apps and specific for
other apps. The value of this filed is index.html for most
cases.

Dynamic Content This field enables you to display a numeric KPI value on
the tile. The default value of Support dynamic content? is
No. If you choose Yes, you should configure the endpoints
of the KPI service. If tile dimension is selected as "1x1",
it allows only one endpoint. If "1x2" is selected, two end-
points are allowed.

 Note
The KPI service must return a single numeric
value. You could refer to the return value of OData
specification of $count. For example, /b1s/v2/
PurchaseOrders/$count.

In addition to Service Layer $count services, you


can also use a local customized KPI service, which
should allow access from the webclient domain if it
is a Cross-Origin resource. For example, https://
mylocalKPIservice/KPInumber.

Tile Decoration (Mandatory) The following decorations are supported.

• Icon (Default value)


This allows you to select a valid SAPUI5 or Fiori icon
to decorate a tile.
• Local Image
This allows you to select a local image to decorate a
tile.
• Online Image
This allows you to select an online image to decorate
a tile. Please note that the image link must start with
https.

Tile Icon (Mandatory) This field is only visible when the decoration selected is an
Icon, and the default value is sap-icon://customize.
You can explore all available icons in the Icon Explorer .

How to Develop Web Client Extensions


Tile Extensions PUBLIC 121
Field Description

Local Image for Tile (Mandatory) This field is only visible when the decoration selected is a
Local Image. The image type must be PNG, JPG, JPEG
or BMP.

Online Image for Tile (Mandatory) This field is only visible when the decoration selected is an
Online Image. The image type must be PNG, JPG, JPEG
or BMP, and the image URL must start with https.

8. On the Application Summary page, check the application basics, module information, tile details and then
choose Finish.

If you choose the option to package your application, the wizard will automatedly package the application
once it is created successfully.

Upon success, in the mta_archives folder, the .mtar file is generated.

How to Develop Web Client Extensions


122 PUBLIC Tile Extensions
3.7.3 Checking the Log

For the development or trouble shooting purpose, you might need to check the log to figure out how the tool is
running.

To achieve this, in VS code, select View Output Application Wizard.Generators , and you can find the
detailed log messages.

You can also search for the file Application Wizard.Generators.log in folder %userprofile%
\AppData\Roaming\Code\logs\.

3.8 Single Sign-On with Web Client and Extensions

Introduction

This topic introduces a Web App to demonstrate how to leverage OpenID Connect (OIDC) and use the single
sign-on (SSO) scenario from the Web client to partner's extensions.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 123
Prerequisite

• You already understand the basics of the OIDC SSO.


• You already know how to prepare and run the OAuth Node.js web app. This app is inherited from the
Node.js web app and can be considered as an enhanced version.
For more information about the OIDC SSO and the Node.js web app, see the guide Identity and
Authentication Management in SAP Business One on the SAP Help Portal.
• You already know how to create one URL Mashup app, which will be used as a partners' extension in this
document. For more information, see Working with URL Mashup Extensions in Web Client [page 59].
• You have already installed the VS Code Wizard for SAP Business One Web Client Extensions. For more
information, see Packaging Your Apps Using VS Code Wizard for SAP Business One Web Client Extensions
[page 115].

Functionalities

This Web App is based on the Node.js web app and is designed with the following functionalities:

• Read the company ID in the Web client, if available.


• Send the company ID in query parameters when users are signed in.
• With a valid company ID, skip the step of choosing a company.
• Access the Web client View API.
• Hide the logout button in Web client.

Related Information

Working with URL Mashup Extensions in Web Client [page 59]


Packaging Your Apps Using VS Code Wizard for SAP Business One Web Client Extensions [page 115]
Code Changes [page 124]
Creating a URL Mashup App [page 127]
Accessing the URL Mashup App [page 129]

3.8.1 Code Changes

Compared to the Node.js web app, this app has some minor changes in the following files:

• login.html
Add a hidden field companyID when submitting the login request.

<form action="/login">
<input type="text" name="companyID" style="display: none;" />
<input type="submit" value="Sign in" class="btn btn-gray1" />

How to Develop Web Client Extensions


124 PUBLIC Tile Extensions
</form>

Set the field value by parsing the window.location.search on the loading page.

window.onload = function () {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams) {
const companyID = urlParams.get("companyID");
if (companyID) {
let companyIDEle = document.getElementsByName("companyID")[0];
companyIDEle.value = companyID;
}
}
};

• server.js
Before starting the authentication flow, set the company ID in the state URL.

router.get(["/login"], (req, res, next) => {


let stateURL = req.query?.companyID
? home_url + `?companyID=` + req.query?.companyID
: home_url;
res.redirect(
client.authorizationUrl({
scope: "openid",
redirect_uri: redirect_uri,
response_type: "code",
state: stateURL,
})
);
});

• choose_company.js
Get the company ID hint from the return_to parameter.

const return_to = urlParams.get("return_to");


const pos = return_to.indexOf("?");
let companyIDHint;
if (pos != -1) {
let queryString = return_to.substring(pos + 1);
const params = new URLSearchParams(queryString);
companyIDHint = params.get("companyID");
}

Directly choose a company with the company ID.

(async () => {
try{
if (companyIDHint) {
if (await chooseCompany({ companyID: companyIDHint })) {
return;
}
}
...
}catch(e){
alert('Choose company error.')
console.log(e);
}
})();

• home.html
Add a Web client section with two buttons and only show it in the Web client context.

<div id="WebClientContext" style="display:none">

How to Develop Web Client Extensions


Tile Extensions PUBLIC 125
<h2>I become an URL-mashup App running in Web Client.</h2>
<br />
<h3>Access Views in Web Client</h3>
<div>
<button class="btn btn-blue" id="WC-ItemList1">
Open Item List (New Window)
</button>
<button class="btn btn-blue" id="WC-ItemList2">
Open Item List (Current Window)
</button>
</div>
</div>

• home.js
Accordingly, add the press handler button, by which the Web client View API will be invoked.

async function getItemListViewURL() {


// get variant list
var origin = document.location.ancestorOrigins[0];
const BOName = "Items";
const BOType = "System";
let resp = await fetch(
origin + "/extn/api/Variants?objName=" + BOName + "&objType=" + BOType,
{
method: "GET",
credentials: "include",
}
);
let json = await resp.json();
// get variant GUID by variant name
const variantName = "All Items";
let guidValue = "";
json.forEach((item, index, json) => {
if (item.Name === variantName) {
guidValue = item.Guid;
}
});
// get BO list link
let respBoList = await fetch(
origin +
"/extn/api/objectsListView?objName=" +
BOName +
"&objType=" +
BOType +
"&variantGUID=" +
guidValue,
{
method: "GET",
credentials: "include",
}
);
let boListLink = await respBoList.text();
var link = origin + boListLink;
return link;
}

To have a better understanding of this app, you can download and unzip this file to get the source code.

Related Information

Single Sign-On with Web Client and Extensions [page 123]

How to Develop Web Client Extensions


126 PUBLIC Tile Extensions
3.8.2 Creating a URL Mashup App

Context

With the URL of the Web App, you can now open the VS Code Wizard for SAP Business One Web Client
Extensions to create one URL Mashup app for SAP Business One, Web client in the following steps.

Procedure

1. From menu View, click Command Palette... and select Open Template Wizard.
2. Select SAP Business One Web Client Extensions and click Start.
3. For Application Type, select the Tile Extension App and choose Next.
4. For Application Information, enter some basic information about your application (like below), and choose
Next.

Attributes Values

What is the ID of your application? urlmashup-app1

What is the version of your application? 1.0.0

Who is the provider of your application? sapb1

5. For Module Type, select URL Mashup App.


6. For Module Attributes, specify the attributes in the following table.

Attributes Values

What is the name of your module? module1

What is the tile number for your module? 1

There are two tiles, one for the existing window and the other for the new window.

7. For Tile Settings, specify the attributes in the following table.

Attributes Values

What is the title of the tile? A partner's app

Enable a default header with title name? No

What is the subtitle of the tile? url-mashup app

Select the dimensions of the tile. 1x1

Select the tile link method. Existing window

How to Develop Web Client Extensions


Tile Extensions PUBLIC 127
Attributes Values

What is the link for the tile* (See the note below)

Support dynamic content? No

Select a decoration type for the tile Icon

Select an icon for the tile. sap-icon://customize

 Note

For the tile link, passing system built-in query placeholders enclosed with curly brakets is permitted. In
the runtime, when the URL Mashup app is opened in the Web client, placeholders will be replaced by
real parameter values.

In this way, the Web client is able to pass its context information (for example, the current company
ID) to the URL Mashup app, so that the extension app can read the context information for further
processing. For example, with the company ID, the extension app will know which company is chosen in
the Web client and therefore skip the step where a company is chosen, once the SSO is finished.

The supported query placeholders include:


• b1-companyID: the current company's ID
• b1-language: the current user's language
• b1-theme: the current user's theme

In this case, assuming that the Web App is running on the endpoint https://localhost:8000, we
can specify the tile link as follows:

https://localhost:8000?companyID={b1-companyID}&language={b1-
language}&theme={b1-theme}

8. Review the Application Summary and choose Finish.


9. Upon success, the app is created. You can find the package urlmashup-app1_1.0.0.mtar in the
mta_archives folder.
10. Upload this package to the SAP Business One Extension Manager and assign it to a company.

Results

You can properly update this app's configurations in the .env file and start the app with the following
command:

npm install
npm start

Related Information

Running VS Code Wizard for SAP Business One Web Client Extensions [page 118]

How to Develop Web Client Extensions


128 PUBLIC Tile Extensions
Deploying Web Client Extensions on Extension Manager [page 249]
Importing the Mtar Archive and Assigning to a Company [page 250]

3.8.3 Accessing the URL Mashup App

Context

The URL Mashup app is a Web client extension and can only run in the Web client context. Make sure the
company you want to log in to is assigned with the URL Mashup app in the SAP Business One Extension
Manager.

Procedure

1. Log in to the company in the Web client and then navigate to the Extensions tab, where you will find a tile
for your app.

2. Click the tile, in this case, A partner's app tile, and the app will be opened in the current window.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 129
3. Click the Sign in button, and you will enter into the Home page directly, without inputing the login
credentials or choosing a company. This is because of the SSO mechanism and the company ID
placeholder mechanism respectively.

How to Develop Web Client Extensions


130 PUBLIC Tile Extensions
4. For the item list view in the Web client, you can open it either in a new window or in the current window like
below.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 131
 Note

If the Web client session has timed out, you need to manually log in again.

Related Information

Creating a URL Mashup App [page 127]

3.9 Third-Party Cookies for Web Client Extensions

Google Chrome is phasing out support for third-party cookies . This section discusses the impact of this
change on specific scenarios and presents possible solutions.

Impact on Scenarios

A typical scenario that would be impacted by this change involves a Web Client URL mashup application
embedding a partner Web application as an iframe. If this mashup application relies on cookies for
functionality, end-users will no longer be able to access it.

Prerequisites

To mitigate this impact, it is recommended that both the Web Client and the SLD are installed under the same
root domain, which can be achieved in the following ways:

• Option 1: Proxy Server


You can deploy a proxy server as an entry point into the application. This allows every component to use
the same hostname when users access Web Client and extensions.
• Option 2: FQDN with Common Root Domain
During installation, use a Fully Qualified Domain Name (FQDN) with a common root domain.
This is not recognized as a third-party domain, for instance, webclient.customer.domain,
sld.customer.domain, and so on.
For more information, please see SAP Business One Administrator's Guide.

How to Develop Web Client Extensions


132 PUBLIC Tile Extensions
Solution

 Note

Quick Workaround:

You can mark the URL mashup application open in a new tab instead of an iframe.

The following technical solutions are provided for you:

• Partitioned Cookies
• Storage Access API
• OAuth PKCE Flow

You can work with the technical solution for different cases of authentication:

• Case 1: Authentication with Third-Party IDP


Both the third-party IDP and the partner application need to adapt to a technical solution.
• Case 2: Authentication with SAP Business One IDP
The partner application needs to adapt to a technical solution.
• Case 3: No Authentication
In general, the partner application does not need to change. However, if the partner application relies on
some cookies, it also needs to apply a technical solution.

You can download and unzip this file to get the source code.

Partitioned Cookies

It uses expresss-session to create partitioned cookies.

In the file server.js of the sample code, please refer to the sample code change:

app.use(
session({
name: "EXTN.SESSION",
secret: process.env.SECRET,
cookie: { maxAge: timeout, sameSite: "none", secure: true, partitioned:
true }
})
);

You can view a cookie's partition key in the developer tools:

Storage Access API

Please refer to the sample code change. It tries to call document.requestStorageAccess() when the user
chooses the login button. If the user chooses Allow in the pop up window, the extension can read third-party
cookies.

1. static/js/readCookieScript.js

How to Develop Web Client Extensions


Tile Extensions PUBLIC 133
Sample script to request storage access.

async function requestAccess() {


if (!hasAccess) {
console.log(
"Don't have access. Trying again within this click handler, in case
it needed a prompt."
);
try {
// This should now work if it was waiting a prompt
console.log("Before prompt");
await document.requestStorageAccess();
hasAccess = true; // Can assume this was true if above did not reject
console.log("Have access now thanks to prompt");
} catch (error) {
console.log("Permission denied, either blocked by user or browser,
requestStorageAccess Error:", error);
}
hasAccess = await document.hasStorageAccess();
console.log("Updated hasAccess:", hasAccess);
}
updateCookiesOutput();
}

2. static/login.html
Add a script readCookieScript.js.

<head>
<meta charset="UTF-8" />
<title>Sign in</title>
<link type="text/css" href="css/index.css" rel="stylesheet" />
<script type="text/javascript" src="js/readCookieScript.js"></script>
</head>

3. static/js/login.js
Before starting the authentication flow, request access in the button click handler.

document.getElementById("loginButton").addEventListener("click", async
function () {
const companyID = document.getElementsByName("companyID")[0].value;
await requestAccess();
window.location.href = "/login?companyID=" + companyID;
});

This solution works across different web browsers. The popup windows will appear as follows:

• Google Chrome

• Microsoft Edge

How to Develop Web Client Extensions


134 PUBLIC Tile Extensions
• Safari

• Mozilla Firefox

OAuth PKCE Flow


Third-party cookies are not used.

How to Develop Web Client Extensions


Tile Extensions PUBLIC 135
Please refer to the sample Walkthrough for Single Page Apps, it uses oidc-client-ts, which supports using
Authorization Code Grant with Proof Key for Code Exchange (PKCE).

How to Develop Web Client Extensions


136 PUBLIC Tile Extensions
4 UI API Extensions

As of SAP Business One, Web client 10.0 FP 2405, Web Client UI API is available for you. It allows you to create
UI extensions on top of Web Client, so that you can customize UI pages to suit your individual business needs.

With the UI API framework, the dedicated Visual Studio Code plugin, and the Web Client Inspector extension,
you now have the tools to tailor the software to your exact needs and build extensions that streamline your
workflow.

Prerequisites

• Install SAP Business One, Web client 10.0 FP 2405 or higher.


• Install VS Code with the new VS Code Plugin (working on the Chrome browser only).
• Install Web Client Inspector.
• To run your app in VS Code, from SAP Business One, Web client, turn on Developer Mode from
Settings Extensibility .

 Note

In the production mode of SAP Business One, Web client, please turn off the Developer Mode.

Related Information

Visual Studio Code Plugin for Web Client [page 137]


Web Client UI API References [page 154]
Web Client Inspector [page 209]

4.1 Visual Studio Code Plugin for Web Client

The Visual Studio Code Plugin for Web Client provides you with an all-in-one environment. You can write,
debug, preview and test your extensions directly within VS Code. Also, you can build and deploy your
extensions directly to Web Client in a few easy steps.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 137
Related Information

Installing Visual Studio Code Plugin for Web Client [page 8]


Working with UI API Apps in Visual Studio Code Plugin for Web Client [page 138]
Supported Views [page 152]

4.1.1 Working with UI API Apps in Visual Studio Code Plugin


for Web Client

In this section, you will learn how to work with VS Code Plugin, and how to create, run, build, and deploy a UI
API app.

• Creating UI API Apps [page 138]


• Running UI API Apps [page 145]
• Building and Deploying UI API Apps [page 151]

4.1.1.1 Creating UI API Apps

Context

Follow the below procedures to create a UI API app.

Procedure

1. Start the VS code and open an empty folder or a workspace.


2. In the menu bar, select View, click Command Palette..., and input Open Template Wizard.
3. Select the generator for SAP Business One Web Client Extensions and click Start.

How to Develop Web Client Extensions


138 PUBLIC UI API Extensions
4. Select UI API App.

5. Fill in the basic information.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 139
6. Set your module attributes.

For the Select the Object Type field, if you choose UDO/UDT, you need to input the view GUID manually in
the next input box.

 Note

To find an existing view's GUID, refer to Web Client Inspector [page 209].

7. Set your view settings.

How to Develop Web Client Extensions


140 PUBLIC UI API Extensions
For view settings, you can copy the view URL from the Web client and paste it here. The default debug
port is 8081, and the UI API application's static files would be served on this debug port by CORS resource
sharing.

8. Check the application summary and click the Finish button.

9. The project will be created as below.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 141
The folder structure is as follows:

├── .vscode
│ └── launch.json
│ └── settings.json
├── node_modules
├── SalesModule
│ └── webapp
│ ├── controller
│ │ └── SalesOrderDetail.js
│ │ └── utility.js
│ ├── i18n
│ │ └── i18n_en.properties
│ │ └── i18n.properties
│ ├── layout
│ │ └── SalesOrderDetail.layout.json
│ ├── model
│ │ └── models.js
│ └── manifest.json
├── .gitignore
├── app.json
├── gulpfile.js
├── index.js
├── mta.yaml
├── package-lock.json
├── package.json
└── README.md

Here are some descriptions for the generated files.

File Description

launch.json A setup file for the debug server, including the Web client view URL.

SalesOrderDetail.js A controller file for the view layout to define the interactive logic.

How to Develop Web Client Extensions


142 PUBLIC UI API Extensions
File Description

SalesOrderDetail.layout.j A UI layout file to define the overlay controls for views.


son

i18n.properties The properties file for texts contains name-value pairs for each element, in-
cluding a separate file for each supported language with a suffix for the locale,
for example, i18n_de.properties for German, i18n_en.properties for English,
and so on.

models.js The utility file for the customized data model for the view.

manifest.json A descriptor file to define the resource bundles for the UIAPI app.

gulpfile.js A simple configuration file for Gulp to pack the frontend assets.

app.json An app description file to define the app modules and paths for the debug
server.

index.js A Node JS file to start the debug server.

mta.yaml The development descriptor file for build and package.

package.json The file holds various metadata relevant to a NodeJS project. For more infor-
mation, see here .

package-lock.json An automatically generated file for any NPM operations. For more information,
see here .

node_modules The node module folder for Node JS projects.

10. Open and edit the *.layout.json file under the module folder.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 143
Locate the value of the first guid property, and replace it with an existing control's uuid (for example
8p7t18NaXsGaLBaXYHnt5T) on the view, so that the Web client UI API can figure out the location of the
new button you want to place.

When you hover over a property, the help information is displayed.

When a property is misspelled, a warning message is displayed.

When you edit the layout file, the intelligence for auto-complete is displayed.

If more new GUID is needed, right-click the value of "guid" in the *.layout.json file and click the menu
item Generate UUID (Web Client).

How to Develop Web Client Extensions


144 PUBLIC UI API Extensions
 Note

To find an existing control's GUID, refer to Web Client Inspector [page 209].

11. Open and edit the manifest.json file under the module folder for the allowed list. "*" means that all APIs
are allowed.

{
"allowedExternalURLs": "*",
"allowedServiceLayerAPIs": "*"
}

Accordingly, Extension Manager is enhanced to support Service Layer API and the external URLs allowed
list for UI Extension.

• Display the list during the deployment or upload stage in the front end.
• Allow the administrator to confirm or reject the list in the front end.
• Check the data integrity of the allow-list before persisting into the database in the back end.
• Provide OData API to query the UI API extension metadata.

4.1.1.2 Running UI API Apps

Context

Follow the below procedures to run the UI API app.

Procedure

1. Enable the development mode.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 145
By default, the Web client development mode is off. To run the app in VS Code, we need to enable the
development mode as follows.
1. Locate the user profile icon and click Settings.

2. In the Settings dialog box, navigate to the Extensibility panel and enable the Developer Mode.

2. Debug and preview.


1. Right-click the SalesOrderDetail.layout.json file under the module folder and choose the menu
item Preview (Web Client).

How to Develop Web Client Extensions


146 PUBLIC UI API Extensions
2. A new chrome session is created and a local debug service task launched. UI extension static files are
served on this debug port by CORS (Cross Origin Resource Sharing) mechanisms.

3. (Optional) If you want to manually change the Web client view url, go to the $
{workspace}/.vscode/launch.json file and change the attributes startUrl.

{
"SalesModule": {
"SalesOrderDetail": {
"startUrl": "<your web client sales order detail view link>"
}
}
}

4. (Optional) If you want to enable the debug server only, right-click the ${workspace}/app.json file
and choose the menu item Enable Debug Server (Web Client).

How to Develop Web Client Extensions


UI API Extensions PUBLIC 147
5. Log in to the Web client and then you'll see that the customized button is created.

6. Open the *.controller.js file under the module folder and set a breakpoint inside
onButtonClick. Click the new button that you created and go to the VS Code debug session on
the side bar, where you can see that the breakpoint is triggered. Also, variables are retrieved on the VS
Code debug windows.

How to Develop Web Client Extensions


148 PUBLIC UI API Extensions
 Note

Once you open a preview session, in this chrome window, you're able to preview all modules/views
that you've created in the current project. You can set breakpoints in the JS files of all these modules.
Any changes in your JS source files would be monitored in this session. There's no need to reopen a
preview session, but remember to refresh the page for an instant preview. Once you refresh the page,
the breakpoints on the JS file will be inactive. You need to activate them by clicking the button Toggle
Activate Breakpoints on the debug window BREAKPOINTS.

3. Add modules.

Right-click the mta.yaml file and choose the menu item Add Module (Web Client). A new template wizard
opens up. Follow the steps to create a new module.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 149
4. Add views.

Right-click the manifest.json file under the module folder and choose the menu item Add View (Web
Client). A new template wizard opens up. Follow the steps to create a new view.

How to Develop Web Client Extensions


150 PUBLIC UI API Extensions
4.1.1.3 Building and Deploying UI API Apps

Context

Follow the below procedures to build and deploy the UI API app.

Procedure

1. Right-click the mta.yaml file and choose the menu item Build MTA (Web Client).

Upon success, a folder named mta_archives will be created. Find the mtar archive under the project
folder.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 151
 Note

A folder named dist will also be created under the module folder. During the packaging process, gulp
is used as a task runner to build these modules. Any breakpoint set on files under the dist folder
cannot be triggered since these are deployment-ready files, which aren't for debug purposes.

2. To deploy the package, follow the Deploying Web Client Extensions on Extension Manager [page 249] topic.

4.1.2 Supported Views

View Name Available Since

Sales Quotations List SAP Business One 10.0 FP 2405

Sales Quotation Detail SAP Business One 10.0 FP 2405

Sales Orders List SAP Business One 10.0 FP 2405

Sales Order Detail SAP Business One 10.0 FP 2405

Deliveries List SAP Business One 10.0 FP 2405

Delivery Detail SAP Business One 10.0 FP 2405

A/R Invoices List SAP Business One 10.0 FP 2405

A/R Invoice Detail SAP Business One 10.0 FP 2405

Sales Drafts List SAP Business One 10.0 FP 2405

Docs in Approval Process List SAP Business One 10.0 FP 2405

Returns List SAP Business One 10.0 FP 2405

How to Develop Web Client Extensions


152 PUBLIC UI API Extensions
View Name Available Since

Return Detail SAP Business One 10.0 FP 2405

A/R Credit Memos List SAP Business One 10.0 FP 2405

A/R Credit Memo Detail SAP Business One 10.0 FP 2405

Purchase Orders List SAP Business One 10.0 FP 2405

Purchase Order Detail SAP Business One 10.0 FP 2405

Purchase Quotations List SAP Business One 10.0 FP 2405

Purchase Quotation Detail SAP Business One 10.0 FP 2405

Goods Receipt POs List SAP Business One 10.0 FP 2405

Goods Receipt PO Detail SAP Business One 10.0 FP 2405

A/P Invoices List SAP Business One 10.0 FP 2405

A/P Invoice Detail SAP Business One 10.0 FP 2405

A/P Reserve Invoices List SAP Business One 10.0 FP 2405

A/P Reserve Invoice Detail SAP Business One 10.0 FP 2405

A/R Reserve Invoices List SAP Business One 10.0 FP 2405

A/R Reserve Invoice Detail SAP Business One 10.0 FP 2405

Goods Returns List SAP Business One 10.0 FP 2405

Goods Return Detail SAP Business One 10.0 FP 2405

A/P Credit Memos List SAP Business One 10.0 FP 2405

A/P Credit Memo Detail SAP Business One 10.0 FP 2405

Goods Issues List SAP Business One 10.0 FP 2405

Goods Issue Detail SAP Business One 10.0 FP 2405

Approval Decisions List SAP Business One 10.0 FP 2405

Outgoing Payments in Approval Process List SAP Business One 10.0 FP 2405

Return Requests List SAP Business One 10.0 FP 2405

Return Request Detail SAP Business One 10.0 FP 2405

Goods Return Requests List SAP Business One 10.0 FP 2405

Goods Return Request Detail SAP Business One 10.0 FP 2405

Purchase Requests List SAP Business One 10.0 FP 2405

Purchase Request Detail SAP Business One 10.0 FP 2405

Inventory Counting Transactions List SAP Business One 10.0 FP 2405

Inventory Counting Transaction Detail SAP Business One 10.0 FP 2405

Service Contracts List SAP Business One 10.0 FP 2405

Service Contract Detail SAP Business One 10.0 FP 2405

Goods Receipts List SAP Business One 10.0 FP 2405

How to Develop Web Client Extensions


UI API Extensions PUBLIC 153
View Name Available Since

Goods Receipt Detail SAP Business One 10.0 FP 2405

Production Orders List SAP Business One 10.0 FP 2405

Production Order Detail SAP Business One 10.0 FP 2405

Issues for Production List SAP Business One 10.0 FP 2405

Issue for Production Detail SAP Business One 10.0 FP 2405

Receipts from Production List SAP Business One 10.0 FP 2405

Receipt from Production Detail SAP Business One 10.0 FP 2405

Bills of Materials List SAP Business One 10.0 FP 2405

Bill of Materials Detail SAP Business One 10.0 FP 2405

Journal Entries List SAP Business One 10.0 FP 2405

Journal Entry Detail SAP Business One 10.0 FP 2405

Business Partners List SAP Business One 10.0 FP 2405

Business Partner Detail SAP Business One 10.0 FP 2405

Time Sheets List SAP Business One 10.0 FP 2405

Time Sheet Detail SAP Business One 10.0 FP 2405

Activities List SAP Business One 10.0 FP 2405

Activity Detail SAP Business One 10.0 FP 2405

4.2 Web Client UI API References

Scope

Web Client UI framework is based on SAP UI5. However, the UI5 controls will not be exposed directly. Instead,
the controls exposed in Web Client are inherited from UI5 and are specifically customized for Web Client.

The exposed controls are a subset of controls used in Web Client. According to the product roadmap, the
controls will be gradually exposed in each incoming release cycle. This means that only the exposed controls
and exposed properties/events/methods will be supported. Any misusage on unexposed controls is strongly
discouraged.

Not all parts of Web Client user interfaces are allowed to be customized. We support a limited set of list view
and detailed view customization, and will support more in future releases. Please see Supported Views [page
155].

The version of JavaScript supported by the Web Client UI API conforms to ECMAScript 2017 standards, also
known as ES8. Code that utilizes functionality introduced in ECMAScript versions later than ECMAScript 2017
is not supported and may encounter errors during packaging or runtime.

How to Develop Web Client Extensions


154 PUBLIC UI API Extensions
Related Information

Overlay [page 157]


Namespace [page 158]
Controls [page 164]
Data Binding [page 186]
Event Flow [page 190]
Types [page 192]

4.2.1 Supported Views

View Name Available Since

Sales Quotations List SAP Business One 10.0 FP 2405

Sales Quotation Detail SAP Business One 10.0 FP 2405

Sales Orders List SAP Business One 10.0 FP 2405

Sales Order Detail SAP Business One 10.0 FP 2405

Deliveries List SAP Business One 10.0 FP 2405

Delivery Detail SAP Business One 10.0 FP 2405

A/R Invoices List SAP Business One 10.0 FP 2405

A/R Invoice Detail SAP Business One 10.0 FP 2405

Sales Drafts List SAP Business One 10.0 FP 2405

Docs in Approval Process List SAP Business One 10.0 FP 2405

Returns List SAP Business One 10.0 FP 2405

Return Detail SAP Business One 10.0 FP 2405

A/R Credit Memos List SAP Business One 10.0 FP 2405

A/R Credit Memo Detail SAP Business One 10.0 FP 2405

Purchase Orders List SAP Business One 10.0 FP 2405

Purchase Order Detail SAP Business One 10.0 FP 2405

Purchase Quotations List SAP Business One 10.0 FP 2405

Purchase Quotation Detail SAP Business One 10.0 FP 2405

Goods Receipt POs List SAP Business One 10.0 FP 2405

Goods Receipt PO Detail SAP Business One 10.0 FP 2405

A/P Invoices List SAP Business One 10.0 FP 2405

A/P Invoice Detail SAP Business One 10.0 FP 2405

A/P Reserve Invoices List SAP Business One 10.0 FP 2405

How to Develop Web Client Extensions


UI API Extensions PUBLIC 155
View Name Available Since

A/P Reserve Invoice Detail SAP Business One 10.0 FP 2405

A/R Reserve Invoices List SAP Business One 10.0 FP 2405

A/R Reserve Invoice Detail SAP Business One 10.0 FP 2405

Goods Returns List SAP Business One 10.0 FP 2405

Goods Return Detail SAP Business One 10.0 FP 2405

A/P Credit Memos List SAP Business One 10.0 FP 2405

A/P Credit Memo Detail SAP Business One 10.0 FP 2405

Goods Issues List SAP Business One 10.0 FP 2405

Goods Issue Detail SAP Business One 10.0 FP 2405

Approval Decisions List SAP Business One 10.0 FP 2405

Outgoing Payments in Approval Process List SAP Business One 10.0 FP 2405

Return Requests List SAP Business One 10.0 FP 2405

Return Request Detail SAP Business One 10.0 FP 2405

Goods Return Requests List SAP Business One 10.0 FP 2405

Goods Return Request Detail SAP Business One 10.0 FP 2405

Purchase Requests List SAP Business One 10.0 FP 2405

Purchase Request Detail SAP Business One 10.0 FP 2405

Inventory Counting Transactions List SAP Business One 10.0 FP 2405

Inventory Counting Transaction Detail SAP Business One 10.0 FP 2405

Service Contracts List SAP Business One 10.0 FP 2405

Service Contract Detail SAP Business One 10.0 FP 2405

Goods Receipts List SAP Business One 10.0 FP 2405

Goods Receipt Detail SAP Business One 10.0 FP 2405

Production Orders List SAP Business One 10.0 FP 2405

Production Order Detail SAP Business One 10.0 FP 2405

Issues for Production List SAP Business One 10.0 FP 2405

Issue for Production Detail SAP Business One 10.0 FP 2405

Receipts from Production List SAP Business One 10.0 FP 2405

Receipt from Production Detail SAP Business One 10.0 FP 2405

Bills of Materials List SAP Business One 10.0 FP 2405

Bill of Materials Detail SAP Business One 10.0 FP 2405

Journal Entries List SAP Business One 10.0 FP 2405

Journal Entry Detail SAP Business One 10.0 FP 2405

Business Partners List SAP Business One 10.0 FP 2405

How to Develop Web Client Extensions


156 PUBLIC UI API Extensions
View Name Available Since

Business Partner Detail SAP Business One 10.0 FP 2405

Time Sheets List SAP Business One 10.0 FP 2405

Time Sheet Detail SAP Business One 10.0 FP 2405

Activities List SAP Business One 10.0 FP 2405

Activity Detail SAP Business One 10.0 FP 2405

4.2.2 Overlay

Web Client UI API framework makes use of an overlay mechanism to implement the UI customization on
system built-in views, or UDO/UDT views. Generally, the controls' layout in a view is from left to right and from
top to bottom. Each control has a unique GUID. Duplicate GUID in a view will result in a runtime error. To figure
out the position of UI elements, the following positional properties are used in an overlay file.

• before
To insert some new controls before an existing control by specifying its GUID.
• after
To insert some new controls after an existing control by specifying its GUID.
• on
To override or update an existing control by specifying its GUID and some properties or events.

With the GUID and the positional property, the Web Client UI API framework is able to figure out where you
want to locate the new controls or update the existing controls.

The overlay is defined in JSON format and the naming convention for an overlay file is *.layout.json. A
typical overlay content is as below:

{
"controller": "<app-provider.app-name.moduel-name.controller.controller-name>",
"overlay": {
"before": [
{
"guid": "<an-existing-control's-guid>",
"items": [
{
"guid": "<a-new-control's-guid>",
"ctrlType": "<control-type, e.g. b1.sdk.Button>",
"<propery-name>": "<property-value>",
"<event-name>": "<event-handler>"
}
]
}
],
"after": [
{
"guid": "<an-existing-control's-guid>",
"items": [
{
"guid": "<a-new-control's-guid>",
"ctrlType": "<control-type, e.g. b1.sdk.Button>",
"<propery-name>": "<property-value>",
"<event-name>": "<event-handler>"

How to Develop Web Client Extensions


UI API Extensions PUBLIC 157
}
]
}
],
"on": [
{
"guid": "<an-existing-control's-guid>",
"<property-name>": "<property-value>",
"<event-name>": "<event-handler>"
}
]
}
}

 Note

• The controller property is a reference to the JavaScript file, in which you can define some
interactive logic. Some code snippets on how to use the overlay mechanism can be found in the
following chapters.
• Any invalid property or improper positioned property in the JSON schema will probably result in a
runtime error on loading. To mitigate these errors, it is recommended to use the development tool
Visual Studio Code Plugin for Web Client [page 137], which provides a static checking according to a
predefined JSON schema for overlay files.
• In some cases, customers may want to move their UDFs from the system UDF section to their
customized section. To achieve this, the property move can be used in the overlay.

{
"controller": "<app-provider.app-name.moduel-name.controller.controller-
name>",
"overlay": {
"move": [
{
"guid": "<an-existing-UDF's-guid>",
"targetGroupGuid": "<a-group-in-a-customized-section>"
}
]
}
}

4.2.3 Namespace

Namespaces offer a way to sequester different sections of code in order to avoid conflicts and overlapping
functions. There are two distinct approaches we provide for you to use.

Controls Namespace

The global namespace b1.sdk is used to host public controls and related types for control properties. This
helps in managing all controls and properties systematically with minimal chances of conflict.

For instance, if you want to reference Button, use b1.sdk.Button. If you want to assign a value to the
buttonType property in JavaScript, use b1.sdk.ButtonType.Accept.

How to Develop Web Client Extensions


158 PUBLIC UI API Extensions
Extensions Namespace

We also provide a namespace for separating extensions from different partners. This namespace is defined as a
combination of three attributes: provider name, app name, and module name.

The structure of the namespace is as follows:

namespace = provider name + app name + module name

This namespace is generated automatically when you run the UI API creation wizard. It is subsequently stored
in the manifest.json file.

By utilizing the namespace mechanism, we can isolate extensions from different partners and the Web Client,
helping to prevent code conflicts and smooth the operation of your application.

4.2.4 SDKEnv

It is the type of the current SDK environment and has the following functions.

Function Declaration Description

ActiveView(): object Gets the active view.

showMessageBox(messageBox: object): Promise Shows the message box.

showToastMessage(messageText: string): Promise Shows a toast message.

getService(): object Gets supported service.

open(url: string): Promise Opens an external URL or a relative View Link URL.

 Note

For the above function declaration, it is described in the TypeScript syntax.

Related Information

ActiveView [page 160]


showMessageBox [page 160]
showToastMessage [page 161]
open [page 161]
getService [page 162]

How to Develop Web Client Extensions


UI API Extensions PUBLIC 159
4.2.4.1 ActiveView

It is the type of the Web Client event and has the following functions. You can use it in the event handler.

For the function ActiveView, controls can be accessed by providing the GUID as follows:

const oView = await oInst.ActiveView();


const oButton = await oView.Button(buttonGuid);
const oInput = await oView.Input(inputGuid);
const oText = await oView.StaticText(staticTextGuid);
const oCheckBox = await oView.CheckBox(checkBoxGuid);
const oComboBox = await oView.ComboBox(comboBoxGuid);
const oSection = await oView.Section(sectionGuid);
const oGrid = await oView.Grid(gridGuid);

For the function ActiveView, the methods below can be used for both the List View and the Detailed View:

List view methods


Method Declartaion Description

getGuid(): object Returns the GUID of the list view.

getViewType() : object Returns the view type.

hideBusy(): Promise Hides the busy indicator of the view.

showBusy(): Promise Shows the busy indicator of the view.

getCustomizedData(modelName: string): Promise Returns the data of model with name modelName, which is
defined in the extension.

setCustomizedData(data: object, modelName: string): Sets the data to the model with name modelName, which is
Promise defined in the extension.

Detailed view methods


Method Declartaion Description

getGuid(): object Returns the GUID of the list view.

getViewType() : object Returns the view type.

hideBusy(): Promise Hides the busy indicator of the view.

showBusy(): Promise Shows the busy indicator of the view.

getCustomizedData(modelName: string): Promise Returns the data of model with name modelName, which is
defined in the extension.

setCustomizedData(data: object, modelName: string): Sets the data to the model with name modelName, which is
Promise defined in the extension.

4.2.4.2 showMessageBox

• For the function showMessageBox, its parameter type is an object, which is described in the TypeScript
syntax below.

// Typescript syntax

How to Develop Web Client Extensions


160 PUBLIC UI API Extensions
type messageBoxParameterType = {
messageBoxType: b1.sdk.MessageBoxType;
messageText: string;
messageOtions?: {
title: string;
initialFocus?: b1.sdk.MessageBoxAction;
actions: b1.sdk.MessageBoxAction[];
};
};

A typical usage of showMessageBox is as follows:

testMessageBox: async function (oEnv, oEvent) {


let oAction = await oEnv.showMessageBox(
b1.sdk.MessageBoxType.Warning,
"I am a Warning message.",
{
title: "MessageBox Test",
initialFocus: b1.sdk.MessageBoxAction.Cancel,
actions: [
b1.sdk.MessageBoxAction.Ok,
b1.sdk.MessageBoxAction.Cancel,
],
}
);
let toastMessage =
oAction == b1.sdk.MessageBoxAction.OK
? "OK button is clicked."
: "Cancel button is clicked.";
oEnv.showToastMessage(toastMessage);
}

4.2.4.3 showToastMessage

For the function showToastMessage, its parameter type is a string.

async "onShowName" (oEnv, oEvent) {


const oView = await oEnv.ActiveView();
const oData = await oView.getData();
if (oData.CardName) {
await oEnv.showToastMessage(oData.CardName);
} else {
await oEnv.showToastMessage("name does not exist");
}
}

4.2.4.4 open

For the function open, the external URL should be predefined in allowedExternalURLs.

A typical usage of open is as follows:

await oEnv.open("https://www.google.com");
await oEnv.open("/webx/index.html#webclient-ORDR&/Objects/ORDR/List");

How to Develop Web Client Extensions


UI API Extensions PUBLIC 161
4.2.4.5 getService

For the function getService, supported service APIs including Service Layer APIs, View Link APIs, and
external service APIs will be returned. Service Layer APIs and external service APIs support the methods get,
post, put, patch and delete, View Link APIs support the method get. Internally, Service Layer oData V4 is
used.

Methods in Service Layer APIs


Method Declartaion Description

get(url: string, headers?: object): Promise Get data

post(url: string, data: object, headers?: object): Promise Post data

put(url: string, data: object, headers?: object): Promise Put data

patch(url: string, data: object, headers?: object): Promise Patch data

delete(url: string, headers?: object): Promise Delete data

Methods in View Link APIs


Method Declaration Description

get(url: string, headers?: object): Promise Get data

Methods in External Service APIs


Method Declaration Description

get(url: string, options: object): Promise Get data

post(url: string, data: object/string, options: object): Prom- Post data


ise

put(url: string, data: object/string, options: object): Promise Put data

patch(url: string, data: object/string, options: object): Prom- Patch data


ise

delete(url: string, data: object/string, options: object): Delete data


Promise

The parameter data can be either an object or a string. The parameter options should have the following
members:

Name Type Description

headers object Addtional headers to be sent with the request

mode string The mode of the request for handling cross-origin requests, for example,
"cors" (default), "no-cors", "same-origin"

The response has the following methods:

Method Declaration Description

isSuccess(): boolean Returns true if the response is successful, otherwise, returns


false

How to Develop Web Client Extensions


162 PUBLIC UI API Extensions
Method Declaration Description

getStatus(): int Returns the status code of the response

getHeaders(): object Returns headers of the response (not used by external serv-
ices)

getData(): object Returns data of the response

A typical usage of Service Layer APIs is as follows:

const services = await oEnv.getService();


const serviceLayer = services.ServiceLayer;
const response = await serviceLayer.get("Orders?$filter=PropertyNotExist eq 1",
{
"Customized-Header-1": "customized header value...",
"Customized-Header-2": "customized header value..."
});
const response = await serviceLayer.post("Orders",
{
"CardCode": "C70000",
"DocDueDate": "2014-04-04",
"DocumentLines": [
{
"ItemCode": "A00001",
"Quantity": "100",
"UnitPrice": "30"
}
]
},
{
"Customized-Header-1": "customized header value...",
"Customized-Header-2": "customized header value..."
});
const isSuccess = response.isSuccess();
const status = response.getStatus();
const headers = response.getHeaders();
const data = response.getData();
this.showMessageBox(oEnv, isSuccess, status, headers, data);

A typical usage of View Link APIs is as follows:

const services = await oEnv.getService();


const viewLinkService = services.ViewLinkService;

const BOName = "Orders";


const BOType = "System";

const response = await viewLinkService.get("/api/Variants?objName=" + BOName +


"&objType=" + BOType);

For more information about View Link APIs, please refer to Working with APIs That Generate Web Client Views
URLs [page 257].

A typical usage of external service APIs is as follows:

const services = await oEnv.getService();


const externalService = services.ExternalService;
const getResponse = await externalService.get(
"http://localhost:3000/service/", {
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Authorization": "Bearer MGQ0NjQyMTItNWQ5MS00YjQxLTk5YjItNTA4Mzk1NDliMmYx"
},

How to Develop Web Client Extensions


UI API Extensions PUBLIC 163
mode: "cors"
})
const postResponse = await externalService.post(
"http://localhost:3000/service/", {
username: "test123",
password: "123456"
}, {
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Authorization": "Bearer MGQ0NjQyMTItNWQ5MS00YjQxLTk5YjItNTA4Mzk1NDliMmYx"
},
mode: "cors"
}).catch((e) = {
console.log(e)
});
console.log(postResponse.getData())
const response2 = await externalService.post(
"http://localhost:3000/service/",
"username=testUser&password=123456&check_type=password",
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
mode: "cors"
})

4.2.5 Controls

A control is a core element that provides users with the means to interact with the Web Client application.
Controls are UI elements, such as buttons, input fields, or grid/table that can handle user interaction, maintain
their state, and manage any relevant data. All controls follow SAP's Fiori design guidelines, making it easy to
create a consistent user interface and user experience across all SAP applications. Each control comes with
properties, aggregation, events, and methods.

• Properties
These are the values that influence the behavior or the appearance of a control, for example, the text on a
button, the state of a checkbox (checked or unchecked), and so on.
• Aggregations
These define the relationship controls have to eachother. It means controls can have child controls. For
example, a grid control can have multiple column controls.
• Events
User interactions with controls can trigger events. For example, a button press, an input field change, and
so on.
• Methods
These are functions that are part of the control and can be used to perform actions or manipulate the
control’s data or its visual representation. They are used either to set or get properties, or to trigger events.

In the Web Client UI API framework, there is a direct relationship between properties and methods. Typically,
for each property, there are corresponding "getter" and "setter" methods, which is a common convention in
many programming languages and frameworks.

For instance, if there's a property named "value" in a control, the control will often provide the following
methods:

• getValue: This is a getter method that retrieves the current value of the property.

How to Develop Web Client Extensions


164 PUBLIC UI API Extensions
• setValue: This is a setter method that sets a new value for the property.

All "getter" and "setter" methods adhere to camel case for naming conventions. In camel case, the first word
starts with lowercase, and subsequent words within the name have their first letter capitalized. These methods
allow for interaction with the property. The getter method is used to read the property's value, while the setter
method is used to change the property's value. However, it's not always the case that every single property will
have a functional getter and a setter. Very few properties may be read-only, while most other properties are
readable and writable. For this case, calling the setter methods on read-only properties would have no effect.

 Note

For the getter and setter methods, in the following chapters, we will not explicitly list them for each control.
Instead, only specific methods available for each control will be documented.

The following controls are available:

• Button [page 165]


• Input [page 167]
• StaticText [page 170]
• CheckBox [page 172]
• ComboBox [page 174]
• Section [page 177]
• Grid [page 179]

4.2.5.1 Button

Available as of SAP Business One 10.0 FP 2405

A button is a control that enables users to trigger actions. For the Button UI, you can define a text, an
icon, or both. You can also specify whether the text or the icon is displayed first. You can choose from a set
of predefined ButtonTypes that offer different styling to correspond to the triggered action. You can set the
Button as enabled or disabled. An enabled Button can be pressed by clicking or tapping it, and it changes its
style to provide visual feedback to the user that it is pressed or is being hovered over with the mouse cursor. A
disabled Button appears inactive and cannot be pressed.

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

enabled boolean No true No Determines


whether the con-
trol is enabled

How to Develop Web Client Extensions


UI API Extensions PUBLIC 165
Name Type Mandatory Default Value Read Only Description

text string No '' No Displays text

buttonType Enum No Default No See


b1.sdk.Butto
nType

tooltip string No '' No Tooltip text when a


user hovers on a
control

icon string No '' No Represents an


RFC3986 con-
formant URI

visible boolean No true No Determines


whether the con-
trol is visible

Events

Name Description

press Fired when the user clicks or taps on the control.

Methods

getter and setter

Get and set each property.

Usage

• Define the control in layout file.

{
"guid": "CUSTOM_CONTROL_GUID_NEW_BUTTON1",
"ctrlType": "b1.sdk.Button",
"text": "testing...",
"icon": "sap-icon://accept",
"enabled": true,
"visible": true,
"buttonType": "Default",
"tooltip": "I am in testing..."
},
{
"guid": "CUSTOM_CONTROL_GUID_NEW_BUTTON2",
"ctrlType": "b1.sdk.Button",
"text": "Click Me!!!",

How to Develop Web Client Extensions


166 PUBLIC UI API Extensions
"icon": "sap-icon://accept",
"enabled": true,
"visible": true,
"buttonType": "Default",
"tooltip": "I am the tester",
"press": {
"procName": "onButtonClick"
}
}

• Interact with the control in controller file.

testButton: async function (oInst, oEvent) {


// Select the control in the current view
const oView = await oInst.ActiveView();
const oButton = await oView.Button("CUSTOM_CONTROL_GUID_NEW_BUTTON1");
// Assign values to the control properties
await oButton.setText("HelloWorld");
await oButton.setTooltip("I am a button");
await oButton.setEnabled(await !oButton.getEnabled());
await oButton.setVisible(await !oButton.getVisible());
await oButton.setIcon("sap-icon://accelerated");
await oButton.setButtonType(b1.sdk.ButtonType.Accept);
console.log(await oButton.getGuid());
console.log(await oButton.getText());
}

4.2.5.2 Input

Available as of SAP Business One 10.0 FP 2405

An input allows the user to enter and edit text or numeric values in one line.

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

editable boolean No true No Determines


whether the con-
trol is editable

enabled boolean No true No Determines


whether the con-
trol is enabled

mandatory boolean No false No Determines


whether to display
a red asterisk be-
fore the label text

How to Develop Web Client Extensions


UI API Extensions PUBLIC 167
Name Type Mandatory Default Value Read Only Description

inputType enum No String No See


b1.sdk.Input
Type

tooltip string No '' No Tooltip text when


the user hovers
over this control

visible boolean No true No Determines


whether the con-
trol is visible

lable string No '' No Control introduc-


tion / title

hideLable boolean No false Yes Whether to hide la-


bel

textDirection enum No LTR No See


b1.sdk.TextD
irection

textAlign enum No Right is the No See


default value if b1.sdk.TextA
the inputType is lign
of currency type,
while Begin is the
default value for
other input types.

maxLength number No 0 No Maximum number


of characters for
input value. Value
'0' means the fea-
ture is switched
off. The length is
without limitation.

value string No '' No The value of the


control

wrapping boolean No false No Whether to break a


new line if not edit-
able

valueState enum No None No See


b1.sdk.Value
State

valueStateText string No '' No An additional text


show around for
valueState

showSuggestion boolean No false No Whether to show


suggestion when
user inputs

How to Develop Web Client Extensions


168 PUBLIC UI API Extensions
Name Type Mandatory Default Value Read Only Description

suggestionItems Item [] No [] No Items displayed


in the sugges-
tion popup, see
b1.sdk.Item

currency string No null No The currency part


($, EUR…) of
a Currency In-
put (Sum, Tax,
Price…). When the
input binds the
currency property,
the currency value
will be validated
and can not be
empty.

Events

Name Description

change Fired when the value is changed.

suggest Fired when user input and showSuggestion is true.

The event parameter mParameters should have the following members:

change
Name Type Description

value string The new value of the control

oldValue string The old value of the control

suggest
Parameter Type Description

suggestValue string The current value which has been typed


in the input

Methods

getter and setter

Get and set each property.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 169
Usage

• Define an Input control in layout file.

{
"guid": "pzEqzxS31NR6EfCAEiy4xF",
"ctrlType": "b1.sdk.Input",
"enabled": true,
"editable": true,
"tooltip": "it is a hint",
"visible": true,
"label": "I am in testing...",
"value": "Initial value",
"inputType": "String",
"wrapping": true,
"valueState": "Success",
"textDirection": "LTR",
"valueStateText": "Success State",
"change": {
"procName": "onInputChange"
}
}

• Interact with the Input control in controller file.

testInput: async function (oInst, oEvent) {


const guid = "pzEqzxS31NR6EfCAEiy4xF";
const oView = await oInst.ActiveView();
const oInput = await oView.Input(guid);
// Not allowed, as hideLabel is a ready only property
// oInput.hideLabel = !oInput.hideLabel;
// oInput.inputType = b1.sdk.Measure;
await oInput.setTooltip("this is a hint");
await oInput.setEditable(!oInput.editable);
let oldValue = await oInput.getValue();
await oInput.setValue("updated value");
await oInput.setMandatory(await !oInput.getMandatory());
await oInput.setLabel("I am in testing...");
await oInput.setValueState("Warning");
console.log("label:", await oInput.getLabel());
console.log("editable:", await oInput.getEditable());
console.log("visible :", await oInput.getVisible());
},
onInputChange: async function (oInst, oEvent) {
const oInput = await oEvent.getSource();
console.log("Guid of the input firing the change event:", await
oInput.getGuid());
console.log("parameters:", oEvent.getParameters());
// Get the updated value and old value from the event parameters
let value = oEvent.getParameter("value");
let oldValue = oEvent.getParameter("oldValue");
console.log("changed value:", value);
console.log("old value:", oldValue);
}

4.2.5.3 StaticText

Available as of SAP Business One 10.0 FP 2405

How to Develop Web Client Extensions


170 PUBLIC UI API Extensions
The StaticText control can be used to embed longer text paragraphs that need text wrapping into your app.
If the configured text value contains HTML code or script tags, those will be escaped.

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

lable string No '' No A label displayed


before a control

hideLable boolean No false Yes Determines


whether or not to
to hide a label

text string No '' No Determines the


text to be dis-
played

*maxLines number No N/A No Limits the number


of lines for wrap-
ping texts

*renderWhite- boolean No true No Determines


space whether or not the
whitespace will be
preserved

wrapping boolean No true No Enables text wrap-


ping

*wrappingType enum No Normal No See b1/sdk/


WrappingType

visible boolean No Yes No Determines


whether the con-
trol is visible

tooltip string No '' No Tooltip text when


the user hovers on
this control

 Note

• For maxLines, the multi-line overflow indicator depends on the browser line clamping support. For
such browsers, this will be shown as an ellipsis. For other browsers, the overflow will be hidden.
• For renderWhitespace, it specifies how whitespace and tabs inside the control are handled. If true,
whitespace will be preserved by the browser. Depending on the wrapping property, text will either only
wrap on line breaks or wrap when necessary, and on line breaks.
• For wrappingType, it takes effect only when the wrapping property is set to true.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 171
Events

No events.

Methods

getter and setter

Get and set each property.

Usage

• Define a StaticText control in layout file.

{
"guid": "sBp9dFHsiWUMmQE3wAeF5Z",
"ctrlType": "b1.sdk.StaticText",
"text": "testing...",
"wrapping": false,
"visible": true,
"tooltip": "I am in testing..."
}

• Interact with the StaticText control in controller file.

testStaticText: async function (oInst, oEvent) {


// Select the control in the current view
const oView = await oInst.ActiveView();
const oText = await oView.StaticText("sBp9dFHsiWUMmQE3wAeF5Z");
// Assign values to the control properties
await oText.setText("HelloWorld");
await oText.setTooltip("I am a text");
await oText.setVisible(await !oText.getVisible());
await oText.setWrapping(true);
console.log(await oText.getGuid());
console.log(await oText.getText());
}

4.2.5.4 CheckBox

Available as of SAP Business One 10.0 FP 2405

It is a control that allows the user to set a boolean value, such as true/false or yes/no for an item.

How to Develop Web Client Extensions


172 PUBLIC UI API Extensions
Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

selected boolean No false No Determines


whether the con-
trol is selected

lable string No '' No Control introduc-


tion / title

hideLable boolean No false Yes Determines


whether or not to
hide the label

tooltip string No '' No Tooltip text when


the user hovers
the cursor over
this control

editable boolean No true No Determines


whether the con-
trol is editable

visible boolean No true No Determines


whether the con-
trol is visible

Events

Name Description

select Fired when the checkbox is selected / deselected.

Methods

getter and setter

Get and set each property.

Usage

• Define a CheckBox control in layout file.

{
"guid": "tbmGK6QJaacC7EkYUWUt8K",

How to Develop Web Client Extensions


UI API Extensions PUBLIC 173
"ctrlType": "b1.sdk.CheckBox",
"label": "I am in testing...",
"hideLabel": true,
"tooltip": "This is a hint",
"editable": true,
"visible": true,
"select": {
"procName": "onSelectChange"
}
}

• Interact with the CheckBox control in controller file.

testCheckBox: async function (oInst, oEvent) {


const guid = "tbmGK6QJaacC7EkYUWUt8K";
const oView = await oInst.ActiveView();
const checkBox = await oView.CheckBox(guid);
await checkBox.setSelected(await !checkBox.getSelected());
await checkBox.setTooltip("this is a hint");
await checkBox.setEditable(await !checkBox.getEditable());
await checkBox.setVisible(await !checkBox.getVisible());
await checkBox.setLabel("I am in testing...");
// Not allowed, as hideLabel is a ready only property
// checkBox.hideLabel = !checkBox.hideLabel;
console.log("selected:", await checkBox.getSelected());
},
onSelectChange: function (oInst, oEvent) {
const checkBox = await oEvent.getSource();
console.log(
"Guid of the checkbox firing the select event:",
await checkBox.getGuid()
);
console.log("parameters:", oEvent.getParameters());
console.log("selected:", oEvent.getParameter("selected"));
}

4.2.5.5 ComboBox

Available as of SAP Business One 10.0 FP 2405

This control is a drop-down list for selecting and filtering values. The control represents a drop-down menu with
a list of the available options and a text input field to narrow down the options.

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

editable boolean No true No Determines


whether the con-
trol is editable

How to Develop Web Client Extensions


174 PUBLIC UI API Extensions
Name Type Mandatory Default Value Read Only Description

selectedKey string No '' No Key of the selected


item

tooltip string No '' No Tooltip text when


the user hovers on
this control

visible boolean No true No Determines


whether the con-
trol is visible

lable string No '' No Control introduc-


tion / title

hideLable boolean No false Yes Determines


whether or not to
hide a label

mandatory boolean No false No Determines


whether or not to
select a value

filterSecondary- boolean No false No Determines


Values whether or not a
filter applies to ad-
ditionalText

showSecondary- boolean No false No Determines


Values whether or not to
display additional-
Text

items Item[] No [] No Items contained


within this
control (see
b1.sdk.Item)

valueState string No None No See


b1.sdk.VaueS
tate

valueStateText string No '' No Additional text


to show for
valueState

Events

Name Description

change Fired when one of the ComboBox Item is selected

loadItems Fired when the user opens the dropdown list to load data

How to Develop Web Client Extensions


UI API Extensions PUBLIC 175
The event parameter mParameters should have the following members:

Name Type Description

value string The new value of the control

oldValue string The old value of the control

Methods

getter and setter

Get and set each property.

getSelectedText

Get the text of the selected item.

getSelectedText() : string

getItems

Get items contained within this control.

getItems() : b1.sdk.Item[]

Usage

• Define a ComboBox control in layout file

{
"guid": "1PFitf7cF8uH6Sq5iPfXLk",
"ctrlType": "b1.sdk.ComboBox",
"label": "Static ComboBox",
"enabled": true,
"visible": true,
"tooltip": "ComboBox tooltip",
"selectedKey": "Y",
"items": [
{
"key": "Y",
"text": "Yes",
"additionalText": "Yes !!!",
"enabled": true
},
{
"key": "N",
"text": "No",
"additionalText": "No !!!",
"enabled": true
}
],
"change": {
"procName": "onChange"
}

How to Develop Web Client Extensions


176 PUBLIC UI API Extensions
}

• Interact with the ComboBox control in the controller file

testComboBox: async function (oInst, oEvent) {


const oView = await oInst.ActiveView();
const oComboBox = await oView.ComboBox("1PFitf7cF8uH6Sq5iPfXLk");
await oComboBox.setValueState(b1.sdk.ValueState.Information);
await oComboBox.setMandatory(await !oComboBox.getMandatory());
await oComboBox.setShowSecondaryValues(await !
oComboBox.getShowSecondaryValues());
console.log("selected text: ", await oComboBox.getSelectedText());
console.log("mandatory: ", await oComboBox.getMandatory());
},
// Handle the ComboBox change event.
// The event is fired by UIAPI or by manually selecting one value from the
drop down list.
onChange: async function (oInst, oEvent) {
const oComboBox = await oEvent.getSource();
console.log(
"Guid of the comboBox firing the change event:",
await oComboBox.getGuid()
);
console.log("parameters:", oEvent.getParameters());
// Get the updated value from the event parameters
let sValue = oEvent.getParameter("value");
let oldValue = oEvent.getParameter("oldValue");
// Set the value to the ComboBox
await oEvent.getSource().setSelectedKey(sValue);
}

4.2.5.6 Section

Available as of SAP Business One 10.0 FP 2405

A section is a top-level information container which is generally used in an object page layoutto aggregate
subsections containing second-level information.

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

visible boolean No true No Determines


whether the con-
trol is visible

text string No Start No Section title

How to Develop Web Client Extensions


UI API Extensions PUBLIC 177
Name Type Mandatory Default Value Read Only Description

subSections SubSection[] No [] No Subsections in a


section, see
b1.sdk.SubSe
ction

showTitle boolean No true No Determines


whether the text is
visible

Events

No events.

Methods

getter and setter

Get and set each property.

Usage

• Define a Section control in layout file

{
"guid": "2uYDkRidQceMnh26HSuU61",
"ctrlType": "b1.sdk.Section",
"text": "Section 4",
"subSections": [
{
"guid": "15Tvy2ADMLsq7TJdJjEQDq",
"ctrlType": "b1.sdk.SubSection",
"text": "SubSection 4.1",
"groups": [
{
"guid": "5mWFpvxL7BKRc2Vmm7PMwv",
"ctrlType": "b1.sdk.Group",
"text": "Group 4.1.1",
"items": [
{
"guid": "vB2cRy8RMqNRJTrnZZHQih",
"label": "Test Label",
"ctrlType": "b1.sdk.StaticText",
"text": "This is a test description."
}
]
}
]
},
{

How to Develop Web Client Extensions


178 PUBLIC UI API Extensions
"guid": "sBp9dFHsiWUMmQE3wAeF5Z",
"ctrlType": "b1.sdk.SubSection",
"text": "SubSection 4.2",
"groups": [
{
"guid": "emC5fRi184o9eg62oHJ8QC",
"ctrlType": "b1.sdk.Group",
"text": "Group 4.2.1",
"items": [
{
"guid": "eUdC8srWcJeGkd3VjajTcD",
"label": "Test Label",
"ctrlType": "b1.sdk.Input"
}
]
},
{
"guid": "23QcpyC9EorFa3oRWaiKBN",
"ctrlType": "b1.sdk.Group",
"text": "Group 4.2.2",
"items": [
{
"guid": "prin72R1LTSrJPi1xZ5rFC",
"label": "Test Label",
"ctrlType": "b1.sdk.Input"
}
]
},
{
"guid": "4GmiJAX6QDprCZp6z4xS92",
"ctrlType": "b1.sdk.Group",
"text": "Group 4.2.3",
"align": "right",
"items": [
{
"guid": "tjX4VQ2JcEYRcqsXe2JmDN",
"label": "Test Label",
"ctrlType": "b1.sdk.StaticText",
"text": "It is a group test for right align."
}
]
}
]
}
]
}

4.2.5.7 Grid

Available as of SAP Business One 10.0 FP 2405

This control provides a comprehensive set of features for displaying and dealing with vast amounts of data.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 179
Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

title string No No Title of the grid

rowsData array Yes Yes The property for


binding data

visibleRowCount int No 20 No Number of visible


rows of the grid

visible boolean No true No Determines


whether the con-
trol should be visi-
ble on the screen

selectionMode SelectionMode No multiple No Selection mode of


the table

columnHeader- int No No Header row height


Height in pixel

columnHeaderVi- boolean No true No Determines


sible whether the col-
umn header is visi-
ble or not

enableSelectAll boolean No true No Specifies if a


select-all button
should be dis-
played in the top
left corner. This
button is only dis-
played if the row
selector is visible
and the selection
mode is set to any
kind of multi selec-
tion.

firstVisibleRow int No 0 No The first visible


row

rowHeight int No No Row height in pixel

selectionBehavior b1.sdk.Grid.Selec- No RowSelector No Selection behav-


tionBehavior ior of the Ta-
ble. This property
defines whether
the row selector
is displayed and
whether the row,
the row selector,
or both can be
clicked to select a
row.

How to Develop Web Client Extensions


180 PUBLIC UI API Extensions
Name Type Mandatory Default Value Read Only Description

showNoData boolean No true No Determines


whether to show
the no data over-
lay or not once the
table is empty. If
set to false, the ta-
ble will just show a
grid of empty cells.

width string No 100% No Width of the Table

noData string No No The text in a table


in case of no data

busy boolean No false No Determines


whether the con-
trol is currently in
a busy state.

Events

Name Description

ItemPressed Fired when the cell of a row is pressed

rowSelectionChange Fired when the row selection of the grid has been changed

firstVisibleRowChanged Fired when the first visible row is changed

sort Fired when the grid is sorted

filter Fired when the grid is filtered

paste Fired when the user pastes contents from the clipboard to
the table

The event parameter mParameters should have the following members:

Name Type Description

value string The new value of the control

oldValue string The old value of the control

Methods

getter and setter

Get and set each property.

getSize

How to Develop Web Client Extensions


UI API Extensions PUBLIC 181
Get binding data size.

getSize(mParameters?: object) : int

getEditable

Get the editable status.

getEditable(mParameters?: object) : boolean

getSelectionMode

Get selection mode of the grid.

getSelectionMode(mParameters?: object) : b1.sdk.Grid.SelectionMode

clearSelection

Removes complete selection.

clearSelection(mParameters?: object) : void

getSelectedIndices

Zero-based indices of selected items, wrapped in an array. An empty array means "no selection".

getSelectedIndices(mParameters?: object) : int[]

getAllSelectedIndices

The actual selected items indices in data, not the indices on the UI (maybe the data is sorted / filtered).

getAllSelectedIndices(mParameters?: object) : int[]

setSelectedIndex

Sets a new value for property selectedIndex.

Zero-based index of selected item. Index value for no selection is -1. When multi-selection is enabled, and
multiple items are selected, the method returns the lead selected item. Sets the zero-based index of the
currently selected item. This method removes any previous selections. When the given index is invalid, the call
is ignored.

When called with a value of null or undefined, the default value of the property will be restored.

Default value is -1.

setSelectedIndex(mParameters?: object) : Promise

The event parameter mParameters should have the following members:

Name Type Description

iSelectedIndex int New value for property


selectedIndex

addSelectionInterval

How to Develop Web Client Extensions


182 PUBLIC UI API Extensions
Adds the given selection interval to the selection. In case of single selection, only iIndexTo is added to the
selection.

addSelectionInterval(mParameters?: object) : Promise

The event parameter mParameters should have the following members:

Name Type Description

iIndexFrom int Index from which the selection should


start

iIndexTo int Index up to which to select

removeSelectionInterval

Removes the given selection interval from the selection. In case of single selection, only iIndexTo is removed
from the selection.

removeSelectionInterval(mParameters?: object) : Promise

The event parameter mParameters should have the following members:

Name Type Description

iIndexFrom int Index from which the deselection


should start

iIndexTo int Index up to which to select

getRowData

Get of binding data.

getRowData(mParameters?: object) : Object

The event parameter mParameters should have the following members:

Name Type Description

iRowIndex int The index of row

getFilteredIndices

Get the indices of filtered data.

getFilteredIndices(mParameters?: object) : Object[]

ready

The grid is initialized.

ready(mParameters?: object) : Promise

setFilter

How to Develop Web Client Extensions


UI API Extensions PUBLIC 183
Sets a filter..

setFilter(mParameters?: object) : void

resetSort

Clear sorting in the grid columns.

resetSort(mParameters?: object) : void

removeRows

Remove the rows of data.

removeRows(mParameters?: object) : void

The event parameter mParameters should have the following members:

Name Type Description

indices int[] The indices of data to be removed

Column

Get column by guid.

Column(mParameters?: object) : Object

The event parameter mParameters should have the following members:

Name Type Description

sCtrlGuid string The column control guid

getColumns

Get all the columns.

getColumns(mParameters?: object) : Column[]

Usage

• Define a Grid control in layout file

{
"guid": "2g9uibjwCxiqPpFrz8NiwY",
"ctrlType": "b1.sdk.Grid",
"title": "Grid Testing",
"visibleRowCount": 20,
"selectionMode": "multiple",
"columnHeaderHeight": 20,
"columnHeaderVisible": true,
"enableSelectAll": true,
"firstVisibleRow": 0,
"rowHeight": 20,
"selectionBehavior": "Row",

How to Develop Web Client Extensions


184 PUBLIC UI API Extensions
"showNoData": false,
"width": "auto",
"noData": "No Data 2",
"busy": false,
"itemPressed": {
"procName": "onItemPressed"
},
"rowSelectionChange": {
"procName": "onSelectionChanged"
},
"firstVisibleRowChanged": {
"procName": "onFirstVisibleRowChanged"
},
"filter": {
"procName": "onFilter"
},
"sort": {
"procName": "onSort"
},
"paste": {
"procName": "onPaste"
}
}

• Interact with the Grid control in controller file

testGrid: async function (oInst, oEvent) {


// Select the control in the current view
const oView = await oInst.ActiveView();
const oGrid = await oView.Grid("2g9uibjwCxiqPpFrz8NiwY");
// Assign values to the control properties
await oGrid.setTitle("Grid Testing");
await oGrid.setVisibleRowCount(15);
await oGrid.setColumnHeaderVisible(await !oGrid.getColumnHeaderVisible());
await oGrid.setEnableSelectAll(await !oGrid.getEnableSelectAll());
await oGrid.setShowNoData(await !oGrid.getShowNoData());
console.log(await oGrid.getTitle());
console.log(await oGrid.getVisibleRowCount());
}
onItemPressed: function(oInst, oEvent){
const param = oEvent.getParameters();
console.log("value: ", param.value);
},
onSelectionChanged: function(oInst, oEvent){
const param = oEvent.getParameters();
console.log("rowIndex: ", param.rowIndex);
console.log("rowIndices: ", param.rowIndices);
console.log("selectAll: ", param.selectAll);
console.log("userInteraction: ", param.userInteraction);
},
onFirstVisibleRowChanged: function(oInst, oEvent){
const param = oEvent.getParameters();
console.log("onFirstVisibleRowChanged: Grid GUID ", param.sCtrlGuid);
},
onSort: function(oInst, oEvent){
const param = oEvent.getParameters();
console.log("Column GUID: ", await param.column.getGuid());
console.log("SortOrder : ", param.sortOrder);
console.log("ColumnAdded: ", param.columnAdded);
},
onFilter: function(oInst, oEvent){
const param = oEvent.getParameters();
console.log("Column GUID: ", await param.column.getGuid());
console.log("value : ", param.value);
},
onPaste: function(oInst, oEvent){
const param = oEvent.getParameters();
console.log("data: ", param.data);

How to Develop Web Client Extensions


UI API Extensions PUBLIC 185
}

4.2.6 Data Binding

Data binding is the process used to bind UI elements to data sources, so as to keep the data in sync and allow
data editing on the UI. The UI uses data binding to bind controls to the model that holds the application data in
JSON format, so that the controls are updated automatically whenever application data changes. Data binding
is also used the other way round, when changes in the control cause an update in the underlying application
data, for example, data entered by the user, which means a two-way binding mechanism.

Related Information

Property Binding [page 186]


Aggregation Binding [page 187]
Expression Binding [page 188]
Resource Model Binding [page 188]
Formatter [page 189]

4.2.6.1 Property Binding

With property binding, you can initialize the properties of a control automatically and update them based on
the data of the model. Once you have defined the property binding, the property is updated automatically every
time the property value of the bound model is changed, and vice versa.

Let's take the property binding on input and checkbox as an example.

• Define the data mode data1 in the controller's onDataLoad method.

onDataLoad: async function (oInst, oEvent) {


const oView = await oInst.ActiveView();
// Create 'data1' as the data model for the basic property binding
await oView.setCustomizedData(
{
selected: true,
value: "hello world",
},
"data1"
);
}

• Define the controls and bind property to the data model with the following binding syntax. Please note that
"@@" is reserved as prefix for partner's data model.

"items": [
{
"guid": "pfKjesz1qTQaNiHm3NL7xM",

How to Develop Web Client Extensions


186 PUBLIC UI API Extensions
"ctrlType": "b1.sdk.CheckBox",
"label": "Checkbox Selected",
"selected": "{@@data1>/selected}",
"tooltip": "this is a hint",
"hideLabel": false,
"editable": true,
"visible": true
},
{
"guid": "bWiRc3dAXqnVaXWSodqH7B",
"ctrlType": "b1.sdk.Input",
"value": "{@@data1>/value}",
"label": "Input Value",
"editable": true,
"visible": true
}
]

4.2.6.2 Aggregation Binding

Aggregation binding, also known as list binding, is used to automatically create child controls according to
model data. It will automatically create as many child controls as needed to display the data in the model using
the template control approaches.

Let's take the aggregation binding on ComboBox as an example.

• Define the data mode data3 in the controller's onDataLoad method.

onDataLoad: async function (oInst, oEvent) {


const oView = await oInst.ActiveView();
// Create 'data3' as the data model for aggregation binding
await oView.setCustomizedData
{
comboBoxData: [
{ key: "key1", text: "text1" },
{ key: "key2", text: "text2" },
{ key: "key3", text: "text3" },
]
},
"data3"
);
}

• Define a control ComboBox and bind property items to the data model with the following binding syntax.

"items": [
{
"guid": "3CGkbnLNeq3168HhtrTa9t",
"ctrlType": "b1.sdk.ComboBox",
"label": "Dynamic ComboBox",
"tooltip": "ComboBox tooltip",
"items": {
"path": "@@data3>/comboBoxData",
"template": {
"ctrlType": "b1.sdk.Item",
"key": "{@@data3>key}",
"text": "{@@data3>text}"
}
}
}]

How to Develop Web Client Extensions


UI API Extensions PUBLIC 187
4.2.6.3 Expression Binding

Expression binding, an enhancement of the SAP UI5 binding syntax, allows you to display a value on the
screen that has been calculated from values found in some model objects. In this way, simple formatting or
calculations can be inserted directly into the data binding string. For the binding syntax, it is exactly the same
as UI5. For more information, please see Expression Binding .

Let's take the expression binding on StaticText as an example.

• Define the data mode data2 in the controller's onDataLoad method.

onDataLoad: async function (oInst, oEvent) {


const oView = await oInst.ActiveView();
// Create 'data2' as the data model for expression binding
await oView.setCustomizedData(
{
unitPrice: 10,
quantity: 1
}
"data2"
);
}

• Define a control StaticText and bind property value to the data model with the expression binding
syntax.

"items": [
{
"guid": "ukXMU1SCgGaSrJuMLbk6MF",
"ctrlType": "b1.sdk.StaticText",
"value": "{= ${@@data2>/unitPrice} * ${@@data2>/quantity}}",
"label": "Total",
"tooltip": "Calculated by expression: unitPrice * quantity"
}
]

4.2.6.4 Resource Model Binding

"Resource Model Binding" or "i18n binding" is a technique used for the internationalization of apps, making
your application more accessible to users worldwide with minimal extra coding effort. The advantage of this
technique is that it decouples content from code, and simplifies the introduction of updates or the addition of
new languages to your app.

Resource model binding works by linking app content variables (also known as keys) to values in the
properties files, named "i18n.properties". Each language variant has its own i18n.properties file. For example,
i18n_en.properties for English, i18n_fr.properties for French, and so on.

Each i18n.properties file contains key-value pairs. The keys are identifiers used in your application code, where
the values are the associated text strings translated to the specific language.

For Web Client UI API apps, the properties files and the model name are specified in the manifest.json as
below:

How to Develop Web Client Extensions


188 PUBLIC UI API Extensions
"b1.bundles": [
{
"i18n": {
"@i18n": ["sapb1.HelloWorld.SalesModule.i18n.i18n"]
}
}
]
}

For example, in the default or English properties file, we might have: buttonText=Get Company
Information.

Once you have set up the i18n.properties files, you can use the notation {i18n>key} in the overlay file to bind
such properties to control attributes in your applicationas follows:

{
"guid": "gJshBkE4qMBcAac7gbYgUn",
"ctrlType": "b1.sdk.Button",
"text": "{@i18n>buttonText}"
}

Web Client UI API framework will handle the rest, selecting the correct i18n.properties file based on the
language setting of your user's device and displaying the correct value on the button.

4.2.6.5 Formatter

Formatter is a utility that facilitates data manipulation during the data binding process between the Model and
the View in Web Client. It is used to transform source data from the Model into a format that can be easily
consumed by UI controls in the view.

The formatter functions are instrumental in customizing raw data according to specific requirements without
altering the original data in the Model. For example, when a UI control requires data in a specific format or data
type, such as an Integer, the Formatter can be used to transform the raw data into the required format during
the binding process. Thus, it provides a clean and efficient method for data manipulation and ensures the
Model's purity, which is essential in the MVC (Model View Controller) paradigm. Overall, Formatter is a robust
and flexible tool that enhances data handling capabilities, thereby enabling the creation of more dynamic and
responsive applications.

For example, if you want to rate a raw price by a formatter, you can define such a formatter in file formatter/
InputFormatter.

define([], function () {
"use strict";
return {
valueFormat: function (price) {
if (price <= 10) {
return "Low";
} else if (price <= 20) {
return "Reasonable";
} else {
return "High";
}
}
};
});

How to Develop Web Client Extensions


UI API Extensions PUBLIC 189
Then you can reference this formatter in the controller file. Remember to assign the formatter to a variable in
the controller constructor.

define(["./utility", "../formatter/InputFormatter"], function (utility,


InputFormatter) {
class Controller {
constructor(){
this.inputFormatter = InputFormatter;
}
//...
}
return Controller;
});

Finally you can use it in the *.layout.json.

{
"guid": "rhsirpA4TUGem87I98Xibg",
"ctrlType": "b1.sdk.Input",
"label": "PriceRating",
"value": "{path: '@@data2>/unitPrice',
formatter:'.inputFormatter.valueFormat'}"
}

4.2.7 Event Flow

Each event flow is generated by a UI operation or calling UI API, and then dispatched to the relevant event
handler with parameters. The event handler can then parse the event parameters and handle the event
appropriately.

Event Trigger

Theoretically, there are two ways to trigger an event:

• Manually interact with the UI


This is the most common way to trigger an event. For example, click one button and change the input
value.
• Programming fires an event
Each event has a corresponding event fire method. For example, for the press event on the Button, it has
a firePress method. An event can be triggered by calling its fire method when you are programming with
UI API.

As of now, the manual interaction is supported only.

Event Parameters

When an event occurs, some parameters can be passed along with it to dispatch more information on the event
itself.

How to Develop Web Client Extensions


190 PUBLIC UI API Extensions
There are two types of parameters:

• Built-in parameters
These parameters are for internal usage. For example, sCtrlGuid and sViewGuid.
• Event-specific parameters
These parameters are for individual events. For example, for the change event on an input control, it has
value and oldValue.

In the event handler, you would find the event has two more parameters: comment and firedByUIAPI.

onButtonClick: async function (oInst, oEvent) {


let isUIAPI = oEvent.getParameter("firedByUIAPI");
let comment = oEvent.getParameter("comment");
//...
}

Event Handler

For all events, regardless of whether the event is fired by pressing a button or triggered by leaving an input
focus, they have a unified event handler as below.

myEventHandler: async function (oInst, oEvent) {


// To handle the event
}

• For oInst, it is an instance of the type SDKEnv, from which you can find some information of the running
context.
• For oEvent, it is an instance of Event, from which you can get the event details by calling its functions (for
example, getParameters).

For more information, see the Types [page 192] topic.

Besides the event handler, each event has a corresponding pre-event handler and a post-event handler, which
can be defined as follows:

{
"guid": "tSnECbffy5gmfjiFHSBfkg",
"ctrlType": "b1.sdk.Button",
"text": "Test",
"press": {
"before": "beforeButtonPress",
"procName": "onButtonPress",
"after": "afterButtonPress"
}
}

For the pre-event handler beforeButtonPress, you can do some customizations before the event is
dispatched to the onButtonPress. For example, you have the chance to change the event parameters or
even prevent the event from dispatching. For the post-event handler afterButtonPress, you can add your
business logic after the event occurs.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 191
Lifecycle Hooks

Web Client UI API provides predefined Lifecycle Hooks for implementation.

Lifecycle Hooks Description

onInit (oInst, oEvent) Called when a view is instantiated and its controls (if availa-
ble) have already been created; it is used to modify the view
before it is displayed to bind the event handlers and carry
out other one-time initializations.

onDataLoad (oInst, oEvent) Called when data is loaded for the view, it is used to modify
the data. Note that it is asynchronously triggered after onI-
nit.

onExit (oInst, oEvent) Called when the view is destroyed, it is used to free resour-
ces and finalize activities.

4.2.8 Types

The following types are explained:

• int [page 192]


• Enumerations [page 192]
• Aggregations [page 197]
• Parameters [page 205]

4.2.8.1 int

JavaScript primitive values of type number and that don’t have a fractional part. To keep the implementation
efficient, the constraint is not enforced. Declaring a property as type int is rather for information purposes.
The corresponding object expects any given value to be an integer value. The default value of the type is the
number 0. Please refer to UI5 Property Types for details.

4.2.8.2 Enumerations

This section documents types for the enumeration properties.

How to Develop Web Client Extensions


192 PUBLIC UI API Extensions
Related Information

b1.sdk.ButtonType [page 193]


b1.sdk.ValueState [page 193]
b1.sdk.InputType [page 194]
b1.sdk.TextDirection [page 194]
b1.sdk.TextAlign [page 194]
b1.sdk.WrappingType [page 195]
b1.sdk.MessageBoxAction [page 195]
b1.sdk.MessageBoxType [page 196]
b1.sdk.Grid.SelectionMode [page 196]
b1.sdk.Grid.SelectionBehavior [page 196]
b1.sdk.Grid.ModelFilterOperator [page 196]
b1.sdk.HorizontalAlign [page 197]

4.2.8.2.1 b1.sdk.ButtonType

Name Description

Accept Accept type

Back Back type (back navigation button for the header)

Default Default type (no special styling)

Emphasized Emphasized type

Ghost Ghost type

Reject Reject type

Transparent Transparent type

Unstyled Unstyled type (no styling)

Up Up type (up navigation button for the header)

4.2.8.2.2 b1.sdk.ValueState

Marker for the correctness of the current value.

Name Description

Error State is not valid

Information State is informative

How to Develop Web Client Extensions


UI API Extensions PUBLIC 193
Name Description

Success State is valid

Warning State is valid but with a warning

None State is not specified

4.2.8.2.3 b1.sdk.InputType

Name Description

Measure Support format, like number1+unit1+number2+unit2, such


as "1.234Lb11.000Oz"

Percent There is a "%" behind the input area

Price Currency format

Quantity Float format, with a rounding accuracy setting for quantity

Rate Float format, with a rounding accuracy setting for rate

String Text format

Sum Currency format

Tax Currency format

Unit Float format, with a rounding accuracy setting for the unit

Integer Integer format, without a fractional part

Hour Display "Hr" behind the input area

4.2.8.2.4 b1.sdk.TextDirection

Text direction for input value.

Name Description

LTR Left to right

RTL Right to left

4.2.8.2.5 b1.sdk.TextAlign

Text alignment for input value.

How to Develop Web Client Extensions


194 PUBLIC UI API Extensions
Name Description

Begin Locale-specific positioning at the beginning of the line

End Locale-specific positioning at the end of the line

Left Hard option for left alignment

Right Hard option for right alignment

Center Centered text alignment

Initial Sets no text align, so the browser default is used

4.2.8.2.6 b1.sdk.WrappingType

Available wrapping types for text controls that can be wrapped which enable you to display the text as
hyphenated.

Name Description

Hyphenated Hyphenation will be used to break words on syllables where


possible.

Normal Normal text wrapping will be used. Words won't break based
on hyphenation.

4.2.8.2.7 b1.sdk.MessageBoxAction

Name Description

Cancel Adds a Cancel button to the message box.

Close Adds a Close button to the message box.

Delete Adds a Delete button to the message box.

Ignore Adds an Ignore button to the message box.

No Adds a No button to the message box.

OK Adds an OK button to the message box.

Retry Adds a Retry button to the message box.

Yes Adds a Yes button to the message box.

Abort Adds an Abort button to the message box.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 195
4.2.8.2.8 b1.sdk.MessageBoxType

Name Description

None Displays an error dialog with no icon.

Error Displays an error dialog with an ERROR icon.

Success Displays a success dialog with a SUCCESS icon.

Warning Displays a warning dialog with a WARNING icon.

Information Displays a warning dialog with an INFORMATION icon.

Confirm Displays a warning dialog with a CONFIRM icon.

4.2.8.2.9 b1.sdk.Grid.SelectionMode

Name Description

Multiple Select multiple rows at a time (toggle behavior).

Single Select one row at a time.

None No rows can be selected.

4.2.8.2.10 b1.sdk.Grid.SelectionBehavior

Name Description

Row Rows can be selected on the complete row.

RowOnly Rows can only be selected on the row (and the selector is
hidden)

RowSelector Rows can only be selected on the row selector.

4.2.8.2.11 b1.sdk.Grid.ModelFilterOperator

Name Description

BT FilterOperator between

Contains FilterOperator contains

How to Develop Web Client Extensions


196 PUBLIC UI API Extensions
Name Description

EQ FilterOperator equals

EndsWith FilterOperator ends with

GE FilterOperator greater or equals

GT FilterOperator greater than

LE FilterOperator less or equals

LT FilterOperator less than

NB FilterOperator not between

NE FilterOperator not equals

NotContains FilterOperator not contains

NotEndsWith FilterOperator not ends with

NotStartsWith FilterOperator not starts with

StartsWith FilterOperator starts with

4.2.8.2.12 b1.sdk.HorizontalAlign

Name Description

Begin Locale-specific positioning at the beginning of the line

Center Centered alignment of text

End Locale-specific positioning at the end of the line

Left Hard option for left alignment

Right Hard option for right alignment

4.2.8.3 Aggregations

This section documents types for the aggregation properties.

Related Information

b1.sdk.Item [page 198]


b1.sdk.SubSection [page 198]
b1.sdk.Group [page 200]
b1.sdk.Row [page 202]

How to Develop Web Client Extensions


UI API Extensions PUBLIC 197
b1.sdk.Column [page 203]

4.2.8.3.1 b1.sdk.Item

Properties

Name Type Mandatory Default Value Read Only Description

key string Yes N/A No Key of the combo


box item

text string No '' No Control introduc-


tion / title

enabled boolean No true No Determines


whether the con-
trol is enabled

additionText string No '' No Additional text to


be displayed along
with this item

4.2.8.3.2 b1.sdk.SubSection

Subsection is a second-level information container, which is generally used in an object page layout.

Available as of SAP Business One 10.0 FP 2405

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

visible boolean No true No Determines


whether the con-
trol is visible.

text string No '' No Subsection title

groups Group[] No [] No Groups in


section, see
b1.sdk.Group

How to Develop Web Client Extensions


198 PUBLIC UI API Extensions
Events

No events.

Methods

No methods.

Usage

Define a Subsection control in layout file.

{
"guid": "2uYDkRidQceMnh26HSuU61",
"ctrlType": "Section",
"text": "Section 1",
"subSection": [
{
"guid": "15Tvy2ADMLsq7TJdJjEQDq",
"ctrlType": "SubSection",
"text": "SubSection 21",
"group": [
{
"guid": "5mWFpvxL7BKRc2Vmm7PMwv",
"ctrlType": "Group",
"text": "Group 2",
"items": [
{
"guid": "vB2cRy8RMqNRJTrnZZHQih",
"label": "Test Label 2",
"ctrlType": "Input"
}
]
}
]
},
{
"guid": "sBp9dFHsiWUMmQE3wAeF5Z",
"ctrlType": "SubSection",
"text": "SubSection 22",
"group": [
{
"guid": "emC5fRi184o9eg62oHJ8QC",
"ctrlType": "Group",
"text": "Group 21",
"items": [
{
"guid": "eUdC8srWcJeGkd3VjajTcD",
"label": "Test Label 21",
"ctrlType": "Input"
}
]
},
{
"guid": "23QcpyC9EorFa3oRWaiKBN",
"ctrlType": "Group",
"text": "Group 212",

How to Develop Web Client Extensions


UI API Extensions PUBLIC 199
"items": [
{
"guid": "prin72R1LTSrJPi1xZ5rFC",
"label": "Test Label 212",
"ctrlType": "Input"
}
]
},
{
"guid": "4GmiJAX6QDprCZp6z4xS92",
"ctrlType": "Group",
"text": "Group 213",
"align": "right",
"items": [
{
"guid": "tjX4VQ2JcEYRcqsXe2JmDN",
"label": "Test Label 213",
"ctrlType": "StaticText",
"text": "This is a test description."
}
]
}
]
}
]
}

4.2.8.3.3 b1.sdk.Group

This control arranges labels and fields (like input fields) into groups and rows. There are different ways to
visualize forms for different screen sizes.

Available as of SAP Business One 10.0 FP 2405

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier

visible boolean No true No Determines


whether the con-
trol is visible.

text string No '' No Group title

align string No left Yes Shows group on


the right side if as-
sign value right.

items Control[] No [] No Control list in the


group

How to Develop Web Client Extensions


200 PUBLIC UI API Extensions
Name Type Mandatory Default Value Read Only Description

width int No 6 Yes You can define the


layout of groups
by specifying the
width of a group.
There are two val-
ues for width: 6
or 12. The default
value is 6, which
means that the
group uses half the
width of the space.
If you want to use
the entire width
of the space for
a group, set the
width to 12.

Events

No events.

Methods

No methods.

Usage

Define a Group control in layout file.

{
"guid": "xbSQCJQoYJaUwUZiAptEaL",
"ctrlType": "Section",
"text": "Section 0",
"subSection": [
{
"guid": "dQpP9ZBpmgLmSCCAaPvgLK",
"ctrlType": "SubSection",
"group": [
{
"guid": "2zJCz7wECRUTAZNa6QBKLE",
"ctrlType": "Group",
"text": "Group 0",
"width": 12,
"items": [
{
"guid": "wDtK6EcdnJED8i86bC6xJk",
"label": "Test Label 01",

How to Develop Web Client Extensions


UI API Extensions PUBLIC 201
"ctrlType": "Input"
},
{
"guid": "bkPZzCT7DqGqWFT9L3GxYY",
"label": "Test Label 02",
"ctrlType": "Input"
}
]
}
]
}
]
}

4.2.8.3.4 b1.sdk.Row

Available as of SAP Business One 10.0 FP 2405

Methods

getIndex

Returns the index of the row in the grid.

getIndex(mParameters?: object) : int

Usage

Define a Row control in the layout file.

{
"overlay": {
"after": [
{
"guid": "isgTCvtiWLcMRPAaD5HW29",
"items": [
]
}
]
}
}

 Note

The property items is a list of the exposed controls with a generic type Control. For example,
b1.sdk.StaticText is a concrete type of Control.

How to Develop Web Client Extensions


202 PUBLIC UI API Extensions
4.2.8.3.5 b1.sdk.Column

Available as of SAP Business One 10.0 FP 2405

Properties

Name Type Mandatory Default Value Read Only Description

guid string Yes N/A Yes Global unique


identifier. All the
grid columns will
have "COLUMN_"
added as the pre-
fix, and all tem-
plates in the col-
umn will have
"CELL_" added as
the prefix auto-
matically.

text string No '' No Label of the col-


umn which is dis-
played in the col-
umn header.

tooltip string No '' No The tooltip that


should be shown
for this Element.

width string No '' No Width of the col-


umn in CSS units.

minWidth int No 0 No Defines the mini-


mum width of a
column in pixels.

visible boolean No true No Determines


whether the con-
trol is visible.

useDefaultSort boolean No true Yes If set to false, you


need to implement
the sorting logic in
the grid sort event.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 203
Name Type Mandatory Default Value Read Only Description

sortProperty string No '' No Specifies the bind-


ing property on
which the column
will sort. Since the
column template
may have compo-
site bindings, it's
not possible to fig-
ure out on which
binding property
the sort shall be
applied. Therefore,
the binding prop-
erty for sorting
must be specified.
For example, if
the first name
and last name are
displayed in the
same column, only
one of the two
can be defined as
sortProperty.

filtered boolean No '' Yes Indicates if the col-


umn is filtered.

filterProperty string No '' No Specifies the bind-


ing property on
which the column
shall be filtered.

hAlign b1.sdk.Horizon No Begin No Horizontal align-


talAlign ment of the col-
umn content. Con-
trols with a text
align do not in-
herit the horizon-
tal alignment. You
have to set the text
align directly on
the template.

Events

No events.

Methods

No methods.

How to Develop Web Client Extensions


204 PUBLIC UI API Extensions
Usage

Define a Column control in layout file.

{
"guid": "2g9uibjwCxiqPpFrz8NiwY",
"ctrlType": "b1.sdk.Grid",
"rowsData": "{@@demo>/rows}",
"title": "A customer defined grid.",
"columns": [
{
"ctrlType": "b1.sdk.Column",
"guid": "k12qZkmVovquw6fXLmRxqz",
"text": "Id",
"defaultVisible": true,
"template": {
"ctrlType": "b1.sdk.Input",
"guid": "dcmfTcU59HCwny9WxkWMZy",
"editable": true,
"value": "{@@demo>id}"
}
}
]
}

4.2.8.4 Parameters

This section documents types for method parameters.

SDKEnv

The first parameter is the type of the current SDK environment. For more information, please see SDKEnv
[page 159].

Event

It is the type of the Web Client event and has the following functions. You can use it in the event handler.

Function Declaration Description

getId(): string Gets the event name.

getSource(): object Gets the event source control.

getParameters(): object Gets the event parameters.

getParameter(name: string): string Gets the event parameter value by name.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 205
Function Declaration Description

preventDefault(): void Prevents the default action of this event.

For the function preventDefault, please refer to the sample layout and code below. A function is created to
handle a button press before the event triggered by the Add & View button within a Sales Quotation detailed
view. To intercept system behaviors before their execution, the before attribute in the JSON layout is utilized.
Within the event function, the content of the Customer Reference No. field is validated; if it is empty, the default
system behavior is prevented by invoking the preventDefault function.

{
"controller": "SAPB1.SalesAssistApp.SalesAssist.controller.QutAssist",
"overlay": {
"on": [
{
"guid": "49H8VADnVmWRK4aFa5TkYy",
"press": {
"before": "onAddnViewButtonClick"
}
}
]
}
}

async onAddnViewButtonClick(oEnv, oEvent) {


// Get current active view
const oView = await oEnv.ActiveView();
// Validation code for Customer Ref. No - not empty.
// Get the Input control of Customer Ref. No.
const oInput = await oView.Input(GUIDCustomerReferenceNum);
// Get the string value of - Customer Ref. No.
const sValue = await oInput.getValue();

// If Customer Ref. No is empty then stop the processing of adding this


document.
if (sValue == "") {

await oEnv.showMessageBox("Information","Please provide a Customer Ref.


No.",{title: "Validation failed",});
// Prevent this event from being processed by the system - Block the
"Add & View" operation.
oEvent.preventDefault();
}
}

4.2.9 Security

You can build the Web Client UI API application using Web Client UI APIs in a well-designed sandbox,
which creates a restricted JavaScript context to execute partner's code in an isolated environment for each
extension. For instance, access to DOM object, window objects, cookies and session storage is restricted, and
external URLs not included in the allowlist cannot be reached. By integrating with Service Layer APIs, View Link
APIs and external URLs, you can enhance the list and detailed views of Web Client with exposed controls and
events.

It is highly recommended to configure the allowlist for Service Layer APIs and external URLs for each UI API
application module. This approach provides a finer granularity control over the capabilities of the extensions.

How to Develop Web Client Extensions


206 PUBLIC UI API Extensions
Cross-Site Request Forgery (CSRF) is a type of security vulnerability that allows an attacker to trick a user
into unintentionally executing actions on a Web application in which the user is authenticated. By exploiting
CSRF, an attacker can perform unauthorized transactions or actions on behalf of the victim without their
consent. Service Layer APIs are protected against CSRF attacks to ensure the integrity and security of the data
exchanged between the client and the server.

Note:

 Note

To configure the allowlist for external URLs and Service Layer APIs, please open and edit the
manifest.json file under the module folder.

{
"allowedExternalURLs": "*",
"allowedServiceLayerAPIs": "*"
}

 Example

{
"allowedServiceLayerAPIs": [
{
"api": "BusinessPartners",
"authorization": "full",
"description": "full authorization on business partners"
},
{
"api": "Items",
"authorization": "readOnly",
"description": "readOnly authorization on items"
},
{
"api": "CompanyService_GetCompanyInfo",
"authorization": "full",
"description": "full authorization to get company info from company
service"
}
],
"allowedExternalURLs": [
{
"endpoint": "https://services.odata.org",
"description": "public odata service"
},
{
"endpoint": "http://api.weatherapi.com",
"description": "free weather api"
}
]
}

If you are configuring the allowlist as an empty array, no APIs are allowed.

{
"allowedExternalURLs": [],
"allowedServiceLayerAPIs": []
}

How to Develop Web Client Extensions


UI API Extensions PUBLIC 207
4.2.10 Samples

To better understand how to use UI API to develop extensions, some samples are prepared for demonstration
purposes.

Quick Startup

Like a startup project, follow the VS Code plugin guide to create one simple UI API app, which shows a button
in the Sales Order detailed view to get the current company information from the Service Layer. For more
information, please see Visual Studio Code Plugin for Web Client [page 137].

For the code details, you can download the sample from here.

Further Development

Based on the startup app, further development can be performed with the following functionalities in the Sales
Order detailed view.

• How to create sections in the Sales Order detailed view


• How to create the above controls in the section
• How to trigger and handle the control events
• How to do the data bindings
• How to change or intercept the behavior of Lifecycle Hooks

For the code details, you can download the sample from here.

UDF Sample

Based on the startup app, a user-defined field (UDF) sample is prepared with the following functionalities in the
Sales Quotation detailed view.

• How to create sections in the Sales Quotations detailed view to show UDF.
• How to do the data bindings with UDF and interact with Service Layer
• How to override the UDF control's properties
• How to move UDF from one section to another

For the code details, you can download the sample from here.

How to Develop Web Client Extensions


208 PUBLIC UI API Extensions
 Note

The UDF sample is based on the demo database (for example, SBODemoUS) and assumes the referenced
UDF already existed in the database. You can get the UDF details from the Service Layer. For example, to
get the UDF details for the Sales Order detailed view, you can use the following request:

GET https://<your service layer:port>/b1s/v1/UserFieldsMD?$filter=TableName


eq 'ORDR'

Upon success, the Service Layer returns a UDF list.

Grid Sample

Based on the startup app, a Grid sample is prepared with the following functionalities in the Sales Order
detailed view.

• How to create Grid with customized data model


• How to select, add, update or delete rows in Grid
• How to handle before event or after event for an event
• How to do sort and filter in Grid

For the code details, you can download the sample from here.

Sales Assist App Sample

Based on the startup app, a Sales Assist App sample is prepared with the following functionalities in the
Business Partner detailed view and the Sales Quotation detailed view.

• How to create application with multiple views for a business scenario


• How to get data from Service Layer with advanced condition
• How to handle button press event of system button

For the code details, you can download the sample from here.

4.3 Web Client Inspector

Web Client Inspector is a standard Chrome or Edge extension that helps app developers to inspect, analyze and
debug extensions/plugs of SAP Business One, Web client.

The key feature of the inspector is to quickly locate the individual Web Client app UI controls and display the
control information in the browser development mode.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 209
4.3.1 Installing Web Client Inspector

Procedure

1. The Web Client Inspector installer is provided in the SAP Business One installation/upgrade package. You
can get the installer from Upgrade CD\Packages.x64\SDK. Run setup.exe and choose Web Client
Inspector.

After installation, you can find all installation scripts under SAP Business One SDK installation
path\Tools\WebClientInspector.
2. In Chrome, open the URL: chrome://extensions/. Alternatively, you can access edge://
extensions/ when in Edge. The extensions page is also reachable via the browser's menu.
3. Check the Developer mode setting and then choose Load unpacked.
4. From the newly opened window, select the folder in which the zip file was unpacked.
5. Restart Chrome or Edge. When Chrome or Edge restarts, you need to confirm that the devtools extension
will not be disabled.

How to Develop Web Client Extensions


210 PUBLIC UI API Extensions
4.3.2 Working with Web Client Inspector

Context

Once installed, the Web Client Inspector is available in Chrome or Edge DevTools (by choosing F12). It becomes
active when the Web client app is loaded.

Take the Sales Order Web Page as an example.

Procedure

1. Open the Web client application and log in via Chrome or Edge.
2. Open the Sales Order Detail View.
3. Open Developer Tools.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 211
4. Click WebClient, and you will see 2 tabs: the UI Inspector tab and the Application Information tab.

How to Develop Web Client Extensions


212 PUBLIC UI API Extensions
• UI Inspector tab
This tab shows the structure and nesting of the Web client controls. You can search and filter for
specific controls.
You have the options to show or hide the uuid of the control.
Clicking a specific node in the tree highlights the corresponding control in the app.
• You can also inspect the specific controls by right-clicking and selecting the Inspect WebClient
Control menu.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 213
How to Develop Web Client Extensions
214 PUBLIC UI API Extensions
• You can manually refresh the current active view by right-clicking and selecting the Refresh UI
Inspector menu in Web Client Inspector page. Consider such cases: when some controls in
the page have been changed, for example, from disable to enable, the inspector page will not be
updated automatically.

How to Develop Web Client Extensions


UI API Extensions PUBLIC 215
• Properties
In this tab, you can see the properties for a specific control. Currently, this tool only supports some
controls, as listed in Supported Controls and Views [page 217]. For unsupported controls, this tool
only shows the uuid property. For editable controls in the edit (add/update) mode, its value will be
changed in the next click.

How to Develop Web Client Extensions


216 PUBLIC UI API Extensions
• Application Information tab
This tab shows the basic information of Web Client Inspector.

4.3.3 Supported Controls and Views

For the supported controls and views, please check the lists below.

Control Name Available Since

Button SAP Business One 10.0 FP 2405

Input SAP Business One 10.0 FP 2405

StaticText SAP Business One 10.0 FP 2405

Section SAP Business One 10.0 FP 2405

SubSection SAP Business One 10.0 FP 2405

Group SAP Business One 10.0 FP 2405

ComboBox SAP Business One 10.0 FP 2405

CheckBox SAP Business One 10.0 FP 2405

How to Develop Web Client Extensions


UI API Extensions PUBLIC 217
Control Name Available Since

Grid SAP Business One 10.0 FP 2405

Related Information

Supported Views [page 155]

How to Develop Web Client Extensions


218 PUBLIC UI API Extensions
5 Extensibility with BTP

This section shows you how to carry out the following tasks:

• How to set up a connection between Service Layer and SAP Business Technology Platform (BTP) by
creating a destination
• How to create a Fiori freestyle project based on this destination using SAP Business Application studio
• How to deploy the Fiori app to BTP
• How to create a URL-mashup app based on the Fiori app
• How to run it in Web Client

The Service Layer used in this document is of version SAP Business One 10.0 FP 2111, and the OData used is of
version 4 to establish the connection.

 Note

Make sure that the Service Layer is running in the public internet, so that it is accessible from BTP.

You can also refer to the video How to develop a Fiori application on BTP and deploy it on Web Client for SAP
Business One , which is valid for Fiori app versions prior to 1.12.1 and contains the main idea in this online
help section.

5.1 Setting Up BTP Destination for Service Layer

Procedure

1. Logon to the BTP Cockpit with your BTP account. In this document, the BTP trial account is used.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 219
2. Enter into the subaccount. In this case, the subaccount is trial.

3. Navigate to Connectivity Destinations , and create a destination by choosing New Destination.

How to Develop Web Client Extensions


220 PUBLIC Extensibility with BTP
How to Develop Web Client Extensions
Extensibility with BTP PUBLIC 221
The destination details are shown as follows:

The Authentication is Basic Authentication, and you also need to specify some additional properties in the
following table:

Additional Property Property Value

HTML5.DynamicDestination true

WebIDEEnabled true

WebIDESystem Gateway

WebIDEUsage odata_gen

Choose Check Connection to verify if the connection is OK. Upon success, the following dialog pops up:

How to Develop Web Client Extensions


222 PUBLIC Extensibility with BTP
5.2 Creating a Dev Space

Procedure

1. Log on to the SAP Business Application Studio.

2. Create a dev space (for example, fiori_dev) and open it.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 223
5.3 Creating a UI5 Project

Procedure

1. Create a new project from the template.

2. Choose SAP Fiori application and Start.

3. In the Floorplan Selection step, select SAPUI5 freestyle as the Application Type, choose SAPUI5 Application
and then choose Next.

How to Develop Web Client Extensions


224 PUBLIC Extensibility with BTP
4. Configure the data source and service selection as follows and then choose Next.

For the System field, select B1ServiceLayer, which is the destination name configured in the Connectivity
field.

For the Service Path field, enter /b1s/v2, which is the relative path for the Service Layer OData V4
protocol.
5. Configure the project attributes in the following way and choose Next.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 225
6. Upon success, an indication message is displayed in the right bottom corner.

7. Navigate to the project location and open the newly created project.

8. Run the project by the following command in a new terminal.

How to Develop Web Client Extensions


226 PUBLIC Extensibility with BTP
A browser pops up like below.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 227
5.4 Creating Worklist Project

Context

You can create a worklist app by following the worklist application template wizard. The following are some key
screenshots and steps:

Procedure

1. Create a new project from the template.

2. Choose SAP Fiori application and start.

How to Develop Web Client Extensions


228 PUBLIC Extensibility with BTP
3. In the Floorplan Selection step, select SAPUI5 freestyle as the Application Type, choose SAP Fiori Worklist
Application and then choose Next.

4. Configure the data source and service selection as follows and then choose Next.

For the System field, select B1ServiceLayer, which is the destination name configured in the Connectivity
field.

For the Service Path field, enter /b1s/v2, which is the relative path for the Service Layer OData V4
protocol.
5. Fill out the entity selection information and choose Next.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 229
6. Configure the project attributes in the following way and choose Next.

How to Develop Web Client Extensions


230 PUBLIC Extensibility with BTP
For the Add deployment configuration field, select Yes. The application will be deployed to cloud foundry.

For the Add FLP configuration field, select Yes. The application will be launched from the Fiori launchpad.
7. Configure the deployment settings and choose Next.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 231
8. Configure the Fiori launchpad settings and choose Finish.

How to Develop Web Client Extensions


232 PUBLIC Extensibility with BTP
 Note

Make sure you have subscribed to the launchpad service. You can check it in the Instances and
Subscriptions under your subaccount.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 233
9. Upon success, the application information is displayed as follows.

10. After the project is generated, open webapp/manifest.json, navigate to the models and add the
following entries:

"groupId": "$direct"

Then the entire models would be:

"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "sapb1.app3.i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"preload": true,
"settings": {
"synchronizationMode": "None",
"operationMode": "Server",
"autoExpandSelect": true,
"groupId": "$direct",
"earlyRequests": true
}
}
},

The purpose of this change is to ensure the request sending to the service layer is using the http method
GET, instead of a POST via OData $batch.

How to Develop Web Client Extensions


234 PUBLIC Extensibility with BTP
11. To allow the Fiori application to be displayed in an iframe, we need to change the frame options by
modifying webapp/index.html as follows.

<script
id="sap-ui-bootstrap"
src="resources/sap-ui-core.js"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-resourceroots='{
"sapb1.employee": "./"
}'
data-sap-ui-compatVersion="edge"
data-sap-ui-async="true"
data-sap-ui-frameOptions="allow"
></script>

The original value of data-sap-ui-frameOptions is:

data-sap-ui-frameOptions="trusted"

We need to change the value to:

data-sap-ui-frameOptions="allow"

This step is mandatory because one of our demonstration purposes is to embed the Fiori app as an iframe
inside Web Client.
12. To run the project, click Preview Application from the dropdown list, and select the the first npm script
start fiori run.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 235
You see a list showing the entity data from the service layer.

5.5 Build and Deploy

Context

Let's build the worklist project and deploy it to BTP.

Procedure

1. To begin building, in the project explorer, right click the mta.yaml, then in the context menu, select Build
MTA Project.

Upon success, a mtar package is generated under the folder mta_archives.

How to Develop Web Client Extensions


236 PUBLIC Extensibility with BTP
2. To deploy it, right click the mtar file, then in the context menu, select Deploy MTA Archive.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 237
3. Enter your credentials to logon to Cloud Foundry.

How to Develop Web Client Extensions


238 PUBLIC Extensibility with BTP
4. Fill in your Cloud Foundry Target and Apply.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 239
A task to deploy will be running like below.

How to Develop Web Client Extensions


240 PUBLIC Extensibility with BTP
5. Find out the name of the destination service in the previous step, for example sapb1-employee-
destination-service, and start your service using the following command.

cf html5-list -di sapb1-employee-destination-service -u -rt launchpad

6. Get the service URL and open it in a browser.

https://<YourCloudFoundryOrganization>.launchpad.cfapps.sap.hana.ondemand.com/
f45d7531-58f2-4f04-ad2c-f7934d367316.sapb1-employee.sapb1employee-0.0.1/
index.html

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 241
How to Develop Web Client Extensions
242 PUBLIC Extensibility with BTP
5.6 Creating URL-Mashup App

Context

Using the URL of the Fiori app, let's open the VS Code to create one URL-mashup app for SAP Business One
Web Client.

Prerequisite

• You have already installed the SAP Business One Web Client Extensions for VS Code.
• You have already installed the SAP Business One Server Tools.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 243
Procedure

1. From the View menu, click Command Palette... and select Open Template Wizard.
2. Select SAP Business One Web Client Extensions, and click Start.
3. For the Application Type, select Tile Extension App and choose Next.
4. For the Application Information, provide basic information about your application like below, and choose
Next.

Attributes Value

What is the ID of your application urlmashup-app1

What is the version of your application 1.0.0

Who is the provider of your application sapb1

5. For the Module Type, select URL Mashup App.


6. For the Module Attributes, specify the attributes in the following table:

Attributes Value

What is the name of your module module1

What is the tile number of your module 2

There are two tiles, one is for the existing window while the other is for a new window.

7. For the Tile Settings, specify the attributes in the following table:

Tile Setting 1

Attributes Value

What is the title of the tile MyEmployee1

Enable a default header with title name No

What is the subtitle of the tile App in existing window

Select the dimensions of the tile 1X1

Select the tile link method Existing Window

What is the link for the tile <The URL of your Fiori app>

Support dynamic content No

Select a decoration type for the tile Icon

How to Develop Web Client Extensions


244 PUBLIC Extensibility with BTP
Attributes Value

Select an icon for the tile sap-icon://employee-pane

Tile Setting 2

Attributes Value

What is the title of the tile MyEmployee2

Enable a default header with title name No

What is the subtitle of the tile App in new window

Select the dimensions of the tile 1X1

Select the tile link method New Window

What is the link for the tile <The URL of your Fiori app>

Support dynamic content No

Select a decoration type for the tile Icon

Select an icon for the tile sap-icon://employee

8. Review the Application Summary and choose Finish.


9. Upon success, the app is created. You can find the package urlmashup-app1_1.0.0.mtar in the
mta_archives folder.
10. Upload this package to the Extension Manager and assign it to a company.

5.7 Configuring Security Settings

Context

By default, it is not allowed to logon to the Fiori App in an iframe from Web Client from the security perspective.
To allow this, follow the below steps to trust Web Client domains.

Procedure

1. Logon to the SAP BTP Cockpit, and navigate to the Security Settings .

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 245
2. Press the + button to add your Web Client domain to the Trusted Domains.

This will allow the Web Client to embed the login page of the SAP Authorization and Trust Management
service. For more information, see the documentation.

5.8 Running the URL-Mashup App

Context

The URL-mashup app is a Web Client extension and can only run in the Web Client context. Make sure that you
have assigned the URL-mashup app to the login company in the Extension Manager.

How to Develop Web Client Extensions


246 PUBLIC Extensibility with BTP
Procedure

1. Log on to the company in Web Client and navigate to the Extensions tab, where you will find there are two
tiles for the apps.

2. Click on the MyEmployee1 tile.Your app will be opened in the current window.

How to Develop Web Client Extensions


Extensibility with BTP PUBLIC 247
3. Click on the MyEmployee2 tile. Your app will be opened in a new tab.

How to Develop Web Client Extensions


248 PUBLIC Extensibility with BTP
6 Deploying Web Client Extensions on
Extension Manager

Context

To enable extensions on the Web client, you need to deploy the mtar archive into the Web client by SAP
Business One Extension Manager.

The SAP Business One Extension Manager is a component in Server Tools for SAP Business One. To install
SAP Business One Extension Manager, you should install SAP Business One Server, and select Server Tools
Landscape Management Extension Manager .

You can access SAP Business One Extension Manager directly from a Web browser on the machine
on which the System Landscape Directory (SLD) service is running using the following URL: https://
<hostname>:<port>/ExtensionManager.

To deploy an extension, perform the following steps:

Procedure

1. Import the extension to SAP Business One Extension Manager.


2. Assign the extension to companies in SAP Business One Extension Manager.
3. Run the extension in the Web client.

Related Information

Importing the Mtar Archive and Assigning to a Company [page 250]

How to Develop Web Client Extensions


Deploying Web Client Extensions on Extension Manager PUBLIC 249
6.1 Importing the Mtar Archive and Assigning to a
Company

To import your mtar archive and assign the extension to a company, perform the following steps:

1. In the SAP Business One Extension Manager window, on the Extensions tab, choose the Import button.
The Extension Import Wizard window appears.
2. Choose the Browse button to select the mtar package and choose Upload.

Upon success, the basic information of the extension appears. Choose Next to optionally specify the value
of the shared parameters.

How to Develop Web Client Extensions


250 PUBLIC Deploying Web Client Extensions on Extension Manager
3. Choose Next.
On the Finish tab, we recommend that you continue to assign this extension to a company.

How to Develop Web Client Extensions


Deploying Web Client Extensions on Extension Manager PUBLIC 251
4. After you click the Finish import and run the company assignment wizard hyperlink, the Company
Assignment Wizard window appears.

5. Set startup mode in user preference for each company user.

How to Develop Web Client Extensions


252 PUBLIC Deploying Web Client Extensions on Extension Manager
 Note

The startup mode values, such as Manual, Automatic or Mandatory, only affect SAP Business One
client extensions. For the Web client, they are all equivalent to "enabled", which decides whether you
can use this extension in the currrent company.

6. To check the assigned extensions in a company, in the SAP Business One Extension Manager window,
choose the Company Assignment tab. From Company List, select the company and check whether the
extension is available. If the extension is not available, you can use the Extension Assignment wizard to
assign it to a company.

 Note

You can use one of the following two ways to assign an extension to a company:

• Run the company assignment wizard


• Run the extension assignment wizard

6.2 Deploying Web Client Extensions in SAP Business One


Cloud

You can completely configure the Web client extensions using the SAP Business One Cloud Control Center.

How to Develop Web Client Extensions


Deploying Web Client Extensions on Extension Manager PUBLIC 253
To deploy an extension in SAP Business One Cloud environment, perform the following steps:

1. Configure Extension Repositories.


2. Copy extensions to the Incoming folder and synchronize extensions.
3. Deploy the extension to a service unit.
4. Assign the extension to tenants.

Sychronizing Mtar Archive on Cloud Control Center

1. In the Cloud Control Center, choose Central Components Extensions .


2. Click the Tools button as below, then set addon repository path.You will find that the Incoming folder and
the Repository folder are automatically generated under the add-on repository path.

3. Go to Incoming folder, create a new subfolder and copy the mtar file on file system.

4. Choose the Synchronize All button.


Upon success, you will see a new row of the Web client extension.

How to Develop Web Client Extensions


254 PUBLIC Deploying Web Client Extensions on Extension Manager
Deploying Web Client Extensions to a Service Unit

1. In the Cloud Control Center, choose Central Components Service Units .


2. Select the service unit to which you want to deploy the extension.
3. In the Service Unit Details area, select the Extensions tab, and then choose the Deploy button.
4. Follow the steps of the deployment wizard.

Assigning Web Client Extensions to Tenants

1. In the Cloud Control Center, choose Customer Management Tenants .


2. Select the tenant to which you want to assign the extension.
3. In the Tenant Details area, select the Extensions tab, and then choose the Assign button.
4. Follow the steps of the assignment wizard.

How to Develop Web Client Extensions


Deploying Web Client Extensions on Extension Manager PUBLIC 255
5. Set startupmode for the user preference for the company user.

How to Develop Web Client Extensions


256 PUBLIC Deploying Web Client Extensions on Extension Manager
7 Working with APIs That Generate Web
Client Views URLs

You are able to use APIs to generate URLs for the following views:

• List view and detailed view for an object


• Analytics views

You can use the created URLs in your extentions.

Related Information

Generating Web Client Object Views URLs with APIs [page 257]
Generating Web Client Analytics Views URLs with APIs [page 268]

7.1 Generating Web Client Object Views URLs with APIs

You can work with the following APIs to get the URL of the list view of an object:

1. Getting the variant list by object name and object type.

/extn/api/Variants?objName={objName}&objType={objType}

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 257
2. Getting the URL of the object's list view by object name, object type and variant GUID.

/extn/api/objectsListView?
objName={objName}&objType={objType}&variantGUID={variantGUID}

You can work with the following APIs to get the URL of the detailed view of an object:

1. Getting the URL of the object's detailed view for a specific record by object name, object type and object
key value:

/extn/api/objectsDetailView?objName={objName}&objType={objType}&value={value}

2. Getting the URL of a configuration object by the object key value:

extn/api/objectsDetailView?objName=Configuration&value={value}

More Information for Object Type

Three kinds of object types are defined in the Web client: SYSTEM (system objects in SAP Business One), UDO
(user-defined objects) and UDT (user-defined tables) .

var objectType = {
SYSTEM: 'System', //system object type
UDO: 'UDO',
UDT: 'UDT'
}

All system objects in the Web client are supported, and their names are used as parameters in the Web client
views APIs.

Refer to the following to get the system object names:

var systemObjectName = {
ACTIVITIES: 'Activities',
APPROVALREQUESTS: 'ApprovalRequests',
BUSINESSPARTNERS: 'BusinessPartners',
CREDITNOTES: 'CreditNotes',
DELIVERYNOTES: 'DeliveryNotes',
DRAFTS: 'Drafts',
INVOICES: 'Invoices',
ITEMS: 'Items',
ORDERS: 'Orders',
PURCHASECREDITNOTES: 'PurchaseCreditNotes',
PURCHASEDELIVERYNOTES: 'PurchaseDeliveryNotes',
PURCHASEINVOICES: 'PurchaseInvoices',
PURCHASEORDERS: 'PurchaseOrders',
PURCHASEQUOTATIONS: 'PurchaseQuotations',
PURCHASERETURNS: 'PurchaseReturns',
QUOTATIONS: 'Quotations',
RESERVEINVOICES: 'ReserveInvoices',
RETURNS: 'Returns',
OPPORTUNITIES: 'Opportunities',
INCOMINGPAYMENTS: 'IncomingPayments',
TIMESHEETS: 'TimeSheets',
SOLUTIONSKNOWLEDGEBASE: 'SolutionsKnowledgeBase',
SERVICECALL: 'ServiceCall',
BUSINESSPARTNERCATALOGNUMBERS: 'BusinessPartnerCatalogNumbers',
OUTGOINGPAYMENTS: 'OutgoingPayments',
USERQUERIES: 'UserQueries',

How to Develop Web Client Extensions


258 PUBLIC Working with APIs That Generate Web Client Views URLs
INVENTORYGENEXIT: 'InventoryGenExit',
CUSTOMEREQUIPMENTCARDS:'CustomerEquipmentCards',
APPROVALDECISIONS: 'ApprovalDecisions',
OUTGOINGPAYMENTSINAPPROVALPROCESS: 'OutgoingPaymentsInApprovalProcess',
JOURNALENTRIES: 'JournalEntries',
ReturnRequest: 'ReturnRequest',
GoodsReturnRequest: 'GoodsReturnRequest',
PurchaseRequests: 'PurchaseRequests',
InventoryCounting: 'InventoryCounting',
ServiceContracts: 'ServiceContracts',
InventoryGenEntry: 'InventoryGenEntry',
ProductionOrders: 'ProductionOrders',
IssueForProduction: 'IssueForProduction',
ReceiptFromProduction: 'ReceiptFromProduction',
PurchaseReserveInvoice: 'PurchaseReserveInvoice',
BillOfMaterial: 'BillOfMaterial',
UserDefinedFields: 'UserDefinedFields',
Configuration: 'Configuration'}

Related Information

Getting Variant List by Object Name and Object Type [page 259]
Getting URL of Object's List View by Object Name, Object Type and Variant GUID [page 260]
Getting URL of a Specific Record's Detailed View by Object Name, Object Type and Object Key Value [page 261]
Getting URL of a Configuration Object's Detailed View by Object Key Value [page 263]

7.1.1 Getting Variant List by Object Name and Object Type

API

/extn/api/Variants?objName={objName}&objType={objType}

Method

GET

Parameters

• objType (not required) String


The object type is from Object Type, and if object type is "System", parameter "objType" can be ignored.
• objName (required) String
Use the object name displayed in the Web client or service layer. If object type is "System", use the name in
System Object Name.

Response

Content-Type: application/json

[{"Guid":"35320f2c-c83b-4db9-a81c-a4502248ce04","Name":"Open Sales Orders"},


{"Guid":"5a9a1325-b3bc-4729-8c8d-b243e045fff2","Name":"Sales Orders Backorder"},
{"Guid":"642882dd-9525-48ff-acff-53a84a729cf5","Name":"My Sales Orders"},
{"Guid":"7944e0ca-613f-4222-b21e-52c134d687e9","Name":"My Open Sales Orders"},
{"Guid":"d9ddd650-22de-49cc-a480-a8e01b5d9db4","Name":"All Sales Orders"}]

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 259
The above response use Sales Order as an example, and the variant name list can be seen in the Web client as
below:

7.1.2 Getting URL of Object's List View by Object Name,


Object Type and Variant GUID

API

/extn/api/objectsListView?
objName={objName}&objType={objType}&variantGUID={variantGUID}

Method

GET

Parameters

• objType (not required) String


The object type is from Object Type, and if object type is "System", parameter "objType" can be ignored.
• objName (required) String
Use the object name displayed in the Web client or Service Layer. If object type is "System", use the name
in System Object Name.
• variantGUID (required)
Variant GUID is from response of API "/extn/api/Variants".

How to Develop Web Client Extensions


260 PUBLIC Working with APIs That Generate Web Client Views URLs
Response

Content-Type: text/html

/webx/index.html#webclient-OCRD&/Objects/OCRD/List?
s=~(status~(version~1~userFilter~'CardType*20EQ*20*27L*27~filterBarLayout~'*7bvis
ibleItems*3a*5bCardCode*2cCardType*2cGroupCode*5d*7d~selectedColumns~(~(p~'CardCo
de)~(p~'CardName)~(p~'CardType)~(p~'GroupCode)~(p~'Balance)~(p~'Currency)~(p~'Cel
lular)~(p~'E_Mail)~(p~'IntrntSite)~(p~'CntctPrsn))~groupBy~(~)~sortBy~(~(key~'Car
dCode~dir~'Ascending)))~variant~(selectedKey~'2f224d16-f138-474c-
b5c1-5599c72e29c2~dirtyFlag~false))&r=yZjhyz8t

Using Sales Order as example, choose one variant GUID, get the sales order instance lists link for this variant.
You can access the link in the Web client as below:

7.1.3 Getting URL of a Specific Record's Detailed View by


Object Name, Object Type and Object Key Value

API

/extn/api/objectsDetailView?objName={objName}&objType={objType}&value={value}

Method

GET

Parameters

• objType (not required) String


The object type is from Object Type, and if object type is "System", parameter "objType" can be igonred.
• objName (required) String
Use the object name displayed in the Web client or service layer. If object type is "System", use the name in
System Object Name.
• value (required)
The object value can be gotten from the Service Layer or database access.

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 261
 Note

Different objects have different key values and we have two kinds of object: documents and master
data, for example, (documents) Sales Order's key is DocEntry in 'ORDR', (master data) Items' key is
ItemCode in 'OITM'.

Response

Content-Type: text/html

/webx/index.html#webclient-ORDR&/Objects/ORDR/Detail?r=l08SPA6Z&id=ORDR%252C1217

Uses Sales Order as example, choose one object instance 1217, get the sales order instance detail link.

 Note

Alternatively, with an existing Document Number (for example, 1204), the corresponding Internal Number
can be retrieved by invoking the Service Layer API like blow:

GET /b1s/v2/Orders?$filter=DocNum eq 1204&$select=DocEntry

Upon Success, the Service Layer returns the DocEntry, which is the alias for Internal Number.

{
"value": [
{
"@odata.etag": "W/\"356A192B7913B04C54574D18C28D46E6395428AB\"",
"DocEntry": 1217
}
]
}

How to Develop Web Client Extensions


262 PUBLIC Working with APIs That Generate Web Client Views URLs
You can access the link in the Web client as below:

7.1.4 Getting URL of a Configuration Object's Detailed View


by Object Key Value

API

/extn/api/objectsDetailView?objName=Configuration&value={value}

Method

GET

Parameters

• objName (required) String


Use Configuration as the object name.
• value (required) String
Refer to the following to get the values:

"InventorySettings"

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 263
"ApprovalProcessSettings"
"ApprovalStages"
"ApprovalTemplates"
"SubstituteAuthorizers"
"BusinessPartnersSettings"
"CompanyDetails"
"CompanySettings"
"States"
"Competitors"
"InformationSources"
"InterestRanges"
"LevelsOfInterest"
"OpportunityStages"
"PostingPeriodsSettings"
"PostingPeriodsDefinition"
"CommissionGroups"
"Partners"
"Reasons"
"Relationships"
"PredefinedTexts"
"SalesEmployees"
"UnitOfMeasureGroups"
"UnitOfMeasure"
"ReferenceFieldLinks"
"Freights"
"CountriesRegions"
"Banks"
"CreditCards"
"PackageTypes"
"Indicators"
"ActivityTaskStatuses"
"ActivityCategories"
"ActivitySubcategories"
"MeetingLocations"
"SalesAndPurchasingSettings"
"SalesDocumentSettings"
"PurchasingDocumentSettings"
"CustomerGroups"
"VendorGroups"
"EmailGroups"
"BusinessPartnerPriorities"
"BusinessPartnerProperties"
"PaymentTerms"
"CashDiscounts"
"Territories"
"OpeningBalances"
"BankChargesAllocationCodes"
"HouseBankAccounts"
"CreditCardPayments"
"CreditCardPaymentMethods"
"PaymentBlocks"
"ItemGroups"
"ItemProperties"
"Warehouses"
"LengthAndWidth"
"Weight"
"CustomsGroups"
"Locations"
"Manufacturers"
"ShippingTypes"
"Currencies"
"Projects"
"TransactionCodes"
"PeriodIndicators"
"ServiceCallOrigins"
"ServiceCallProblemTypes"
"ServiceCallProblemSubtypes"
"ServiceCallStatuses"

How to Develop Web Client Extensions


264 PUBLIC Working with APIs That Generate Web Client Views URLs
"ServiceCallTypes"
"SolutionStatuses"
"Languages"
"Industries"

Response

Content-Type: text/html

/webx/index.html#webclient-Config&/Objects/Config/Simple?
subViewId=InventorySettings.detailView

7.1.5 Sample Code

Use JavaScript to show how to use the APIs, as below:

//get variant list


let BOName = "Orders";
let BOType = "System"
let resp = await fetch("/extn/api/Variants?objName=" + BOName + "&objType=" +
BOType, {
method: "GET",
credentials: "include"
});
let json = await resp.json();
//get variant GUID by variant name
let variantName = "My Open Sales Orders"
let guidValue = "";
json.forEach((item,index,json)=>{
if (item.Name === variantName)
{
guidValue = item.Guid;
}
})
//get BO list link
let respBoList = await fetch("/extn/api/objectsListView?objName=" + BOName +
"&objType=" + BOType + "&variantGUID=" + guidValue, {
method: "GET",
credentials: "include"
});
let boListLink = await respBoList.text();
let serviceURL = location.protocol + "//" + location.host;
let fullBoListLink = serviceURL + boListLink;

//get BO detail link


let BOValue = "1217";
let respBoDetail = await fetch("/extn/api/objectsDetailView?objName=" + BOName +
"&objType=" + BOType + "&value=" + BOValue, {
method: "GET",
credentials: "include"
});
let boDetailLink = await respBoDetail.text();
let fullBoDetailLink = serviceURL + boDetailLink;

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 265
7.1.6 Example App

For a better understanding of how to use the APIs, an example is provided for you. The source code and the
mtar package are also provided in the following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which can be deployed directly to the
Extension Manager and displayed in the Web client as below:

In this app, you have an interactive UI to use the APIs.

API - Get Variant List

To invoke this API, input the values of the two required fields:

• BO Type
• BO Name

Click the GetVariantList button, upon success the response is shown in the text area control.

How to Develop Web Client Extensions


266 PUBLIC Working with APIs That Generate Web Client Views URLs
API - Get List View URL

To invoke this API, besides the the two required fields, input the value of the third field: Variant GUID.

You can get the value of this field from the response of the first API.

Click the GetListViewURL button, upon success the response is shown in the text area control.

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 267
API - Get Detailed View URL

To invoke this API, besides the the two required field, input the value of the third field: BO Value.

You can get the BO value from Service Layer or other data sources. For Orders, this field is equivalent to
DocEntry.

Click the GetDetailViewURL button, upon success the response is shown in the text area control.

7.2 Generating Web Client Analytics Views URLs with APIs

You can work with the following APIs to get the URL of the analytics views:

1. Getting all view codes by analytics type, which is Dashboard or ChartContainer.

/extn/api/analyticsViews?analyticsType={analyticsType}

2. Getting the specific analytics view variants list by view code and analytics type.

/extn/api/analyticsViewVariants?
viewCode={viewCode}&analyticsType={analyticsType}

3. Getting the URL of the specific analytics view by view code, analytics type and variant GUID.

/extn/api/analyticsView?
viewCode={viewCode}&analyticsType={analyticsType}&variantGUID={variantGUID}

How to Develop Web Client Extensions


268 PUBLIC Working with APIs That Generate Web Client Views URLs
Related Information

Getting View Codes by Analytics Type [page 269]


Getting Analytics View Variants List by View Code and Analytics Type [page 270]
Getting URL of a Specific Analytics View by View Code, Analytics Type and Variant GUID [page 271]

7.2.1 Getting View Codes by Analytics Type

API

/extn/api/analyticsViews?analyticsType={analyticsType}

Method

GET

Parameters

analyticsType (required) String

The analytics type is either Dashboard or ChartContainer.

Response

Content-Type: application/json

[{"viewId":"RDR90002","text":"Sales Analysis by Rows


Overview","description":"Sales Analysis by Rows Overview"},
{"viewId":"RDR90003","text":"Sales Analysis by Document
Overview","description":"Sales Analysis by Document Overview"},
{"viewId":"RDR90004","text":"Customer Balances Overview","description":"Customer
Balances Overview"},{"viewId":"POR90002","text":"Purchase Analysis
by Rows Overview","description":"Purchase Analysis by
Rows Overview"},{"viewId":"POR90003","text":"Purchase Analysis
by Document Overview","description":"Purchase Analysis
by Document Overview"},{"viewId":"POR90004","text":"Vendor
Balances Overview","description":"Vendor Balances Overview"},
{"viewId":"ITW90002","text":"Inventory Status Overview","description":"Inventory
Status Overview"},{"viewId":"IVL90002","text":"Inventory
Transactions Overview","description":"Inventory Transactions
Overview"},{"viewId":"JDT90002","text":"Financial Analysis
Overview","description":"Financial Analysis Overview"},
{"viewId":"QUT20001","text":"Sales Quotation Header
Overview","description":"Sales Quotation Header Overview"},
{"viewId":"QUT20002","text":"Sales Quotation Detail
Overview","description":"Sales Quotation Detail Overview"},
{"viewId":"MDO10001","text":"General Overview","description":"General Overview"}]

 Note

The response might be different according to user authorization and database type.

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 269
7.2.2 Getting Analytics View Variants List by View Code and
Analytics Type

API

/extn/api/analyticsViewVariants?viewCode={viewCode}&analyticsType={analyticsType}

Method

GET

Parameters

• viewCode (required) String


View code is from response of API "/extn/api/analyticsViews".
• analyticsType (required) String
The analytics type is either Dashboard or ChartContainer.

Response

Content-Type: application/json

[{"Guid":"6a080479-16dc-470e-b3b4-d4a57f26effd","Name":"Standard"},
{"Guid":"a2dfa8a2-24bb-4a48-b711-002a8d453b31","Name":"1st Quarter Only"}]

The above response use Sales Analysis by Rows Overview as an example, and the variant name list can be seen
in the Web client as below:

How to Develop Web Client Extensions


270 PUBLIC Working with APIs That Generate Web Client Views URLs
7.2.3 Getting URL of a Specific Analytics View by View Code,
Analytics Type and Variant GUID

API

/extn/api/analyticsView?
viewCode={viewCode}&analyticsType={analyticsType}&variantGUID={variantGUID}

Method

GET

Parameters

• viewCode (required) String


View code is from response of API "/extn/api/analyticsViews".
• analyticsType (required) String
The analytics type is either Dashboard or ChartContainer.
• variantGUID (required) String
Variant GUID is from response of API "/extn/api/analyticsViewVariants".

Response

Content-Type: text/html

Using Sales Analysis by Rows Overview as example, choose one variant GUID, get the link for this variant. You
can access the link in the Web client as below:

7.2.4 Sample Code

Use JavaScript to show how to use the APIs, as below:

//get dashboard all view codes

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 271
let AnalyticsType = "Dashboard"
let resp = await fetch("/extn/api/analyticsViews?analyticsType=" +
AnalyticsType ,{
method: "GET",
credentials: "include"
});
//get analytics view variants
//get Sales Analysis by Rows Overview variant GUID by viewcode RDR90002
let Viewcode = "RDR90002"
let respvariants = await fetch("/extn/api/analyticsViewVariants?viewCode=" +
Viewcode + "&analyticsType=" + AnalyticsType, {
method: "GET",
credentials: "include"
});
let json = await respvariants.json();
let variantname = "1st Quarter Only"
let guidValue = "";
json.forEach((item,index,json)=>{
if (item.Name === variantName)
{
guidValue = item.Guid;
}
})
//get analytics view link
let variantGUID = "a2dfa8a2-24bb-4a48-b711-002a8d453b31";
let respAnalytic = await fetch("/extn/api/analyticsView?viewCode=" + Viewcode +
"&analyticsType=" + AnalyticsType + "&variantGUID=" + VariantGUID, {
method: "GET",
credentials: "include"
});
let analyticLink = await respAnalytic.text();
let fullanalyticLink = serviceURL + respAnalytic;

7.2.5 Example App

For a better understanding of how to use the APIs, an example is provided for you. The source code and the
mtar package are also provided in the following links respectively.

• You can download and unzip this file to get the source code.
• You can download and unzip this file to get the mtar package, which can be deployed directly to the
Extension Manager and displayed in the Web client as below:

In this app, you have an interactive UI to use the APIs.

API - Get Analytics View Codes

To invoke this API, input the value of the required field Analytics viewType.

Click the GetanalyticsViews button, upon success you get the view codes, and the response is shown in the text
area control.

How to Develop Web Client Extensions


272 PUBLIC Working with APIs That Generate Web Client Views URLs
API - Get Analytics View Variants

To invoke this API, besides the Analytics viewType field, input the value of the field Analytics viewCode.

You can get the value of this field from the response of the first API.

Click the GetViewVariants button, upon success you get the view variants, and the response is shown in the text
area control.

How to Develop Web Client Extensions


Working with APIs That Generate Web Client Views URLs PUBLIC 273
API - Get Analytics View URL

To invoke this API, besides the the two required fields, input the value of the third field Variant GUID.

You can get the value of this field from the response of the second API.

Click the GetanalyticsView button, upon success you get the view URL, and the response is shown in the text
area control.

How to Develop Web Client Extensions


274 PUBLIC Working with APIs That Generate Web Client Views URLs
8 Troubleshooting Guide for Content
Security Policy

Background

As of SAP Business One 10.0 FP 2305, the Web client introduces the Content Security Policy (CSP) to
further enhance its security. For existing or upgraded companies, there is no impact. But for newly created
companies, this feature will be enabled and possibly cause some compatibility issues for the Web client
extensibility. To address this situation, this guide is provided to illustrate how to adjust the CSP settings to
handle various potential CSP issues.

Symptom

As a customer or partner, when opening an extension in the existing window mode, the symptom is that
the extension content is blocked or not displayed. In that case, you can go to the browser's Developer Tools
(also known as Development Mode) and check the errors on the Console tab, where you will find some error
messages relevant to CSP violation.

More details will be explained in the following topics. For information on how to enable the development mode,
please see Browser Development Mode [page 281].

Default CSP Setting

The following CSP is applied to newly created companies by default. When issues arise, adjustment can be
manually made in the General Settings of the Web client.

frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com;


default-src 'self' *.sap.com *.hana.ondemand.com; style-src 'self'
*.sap.com *.hana.ondemand.com 'unsafe-inline'; frame-src 'self' *.sap.com
*.hana.ondemand.com blob:; worker-src 'self' *.sap.com *.hana.ondemand.com blob:

Related Information

Issues and Solutions [page 276]


Appendix [page 280]

How to Develop Web Client Extensions


Troubleshooting Guide for Content Security Policy PUBLIC 275
8.1 Issues and Solutions

How to adjust the CSP settings depends on the specific issues encountered by a given type of extension and
how the extension is programmed. Below are some typical issues and solutions for the sample apps provided in
the guide. If partners develop their own app based on the sample apps, please take the following as a reference
and go to the CSP Generic Approach [page 281] topic to address possible CSP issues.

• Angular App [page 276]


• React App [page 277]
• Blazor App [page 278]
• URL Mashup App [page 279]
• Fiori App [page 280]
• Vue App [page 280]

8.1.1 Angular App

Issues

If you are using an Angular app as your extension, you could possibly run into the following issues on the
Console tab in the browser development mode.

Refused to load the image 'data:image/


svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ij
AgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE
0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIj
QzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiI
C8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS
43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQ
wLjl6IiAvPgogIDwvc3ZnPg==' because it violates the following Content Security
Policy directive: "default-src 'self' *.sap.com *.hana.ondemand.com". Note that
'img-src' was not explicitly set, so 'default-src' is used as a fallback.

Solutions

Append the following CSP directive to the default CSP string.

img-src 'self' *.sap.com *.hana.ondemand.com data:

The final CSP will be:

frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com;


default-src 'self' *.sap.com *.hana.ondemand.com; style-src 'self'
*.sap.com *.hana.ondemand.com 'unsafe-inline'; frame-src 'self' *.sap.com

How to Develop Web Client Extensions


276 PUBLIC Troubleshooting Guide for Content Security Policy
*.hana.ondemand.com blob:; worker-src 'self' *.sap.com *.hana.ondemand.com
blob:;img-src 'self' *.sap.com *.hana.ondemand.com data:

Related Information

CSP Generic Approach [page 281]


Browser Development Mode [page 281]

8.1.2 React App

Issues

If you are using a React app as your extension, you could possibly run into the following issues on the Console
tab in the browser development mode console.

Refused to execute inline script because it violates the following Content


Security Policy directive: "default-src 'self' *.sap.com *.hana.ondemand.com".
Either the 'unsafe-inline' keyword, a hash ('sha256-R79i9Qck3ittlPKbkO8mM/
CeCma7ee3r0rCe5g4CrD0='), or a nonce ('nonce-...') is required to enable inline
execution. Note also that 'script-src' was not explicitly set, so 'default-src'
is used as a fallback.

Solutions

Append the following CSP directive to the default CSP string.

script-src 'self' *.sap.com *.hana.ondemand.com 'sha256-R79i9Qck3ittlPKbkO8mM/


CeCma7ee3r0rCe5g4CrD0='

The final CSP is:

frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com;


default-src 'self' *.sap.com *.hana.ondemand.com; style-src 'self'
*.sap.com *.hana.ondemand.com 'unsafe-inline'; frame-src 'self'
*.sap.com *.hana.ondemand.com blob:; worker-src 'self' *.sap.com
*.hana.ondemand.com blob:;script-src 'self' *.sap.com *.hana.ondemand.com
'sha256-R79i9Qck3ittlPKbkO8mM/CeCma7ee3r0rCe5g4CrD0='

How to Develop Web Client Extensions


Troubleshooting Guide for Content Security Policy PUBLIC 277
Related Information

CSP Generic Approach [page 281]


Browser Development Mode [page 281]

8.1.3 Blazor App

Issues

If you are using a Blazor app as your extension, you could possibly run into the following issues on the Console
tab in the browser development mode.

Refused to execute inline script because it violates the following Content


Security Policy directive: "script-src 'self' *.sap.com *.hana.ondemand.com
'sha256-R79i9Qck3ittlPKbkO8mM/CeCma7ee3r0rCe5g4CrD0='". Either the 'unsafe-
inline' keyword, a hash ('sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA='),
or a nonce ('nonce-...') is required to enable inline execution.
CompileError: WebAssembly.instantiate(): Refused to compile or instantiate
WebAssembly module because 'unsafe-eval' is not an allowed source of script in
the following Content Security Policy directive: "script-src 'self' *.sap.com
*.hana.ondemand.com 'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA='"

Solutions

Append the following CSP directive to the default CSP string.

script-src 'self' *.sap.com *.hana.ondemand.com 'sha256-


v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=' 'unsafe-eval'

The final CSP is:

frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com;


default-src 'self' *.sap.com *.hana.ondemand.com; style-src 'self'
*.sap.com *.hana.ondemand.com 'unsafe-inline'; frame-src 'self'
*.sap.com *.hana.ondemand.com blob:; worker-src 'self' *.sap.com
*.hana.ondemand.com blob:;script-src 'self' *.sap.com *.hana.ondemand.com
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=' 'unsafe-eval'

Related Information

CSP Generic Approach [page 281]


Browser Development Mode [page 281]

How to Develop Web Client Extensions


278 PUBLIC Troubleshooting Guide for Content Security Policy
8.1.4 URL Mashup App

Issues

If you are using a URL mashup app as your extension, you could possibly run into the following issues on the
Console tab in the browser development mode.

Refused to frame 'https://www.bing.com/' because it violates the


following Content Security Policy directive: "frame-src 'self' *.sap.com
*.hana.ondemand.com blob:".

Solutions

Find the frame-src directive and append your app url to the directive, for example www.bing.com.

frame-src 'self' *.sap.com *.hana.ondemand.com blob: www.bing.com;

Alternatively, you can use an asterisk * in your url to make it more generic, like below.

frame-src 'self' *.sap.com *.hana.ondemand.com blob: *.bing.com;

The final CSP is:

frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com;


default-src 'self' *.sap.com *.hana.ondemand.com; style-src 'self'
*.sap.com *.hana.ondemand.com 'unsafe-inline'; frame-src 'self' *.sap.com
*.hana.ondemand.com blob: *.bing.com; worker-src 'self' *.sap.com
*.hana.ondemand.com blob:

Related Information

CSP Generic Approach [page 281]


Browser Development Mode [page 281]

How to Develop Web Client Extensions


Troubleshooting Guide for Content Security Policy PUBLIC 279
8.1.5 Fiori App

Issues

If you are using a Fiori app as your extension, you could possibly run into the before-mentioned issues, or other
CSP issues, on the Console tab of the browser development mode. Whether you encounter issues or not will
depend on how you program with your extension. If your frontend code follows the CSP specifications or some
best practices, you will have no CSP issues.

Solutions

Follow the CSP Generic Approach [page 281] to address possible CSP issues.

8.1.6 Vue App

Issues

If you are using a Vue app as your extension, you could possibly run into the before-mentioned issues, or other
CSP issues, on the Console tab of the browser development mode. Whether you encounter issues or not will
depend on how you program with your extension. If your frontend code follows the CSP specifications or some
best practices, you will have no CSP issues. For example, the Vue sample provided in this guide encountered no
CSP issues.

Solutions

Follow the CSP Generic Approach [page 281] to address possible CSP issues.

8.2 Appendix

You can find the following topics in this section:

How to Develop Web Client Extensions


280 PUBLIC Troubleshooting Guide for Content Security Policy
• CSP Generic Approach [page 281]
• Browser Development Mode [page 281]

8.2.1 CSP Generic Approach

The Content Security Policy (CSP) is a security feature implemented by modern web browsers to prevent
cross-site scripting (XSS) and other code injection attacks. It allows web developers to define a set of rules that
specify which content sources are allowed to be loaded by the browsers.

To address potential CSP issues in the Web client extension, follow the steps below:

1. Determine your content sources. Identify the sources of content that your website should load, such as
images, scripts, styles, fonts, etc. Keep in mind that you should only allow trustworthy sources to minimize
the risks of security breaches.
2. Create a CSP policy. Based on the allowed content sources, create a CSP policy string. The policy string
will consist of one or more directives, each specifying the types of content and their respective sources. For
example, a simple CSP policy string might look like this:

default-src 'self'; script-src 'self' ajax.googleapis.com; img-src 'self'


img.example.com;

This policy only allows the following elements:


• Content from the same origin (using 'self') as the default source
• Scripts from the same origin and ajax.googleapis.com
• Images from the same origin and img.example.com
3. Implement the CSP policy. Update the CSP string properly in the General Settings of the Web client.
4. Test your CSP implementation. After implementing the CSP policy, test your extensions to ensure that they
work as intended. Use the browser's developer tools to check for any CSP violation reports on the Console
tab and address any issues that arise.

 Note

Creating a secure and effective CSP policy may require a thorough understanding of your website's
content and dependencies. It is crucial to test your policy thoroughly and be prepared to make
adjustments if new content sources are introduced.

8.2.2 Browser Development Mode

To access the browser's Developer Tools (also known as Development Mode), follow the steps for the most
popular web browsers:

• Google Chrome
• Press the F12 key or Ctrl + Shift + I (on Mac, press Cmd + Option + I ).

• Alternatively, click the three vertical dots in the top-right corner of the browser, and then go to More
tools Developer tools .

How to Develop Web Client Extensions


Troubleshooting Guide for Content Security Policy PUBLIC 281
• Mozilla Firefox
• Press the F12 key or Ctrl + Shift + I (on Mac, press Cmd + Option + I ).
• Alternatively, click the three horizontal lines (a hamburger-shaped menu) in the top-right corner of the
browser, and then go to Web Developer Toggle Tools .
• Microsoft Edge
• Press the F12 key or Ctrl + Shift + I (on Mac, press Cmd + Option + I ).
• Alternatively, click the three horizontal dots in the top-right corner of the browser, and then go to
More tools Developer tools .
• Safari
1. First, you need to enable the Developer Tools. In the browser, go to Preferences Advanced , and
select the Show Develop menu in menu bar option.
2. Press Cmd + Option + I to open the Web Inspector.
Alternatively, click the Develop menu in the top menu bar and select Show Web Inspector.

Once you’ve accessed the Developer Tools, you'll be able to explore various features like the Elements (DOM)
panel, Console, Network, Application, and more. These tools help you debug, analyze, and optimize your
websites for better performance and user experience.

How to Develop Web Client Extensions


282 PUBLIC Troubleshooting Guide for Content Security Policy
Important Disclaimers and Legal Information

Hyperlinks
Some links are classified by an icon and/or a mouseover text. These links provide additional information.
About the icons:

• Links with the icon : You are entering a Web site that is not hosted by SAP. By using such links, you agree (unless expressly stated otherwise in your
agreements with SAP) to this:

• The content of the linked-to site is not SAP documentation. You may not infer any product claims against SAP based on this information.

• SAP does not agree or disagree with the content on the linked-to site, nor does SAP warrant the availability and correctness. SAP shall not be liable for any
damages caused by the use of such content unless damages have been caused by SAP's gross negligence or willful misconduct.

• Links with the icon : You are leaving the documentation for that particular SAP product or service and are entering an SAP-hosted Web site. By using
such links, you agree that (unless expressly stated otherwise in your agreements with SAP) you may not infer any product claims against SAP based on this
information.

Videos Hosted on External Platforms


Some videos may point to third-party video hosting platforms. SAP cannot guarantee the future availability of videos stored on these platforms. Furthermore, any
advertisements or other content hosted on these platforms (for example, suggested videos or by navigating to other videos hosted on the same site), are not within
the control or responsibility of SAP.

Beta and Other Experimental Features


Experimental features are not part of the officially delivered scope that SAP guarantees for future releases. This means that experimental features may be changed by
SAP at any time for any reason without notice. Experimental features are not for productive use. You may not demonstrate, test, examine, evaluate or otherwise use
the experimental features in a live operating environment or with data that has not been sufficiently backed up.
The purpose of experimental features is to get feedback early on, allowing customers and partners to influence the future product accordingly. By providing your
feedback (e.g. in the SAP Community), you accept that intellectual property rights of the contributions or derivative works shall remain the exclusive property of SAP.

Example Code
Any software coding and/or code snippets are examples. They are not for productive use. The example code is only intended to better explain and visualize the syntax
and phrasing rules. SAP does not warrant the correctness and completeness of the example code. SAP shall not be liable for errors or damages caused by the use of
example code unless damages have been caused by SAP's gross negligence or willful misconduct.

Bias-Free Language
SAP supports a culture of diversity and inclusion. Whenever possible, we use unbiased language in our documentation to refer to people of all cultures, ethnicities,
genders, and abilities.

How to Develop Web Client Extensions


Important Disclaimers and Legal Information PUBLIC 283
www.sap.com/contactsap

© 2024 SAP SE or an SAP affiliate company. All rights reserved.

No part of this publication may be reproduced or transmitted in any form


or for any purpose without the express permission of SAP SE or an SAP
affiliate company. The information contained herein may be changed
without prior notice.

Some software products marketed by SAP SE and its distributors


contain proprietary software components of other software vendors.
National product specifications may vary.

These materials are provided by SAP SE or an SAP affiliate company for


informational purposes only, without representation or warranty of any
kind, and SAP or its affiliated companies shall not be liable for errors or
omissions with respect to the materials. The only warranties for SAP or
SAP affiliate company products and services are those that are set forth
in the express warranty statements accompanying such products and
services, if any. Nothing herein should be construed as constituting an
additional warranty.

SAP and other SAP products and services mentioned herein as well as
their respective logos are trademarks or registered trademarks of SAP
SE (or an SAP affiliate company) in Germany and other countries. All
other product and service names mentioned are the trademarks of their
respective companies.

Please see https://www.sap.com/about/legal/trademark.html for


additional trademark information and notices.

THE BEST RUN

You might also like