@linkup-ai/abap-ai 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +384 -0
- package/dist/adt-client.js +364 -0
- package/dist/cli/activate.js +113 -0
- package/dist/cli/init.js +333 -0
- package/dist/cli/remove.js +80 -0
- package/dist/cli/status.js +229 -0
- package/dist/cli/systems.js +68 -0
- package/dist/cli.js +81 -0
- package/dist/index.js +1318 -0
- package/dist/knowledge/abap/abap-dictionary.md +199 -0
- package/dist/knowledge/abap/abap-sql.md +296 -0
- package/dist/knowledge/abap/amdp.md +273 -0
- package/dist/knowledge/abap/clean-code.md +293 -0
- package/dist/knowledge/abap/cloud-background-processing.md +250 -0
- package/dist/knowledge/abap/cloud-communication.md +265 -0
- package/dist/knowledge/abap/cloud-development.md +176 -0
- package/dist/knowledge/abap/cloud-extensibility.md +252 -0
- package/dist/knowledge/abap/cloud-released-apis.md +261 -0
- package/dist/knowledge/abap/constructor-expressions.md +289 -0
- package/dist/knowledge/abap/enhancements.md +232 -0
- package/dist/knowledge/abap/exceptions.md +271 -0
- package/dist/knowledge/abap/internal-tables.md +205 -0
- package/dist/knowledge/abap/object-orientation.md +298 -0
- package/dist/knowledge/abap/performance.md +216 -0
- package/dist/knowledge/abap/rap-abstract-entities.md +206 -0
- package/dist/knowledge/abap/rap-business-events.md +216 -0
- package/dist/knowledge/abap/rap-draft.md +191 -0
- package/dist/knowledge/abap/rap-eml.md +453 -0
- package/dist/knowledge/abap/rap-end-to-end.md +486 -0
- package/dist/knowledge/abap/rap-feature-control.md +185 -0
- package/dist/knowledge/abap/rap-numbering.md +280 -0
- package/dist/knowledge/abap/rap-service-exposure.md +163 -0
- package/dist/knowledge/abap/rap-unmanaged.md +468 -0
- package/dist/knowledge/abap/string-processing.md +180 -0
- package/dist/knowledge/abap/unit-testing.md +303 -0
- package/dist/knowledge/abap-cds/access-control.md +241 -0
- package/dist/knowledge/abap-cds/annotations.md +331 -0
- package/dist/knowledge/abap-cds/associations.md +254 -0
- package/dist/knowledge/abap-cds/expressions.md +230 -0
- package/dist/knowledge/abap-cds/functions.md +245 -0
- package/dist/knowledge/abap-cds/metadata-extensions.md +294 -0
- package/dist/knowledge/cap/authentication.md +278 -0
- package/dist/knowledge/cap/cdl-syntax.md +247 -0
- package/dist/knowledge/cap/cql-queries.md +266 -0
- package/dist/knowledge/cap/deployment.md +343 -0
- package/dist/knowledge/cap/event-handlers.md +287 -0
- package/dist/knowledge/cap/fiori-integration.md +303 -0
- package/dist/knowledge/cap/service-definitions.md +287 -0
- package/dist/knowledge/fiori/annotations.md +347 -0
- package/dist/knowledge/fiori/deployment.md +340 -0
- package/dist/knowledge/fiori/fiori-elements.md +332 -0
- package/dist/knowledge/fiori/fiori-side-effects.md +107 -0
- package/dist/knowledge/fiori/fiori-valuelist.md +144 -0
- package/dist/knowledge/fiori/ui5-controllers.md +358 -0
- package/dist/knowledge/fiori/ui5-data-binding.md +311 -0
- package/dist/knowledge/fiori/ui5-fragments-dialogs.md +330 -0
- package/dist/knowledge/fiori/ui5-manifest.md +411 -0
- package/dist/knowledge/fiori/ui5-routing.md +303 -0
- package/dist/knowledge/fiori/ui5-xml-views.md +294 -0
- package/dist/logger.js +114 -0
- package/dist/system-profile.js +207 -0
- package/dist/tools/abap-doc.js +72 -0
- package/dist/tools/abapgit.js +161 -0
- package/dist/tools/activate.js +68 -0
- package/dist/tools/atc-check.js +117 -0
- package/dist/tools/auth-object.js +56 -0
- package/dist/tools/breakpoints.js +76 -0
- package/dist/tools/call-hierarchy.js +84 -0
- package/dist/tools/cds-annotations.js +98 -0
- package/dist/tools/cds-dependencies.js +65 -0
- package/dist/tools/check.js +47 -0
- package/dist/tools/code-completion.js +70 -0
- package/dist/tools/code-coverage.js +111 -0
- package/dist/tools/create-amdp.js +111 -0
- package/dist/tools/create-dcl.js +81 -0
- package/dist/tools/create-transport.js +38 -0
- package/dist/tools/create.js +285 -0
- package/dist/tools/data-preview.js +37 -0
- package/dist/tools/delete.js +45 -0
- package/dist/tools/deploy-bsp.js +298 -0
- package/dist/tools/discovery.js +59 -0
- package/dist/tools/element-info.js +93 -0
- package/dist/tools/enhancements.js +186 -0
- package/dist/tools/extract-method.js +44 -0
- package/dist/tools/function-group.js +59 -0
- package/dist/tools/knowledge.js +275 -0
- package/dist/tools/lock-object.js +75 -0
- package/dist/tools/message-class.js +67 -0
- package/dist/tools/navigate.js +80 -0
- package/dist/tools/number-range.js +57 -0
- package/dist/tools/object-documentation.js +43 -0
- package/dist/tools/object-structure.js +78 -0
- package/dist/tools/object-versions.js +57 -0
- package/dist/tools/package-contents.js +60 -0
- package/dist/tools/pretty-printer.js +35 -0
- package/dist/tools/publish-binding.js +49 -0
- package/dist/tools/quick-fix.js +69 -0
- package/dist/tools/read.js +167 -0
- package/dist/tools/refactor-rename.js +60 -0
- package/dist/tools/release-transport.js +24 -0
- package/dist/tools/released-apis.js +51 -0
- package/dist/tools/repository-tree.js +90 -0
- package/dist/tools/scaffold-rap.js +642 -0
- package/dist/tools/search.js +73 -0
- package/dist/tools/shared/data-format.js +101 -0
- package/dist/tools/sql-console.js +17 -0
- package/dist/tools/system-info.js +270 -0
- package/dist/tools/traces.js +66 -0
- package/dist/tools/transport-contents.js +83 -0
- package/dist/tools/transports.js +67 -0
- package/dist/tools/unit-test.js +135 -0
- package/dist/tools/where-used.js +59 -0
- package/dist/tools/write.js +101 -0
- package/package.json +49 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# UI5 manifest.json — complete application descriptor
|
|
2
|
+
|
|
3
|
+
## Minimal manifest.json
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"_version": "1.59.0",
|
|
8
|
+
"sap.app": {
|
|
9
|
+
"id": "com.mycompany.orders",
|
|
10
|
+
"type": "application",
|
|
11
|
+
"applicationVersion": { "version": "1.0.0" },
|
|
12
|
+
"title": "{{appTitle}}",
|
|
13
|
+
"description": "{{appDescription}}",
|
|
14
|
+
"dataSources": {
|
|
15
|
+
"mainService": {
|
|
16
|
+
"uri": "/sap/opu/odata/sap/ZORDER_SRV/",
|
|
17
|
+
"type": "OData",
|
|
18
|
+
"settings": {
|
|
19
|
+
"odataVersion": "2.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"sap.ui": {
|
|
25
|
+
"technology": "UI5",
|
|
26
|
+
"deviceTypes": {
|
|
27
|
+
"desktop": true,
|
|
28
|
+
"tablet": true,
|
|
29
|
+
"phone": true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"sap.ui5": {
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"minUI5Version": "1.120.0",
|
|
35
|
+
"libs": {
|
|
36
|
+
"sap.m": {},
|
|
37
|
+
"sap.ui.core": {},
|
|
38
|
+
"sap.f": {},
|
|
39
|
+
"sap.ui.layout": {}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"models": {
|
|
43
|
+
"i18n": {
|
|
44
|
+
"type": "sap.ui.model.resource.ResourceModel",
|
|
45
|
+
"settings": {
|
|
46
|
+
"bundleName": "com.mycompany.orders.i18n.i18n"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"": {
|
|
50
|
+
"dataSource": "mainService",
|
|
51
|
+
"preload": true,
|
|
52
|
+
"settings": {
|
|
53
|
+
"defaultBindingMode": "TwoWay",
|
|
54
|
+
"defaultCountMode": "Inline",
|
|
55
|
+
"refreshAfterChange": false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"rootView": {
|
|
60
|
+
"viewName": "com.mycompany.orders.view.App",
|
|
61
|
+
"type": "XML",
|
|
62
|
+
"id": "app",
|
|
63
|
+
"async": true
|
|
64
|
+
},
|
|
65
|
+
"routing": {
|
|
66
|
+
"config": {
|
|
67
|
+
"routerClass": "sap.m.routing.Router",
|
|
68
|
+
"type": "View",
|
|
69
|
+
"viewType": "XML",
|
|
70
|
+
"viewPath": "com.mycompany.orders.view",
|
|
71
|
+
"controlId": "appControl",
|
|
72
|
+
"controlAggregation": "pages",
|
|
73
|
+
"async": true
|
|
74
|
+
},
|
|
75
|
+
"routes": [
|
|
76
|
+
{ "name": "list", "pattern": "", "target": "list" },
|
|
77
|
+
{ "name": "detail", "pattern": "Orders/{orderID}", "target": "detail" }
|
|
78
|
+
],
|
|
79
|
+
"targets": {
|
|
80
|
+
"list": { "viewName": "List", "viewLevel": 1 },
|
|
81
|
+
"detail": { "viewName": "Detail", "viewLevel": 2 }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## sap.app — Application Metadata
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"sap.app": {
|
|
93
|
+
"id": "com.mycompany.orders",
|
|
94
|
+
"type": "application",
|
|
95
|
+
"applicationVersion": { "version": "1.0.0" },
|
|
96
|
+
"title": "{{appTitle}}",
|
|
97
|
+
"description": "{{appDescription}}",
|
|
98
|
+
"ach": "FI-GL",
|
|
99
|
+
"resources": "resources.json",
|
|
100
|
+
"sourceTemplate": {
|
|
101
|
+
"id": "@sap/generator-fiori:basic",
|
|
102
|
+
"version": "1.12.0"
|
|
103
|
+
},
|
|
104
|
+
"dataSources": { },
|
|
105
|
+
"crossNavigation": { }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## dataSources — OData V2
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"mainService": {
|
|
115
|
+
"uri": "/sap/opu/odata/sap/ZORDER_SRV/",
|
|
116
|
+
"type": "OData",
|
|
117
|
+
"settings": {
|
|
118
|
+
"annotations": ["annotation0"],
|
|
119
|
+
"localUri": "localService/metadata.xml",
|
|
120
|
+
"odataVersion": "2.0"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"annotation0": {
|
|
124
|
+
"type": "ODataAnnotation",
|
|
125
|
+
"uri": "annotations/annotation.xml",
|
|
126
|
+
"settings": {
|
|
127
|
+
"localUri": "annotations/annotation.xml"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## dataSources — OData V4
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mainService": {
|
|
138
|
+
"uri": "/sap/opu/odata4/sap/zui_order_o4/0001/",
|
|
139
|
+
"type": "OData",
|
|
140
|
+
"settings": {
|
|
141
|
+
"annotations": ["annotation0"],
|
|
142
|
+
"localUri": "localService/metadata.xml",
|
|
143
|
+
"odataVersion": "4.0"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## models — OData V2
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"": {
|
|
154
|
+
"dataSource": "mainService",
|
|
155
|
+
"preload": true,
|
|
156
|
+
"settings": {
|
|
157
|
+
"defaultBindingMode": "TwoWay",
|
|
158
|
+
"defaultCountMode": "Inline",
|
|
159
|
+
"refreshAfterChange": false,
|
|
160
|
+
"useBatch": true,
|
|
161
|
+
"defaultOperationMode": "Server",
|
|
162
|
+
"metadataUrlParams": {
|
|
163
|
+
"sap-value-list": "none"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## models — OData V4
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"": {
|
|
175
|
+
"dataSource": "mainService",
|
|
176
|
+
"preload": true,
|
|
177
|
+
"settings": {
|
|
178
|
+
"synchronizationMode": "None",
|
|
179
|
+
"operationMode": "Server",
|
|
180
|
+
"autoExpandSelect": true,
|
|
181
|
+
"earlyRequests": true,
|
|
182
|
+
"groupId": "$auto",
|
|
183
|
+
"updateGroupId": "$auto"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## models — Additional Models
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"i18n": {
|
|
194
|
+
"type": "sap.ui.model.resource.ResourceModel",
|
|
195
|
+
"settings": {
|
|
196
|
+
"bundleName": "com.mycompany.orders.i18n.i18n",
|
|
197
|
+
"supportedLocales": ["en", "de", "pt_BR"],
|
|
198
|
+
"fallbackLocale": "en"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"device": {
|
|
202
|
+
"type": "sap.ui.model.json.JSONModel",
|
|
203
|
+
"settings": {
|
|
204
|
+
"data": {
|
|
205
|
+
"isPhone": false
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## crossNavigation — FLP Tile
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"sap.app": {
|
|
217
|
+
"crossNavigation": {
|
|
218
|
+
"inbounds": {
|
|
219
|
+
"manageOrders": {
|
|
220
|
+
"semanticObject": "Order",
|
|
221
|
+
"action": "manage",
|
|
222
|
+
"title": "{{appTitle}}",
|
|
223
|
+
"subTitle": "{{appSubTitle}}",
|
|
224
|
+
"icon": "sap-icon://sales-order",
|
|
225
|
+
"signature": {
|
|
226
|
+
"parameters": {
|
|
227
|
+
"OrderID": {
|
|
228
|
+
"defaultValue": { "value": "" }
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"additionalParameters": "allowed"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## dependencies — Libraries
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"sap.ui5": {
|
|
245
|
+
"dependencies": {
|
|
246
|
+
"minUI5Version": "1.120.0",
|
|
247
|
+
"libs": {
|
|
248
|
+
"sap.m": {},
|
|
249
|
+
"sap.ui.core": {},
|
|
250
|
+
"sap.f": {},
|
|
251
|
+
"sap.ui.layout": {},
|
|
252
|
+
"sap.uxap": {},
|
|
253
|
+
"sap.ui.table": {},
|
|
254
|
+
"sap.viz": {},
|
|
255
|
+
"sap.suite.ui.commons": {},
|
|
256
|
+
"sap.fe.templates": {}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
| Library | Use |
|
|
264
|
+
|---------|-----|
|
|
265
|
+
| `sap.m` | Mobile controls (Table, List, Input, Dialog, Page) |
|
|
266
|
+
| `sap.ui.core` | Core framework |
|
|
267
|
+
| `sap.f` | Fiori controls (DynamicPage, FlexibleColumnLayout, Avatar) |
|
|
268
|
+
| `sap.ui.layout` | Layout controls (Grid, Splitter, SimpleForm) |
|
|
269
|
+
| `sap.uxap` | ObjectPageLayout |
|
|
270
|
+
| `sap.ui.table` | Desktop grid table, TreeTable |
|
|
271
|
+
| `sap.viz` | VizFrame charts |
|
|
272
|
+
| `sap.fe.templates` | Fiori Elements templates |
|
|
273
|
+
| `sap.ui.comp` | Smart controls (V2 only) |
|
|
274
|
+
|
|
275
|
+
## contentDensities
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"sap.ui5": {
|
|
280
|
+
"contentDensities": {
|
|
281
|
+
"compact": true,
|
|
282
|
+
"cozy": true
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Component.js — Matching rootView
|
|
289
|
+
|
|
290
|
+
```js
|
|
291
|
+
sap.ui.define([
|
|
292
|
+
"sap/ui/core/UIComponent",
|
|
293
|
+
"sap/ui/model/json/JSONModel",
|
|
294
|
+
"sap/ui/Device"
|
|
295
|
+
], function(UIComponent, JSONModel, Device) {
|
|
296
|
+
"use strict";
|
|
297
|
+
|
|
298
|
+
return UIComponent.extend("com.mycompany.orders.Component", {
|
|
299
|
+
metadata: {
|
|
300
|
+
manifest: "json"
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
init: function() {
|
|
304
|
+
UIComponent.prototype.init.apply(this, arguments);
|
|
305
|
+
|
|
306
|
+
// Device model
|
|
307
|
+
this.setModel(new JSONModel(Device), "device");
|
|
308
|
+
|
|
309
|
+
// Initialize router
|
|
310
|
+
this.getRouter().initialize();
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## App.view.xml — Root View
|
|
317
|
+
|
|
318
|
+
```xml
|
|
319
|
+
<mvc:View
|
|
320
|
+
controllerName="com.mycompany.orders.controller.App"
|
|
321
|
+
xmlns:mvc="sap.ui.core.mvc"
|
|
322
|
+
xmlns="sap.m"
|
|
323
|
+
displayBlock="true">
|
|
324
|
+
|
|
325
|
+
<App id="appControl" busy="{view>/busy}">
|
|
326
|
+
<!-- routing inserts pages here via controlAggregation: "pages" -->
|
|
327
|
+
</App>
|
|
328
|
+
|
|
329
|
+
</mvc:View>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Project Structure
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
webapp/
|
|
336
|
+
├── Component.js
|
|
337
|
+
├── manifest.json
|
|
338
|
+
├── i18n/
|
|
339
|
+
│ ├── i18n.properties # default (English)
|
|
340
|
+
│ ├── i18n_de.properties # German
|
|
341
|
+
│ └── i18n_pt_BR.properties # Portuguese (Brazil)
|
|
342
|
+
├── view/
|
|
343
|
+
│ ├── App.view.xml
|
|
344
|
+
│ ├── List.view.xml
|
|
345
|
+
│ ├── Detail.view.xml
|
|
346
|
+
│ └── NotFound.view.xml
|
|
347
|
+
├── controller/
|
|
348
|
+
│ ├── App.controller.js
|
|
349
|
+
│ ├── BaseController.js
|
|
350
|
+
│ ├── List.controller.js
|
|
351
|
+
│ └── Detail.controller.js
|
|
352
|
+
├── fragments/
|
|
353
|
+
│ ├── CreateDialog.fragment.xml
|
|
354
|
+
│ └── CustomerSelect.fragment.xml
|
|
355
|
+
├── model/
|
|
356
|
+
│ └── formatter.js
|
|
357
|
+
├── css/
|
|
358
|
+
│ └── style.css
|
|
359
|
+
├── localService/
|
|
360
|
+
│ ├── metadata.xml
|
|
361
|
+
│ └── mockdata/
|
|
362
|
+
│ └── Orders.json
|
|
363
|
+
└── test/
|
|
364
|
+
└── ...
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## i18n — Properties File
|
|
368
|
+
|
|
369
|
+
```properties
|
|
370
|
+
# i18n/i18n.properties
|
|
371
|
+
appTitle=Order Management
|
|
372
|
+
appDescription=Manage sales orders
|
|
373
|
+
|
|
374
|
+
# List View
|
|
375
|
+
listTitle=Orders
|
|
376
|
+
listNoData=No orders found
|
|
377
|
+
buttonCreate=Create Order
|
|
378
|
+
|
|
379
|
+
# Detail View
|
|
380
|
+
detailTitle=Order Details
|
|
381
|
+
labelCustomer=Customer
|
|
382
|
+
labelAmount=Amount
|
|
383
|
+
|
|
384
|
+
# Messages
|
|
385
|
+
msgCreated=Order {0} created successfully
|
|
386
|
+
msgDeleted=Order deleted
|
|
387
|
+
msgConfirmDelete=Are you sure you want to delete this order?
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Rules
|
|
391
|
+
- `id` in sap.app must match folder namespace (dots → slashes in path)
|
|
392
|
+
- `"preload": true` on OData model for faster initial load
|
|
393
|
+
- V2: `defaultCountMode: "Inline"` avoids extra $count requests
|
|
394
|
+
- V2: `refreshAfterChange: false` + manual refresh for better control
|
|
395
|
+
- V4: `autoExpandSelect: true` optimizes payload (only requested fields)
|
|
396
|
+
- V4: `groupId: "$auto"` for automatic batching
|
|
397
|
+
- Always define `i18n` model for translatable texts
|
|
398
|
+
- `crossNavigation` required for FLP tile registration
|
|
399
|
+
- `rootView` must match `App.view.xml` with `controlId` matching router config
|
|
400
|
+
|
|
401
|
+
## Anti-Patterns
|
|
402
|
+
| Anti-Pattern | Correct |
|
|
403
|
+
|---|---|
|
|
404
|
+
| Missing `odataVersion` in dataSources | Always specify `"2.0"` or `"4.0"` |
|
|
405
|
+
| V2 model without `defaultCountMode: "Inline"` | Extra $count requests slow list loading |
|
|
406
|
+
| Hardcoded texts in views | Use `{i18n>key}` + i18n properties file |
|
|
407
|
+
| Missing `"preload": true` on OData model | Delays initial data fetch |
|
|
408
|
+
| `async: false` in routing config | Deprecated — always use `async: true` |
|
|
409
|
+
| Missing `crossNavigation` for launchpad app | Tile won't appear in FLP |
|
|
410
|
+
| Component.js without `this.getRouter().initialize()` | Routes won't work |
|
|
411
|
+
| Libraries in dependencies that aren't used | Only include what's imported in views |
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# UI5 Routing — manifest.json routing, navigation, parameters
|
|
2
|
+
|
|
3
|
+
## manifest.json — Routing Configuration
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"sap.ui5": {
|
|
8
|
+
"routing": {
|
|
9
|
+
"config": {
|
|
10
|
+
"routerClass": "sap.m.routing.Router",
|
|
11
|
+
"type": "View",
|
|
12
|
+
"viewType": "XML",
|
|
13
|
+
"viewPath": "com.myapp.view",
|
|
14
|
+
"controlId": "app",
|
|
15
|
+
"controlAggregation": "pages",
|
|
16
|
+
"transition": "slide",
|
|
17
|
+
"async": true,
|
|
18
|
+
"bypassed": {
|
|
19
|
+
"target": "notFound"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"routes": [
|
|
23
|
+
{
|
|
24
|
+
"name": "list",
|
|
25
|
+
"pattern": "",
|
|
26
|
+
"target": "list"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "detail",
|
|
30
|
+
"pattern": "Orders/{orderID}",
|
|
31
|
+
"target": "detail"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "detailItem",
|
|
35
|
+
"pattern": "Orders/{orderID}/Items/{itemID}",
|
|
36
|
+
"target": "detailItem"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "create",
|
|
40
|
+
"pattern": "Orders/new",
|
|
41
|
+
"target": "create"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"targets": {
|
|
45
|
+
"list": {
|
|
46
|
+
"viewName": "List",
|
|
47
|
+
"viewLevel": 1
|
|
48
|
+
},
|
|
49
|
+
"detail": {
|
|
50
|
+
"viewName": "Detail",
|
|
51
|
+
"viewLevel": 2
|
|
52
|
+
},
|
|
53
|
+
"detailItem": {
|
|
54
|
+
"viewName": "DetailItem",
|
|
55
|
+
"viewLevel": 3
|
|
56
|
+
},
|
|
57
|
+
"create": {
|
|
58
|
+
"viewName": "Create",
|
|
59
|
+
"viewLevel": 2
|
|
60
|
+
},
|
|
61
|
+
"notFound": {
|
|
62
|
+
"viewName": "NotFound",
|
|
63
|
+
"viewLevel": 1
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Route Patterns
|
|
72
|
+
|
|
73
|
+
| Pattern | URL Example | Parameters |
|
|
74
|
+
|---------|-------------|------------|
|
|
75
|
+
| `""` | `#/` | (none) |
|
|
76
|
+
| `"Orders/{orderID}"` | `#/Orders/1000` | `{ orderID: "1000" }` |
|
|
77
|
+
| `"Orders/{orderID}/Items/{itemID}"` | `#/Orders/1000/Items/10` | `{ orderID: "1000", itemID: "10" }` |
|
|
78
|
+
| `"Orders/:orderID:"` | `#/Orders/` or `#/Orders/1000` | Optional parameter |
|
|
79
|
+
| `"Orders/{orderID}:?query:"` | `#/Orders/1000?tab=items` | Query parameters |
|
|
80
|
+
|
|
81
|
+
## Navigate To Route
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
// Basic navigation
|
|
85
|
+
this.getRouter().navTo("detail", {
|
|
86
|
+
orderID: sOrderID
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// With query parameters
|
|
90
|
+
this.getRouter().navTo("detail", {
|
|
91
|
+
orderID: sOrderID,
|
|
92
|
+
"?query": { tab: "items", edit: "true" }
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Replace history (no back possible)
|
|
96
|
+
this.getRouter().navTo("list", {}, true);
|
|
97
|
+
|
|
98
|
+
// Navigate from list item press
|
|
99
|
+
onItemPress: function(oEvent) {
|
|
100
|
+
var oContext = oEvent.getSource().getBindingContext();
|
|
101
|
+
this.getRouter().navTo("detail", {
|
|
102
|
+
orderID: oContext.getProperty("OrderID")
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Handle Route Matched
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
onInit: function() {
|
|
111
|
+
this.getRouter().getRoute("detail")
|
|
112
|
+
.attachPatternMatched(this._onRouteMatched, this);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
_onRouteMatched: function(oEvent) {
|
|
116
|
+
var sOrderID = oEvent.getParameter("arguments").orderID;
|
|
117
|
+
var oQuery = oEvent.getParameter("arguments")["?query"] || {};
|
|
118
|
+
|
|
119
|
+
// V2: Bind element with path
|
|
120
|
+
this.getView().bindElement({
|
|
121
|
+
path: "/Orders('" + sOrderID + "')",
|
|
122
|
+
parameters: { expand: "to_Items" },
|
|
123
|
+
events: {
|
|
124
|
+
change: this._onBindingChange.bind(this)
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Handle query params
|
|
129
|
+
if (oQuery.tab) {
|
|
130
|
+
this.byId("iconTabBar").setSelectedKey(oQuery.tab);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
_onBindingChange: function() {
|
|
135
|
+
// Check if entity exists (404 handling)
|
|
136
|
+
if (!this.getView().getBindingContext()) {
|
|
137
|
+
this.getRouter().navTo("notFound", {}, true);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Navigate Back
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
onNavBack: function() {
|
|
146
|
+
var oHistory = sap.ui.core.routing.History.getInstance();
|
|
147
|
+
var sPreviousHash = oHistory.getPreviousHash();
|
|
148
|
+
|
|
149
|
+
if (sPreviousHash !== undefined) {
|
|
150
|
+
window.history.go(-1);
|
|
151
|
+
} else {
|
|
152
|
+
this.getRouter().navTo("list", {}, true);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```xml
|
|
158
|
+
<Page showNavButton="true" navButtonPress=".onNavBack">
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Router Helper Method
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
// In BaseController (reused by all controllers)
|
|
165
|
+
sap.ui.define(["sap/ui/core/mvc/Controller"], function(Controller) {
|
|
166
|
+
return Controller.extend("com.myapp.controller.BaseController", {
|
|
167
|
+
|
|
168
|
+
getRouter: function() {
|
|
169
|
+
return this.getOwnerComponent().getRouter();
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
getModel: function(sName) {
|
|
173
|
+
return this.getView().getModel(sName);
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
setModel: function(oModel, sName) {
|
|
177
|
+
return this.getView().setModel(oModel, sName);
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
getResourceBundle: function() {
|
|
181
|
+
return this.getOwnerComponent().getModel("i18n").getResourceBundle();
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
navTo: function(sRoute, oParams, bReplace) {
|
|
185
|
+
this.getRouter().navTo(sRoute, oParams, bReplace);
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
onNavBack: function() {
|
|
189
|
+
var sPreviousHash = sap.ui.core.routing.History.getInstance().getPreviousHash();
|
|
190
|
+
if (sPreviousHash !== undefined) {
|
|
191
|
+
window.history.go(-1);
|
|
192
|
+
} else {
|
|
193
|
+
this.navTo("list", {}, true);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Detail controller extends BaseController
|
|
200
|
+
return BaseController.extend("com.myapp.controller.Detail", {
|
|
201
|
+
// inherits getRouter, navTo, onNavBack, etc.
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Flexible Column Layout (Master-Detail)
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"sap.ui5": {
|
|
210
|
+
"routing": {
|
|
211
|
+
"config": {
|
|
212
|
+
"routerClass": "sap.f.routing.Router",
|
|
213
|
+
"controlId": "fcl",
|
|
214
|
+
"controlAggregation": "beginColumnPages",
|
|
215
|
+
"async": true,
|
|
216
|
+
"transition": "slide"
|
|
217
|
+
},
|
|
218
|
+
"routes": [
|
|
219
|
+
{
|
|
220
|
+
"name": "list",
|
|
221
|
+
"pattern": ":?query:",
|
|
222
|
+
"target": "list"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"name": "detail",
|
|
226
|
+
"pattern": "Orders/{orderID}:?query:",
|
|
227
|
+
"target": ["list", "detail"]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"name": "detailItem",
|
|
231
|
+
"pattern": "Orders/{orderID}/Items/{itemID}:?query:",
|
|
232
|
+
"target": ["list", "detail", "detailItem"]
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
"targets": {
|
|
236
|
+
"list": {
|
|
237
|
+
"viewName": "List",
|
|
238
|
+
"controlAggregation": "beginColumnPages"
|
|
239
|
+
},
|
|
240
|
+
"detail": {
|
|
241
|
+
"viewName": "Detail",
|
|
242
|
+
"controlAggregation": "midColumnPages"
|
|
243
|
+
},
|
|
244
|
+
"detailItem": {
|
|
245
|
+
"viewName": "DetailItem",
|
|
246
|
+
"controlAggregation": "endColumnPages"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```xml
|
|
255
|
+
<!-- App.view.xml -->
|
|
256
|
+
<mvc:View xmlns:f="sap.f" xmlns:mvc="sap.ui.core.mvc">
|
|
257
|
+
<f:FlexibleColumnLayout id="fcl"
|
|
258
|
+
layout="{fcl>/layout}"
|
|
259
|
+
stateChange=".onStateChange"/>
|
|
260
|
+
</mvc:View>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
// Navigate with layout
|
|
265
|
+
this.getRouter().navTo("detail", {
|
|
266
|
+
orderID: sOrderID,
|
|
267
|
+
"?query": { layout: "TwoColumnsMidExpanded" }
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Not Found Page
|
|
272
|
+
|
|
273
|
+
```xml
|
|
274
|
+
<!-- NotFound.view.xml -->
|
|
275
|
+
<MessagePage
|
|
276
|
+
title="Not Found"
|
|
277
|
+
text="The requested resource was not found"
|
|
278
|
+
icon="sap-icon://document"
|
|
279
|
+
showNavButton="true"
|
|
280
|
+
navButtonPress=".onNavBack"/>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Rules
|
|
284
|
+
- `async: true` is mandatory for modern UI5 apps
|
|
285
|
+
- Routes are matched in order — put specific routes before generic ones
|
|
286
|
+
- `viewLevel` determines transition direction (higher = deeper in nav stack)
|
|
287
|
+
- Always attach `patternMatched` (not `matched`) for detail pages — fires only for this route
|
|
288
|
+
- Handle 404 in `_onBindingChange` — redirect to notFound if context is null
|
|
289
|
+
- Use `BaseController` for shared routing/model methods
|
|
290
|
+
- Use `:?query:` for preserving filter/state in URL
|
|
291
|
+
- FCL: use `sap.f.routing.Router` and `controlAggregation` per target column
|
|
292
|
+
|
|
293
|
+
## Anti-Patterns
|
|
294
|
+
| Anti-Pattern | Correct |
|
|
295
|
+
|---|---|
|
|
296
|
+
| `window.location.hash = "#/route"` | `this.getRouter().navTo("route")` |
|
|
297
|
+
| Attaching `matched` instead of `patternMatched` | `patternMatched` fires only for the specific route |
|
|
298
|
+
| Hardcoded entity path in `bindElement` | Build from route arguments |
|
|
299
|
+
| Missing `bypassed` target in config | Always define a notFound target |
|
|
300
|
+
| Forgetting `async: true` | Required — sync routing is deprecated |
|
|
301
|
+
| Same `viewLevel` for all targets | Set incrementally (1, 2, 3) for correct transitions |
|
|
302
|
+
| Missing `showNavButton` on detail pages | Always show back button on non-root pages |
|
|
303
|
+
| FCL with `sap.m.routing.Router` | Use `sap.f.routing.Router` for FlexibleColumnLayout |
|