@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.
Files changed (114) hide show
  1. package/README.md +384 -0
  2. package/dist/adt-client.js +364 -0
  3. package/dist/cli/activate.js +113 -0
  4. package/dist/cli/init.js +333 -0
  5. package/dist/cli/remove.js +80 -0
  6. package/dist/cli/status.js +229 -0
  7. package/dist/cli/systems.js +68 -0
  8. package/dist/cli.js +81 -0
  9. package/dist/index.js +1318 -0
  10. package/dist/knowledge/abap/abap-dictionary.md +199 -0
  11. package/dist/knowledge/abap/abap-sql.md +296 -0
  12. package/dist/knowledge/abap/amdp.md +273 -0
  13. package/dist/knowledge/abap/clean-code.md +293 -0
  14. package/dist/knowledge/abap/cloud-background-processing.md +250 -0
  15. package/dist/knowledge/abap/cloud-communication.md +265 -0
  16. package/dist/knowledge/abap/cloud-development.md +176 -0
  17. package/dist/knowledge/abap/cloud-extensibility.md +252 -0
  18. package/dist/knowledge/abap/cloud-released-apis.md +261 -0
  19. package/dist/knowledge/abap/constructor-expressions.md +289 -0
  20. package/dist/knowledge/abap/enhancements.md +232 -0
  21. package/dist/knowledge/abap/exceptions.md +271 -0
  22. package/dist/knowledge/abap/internal-tables.md +205 -0
  23. package/dist/knowledge/abap/object-orientation.md +298 -0
  24. package/dist/knowledge/abap/performance.md +216 -0
  25. package/dist/knowledge/abap/rap-abstract-entities.md +206 -0
  26. package/dist/knowledge/abap/rap-business-events.md +216 -0
  27. package/dist/knowledge/abap/rap-draft.md +191 -0
  28. package/dist/knowledge/abap/rap-eml.md +453 -0
  29. package/dist/knowledge/abap/rap-end-to-end.md +486 -0
  30. package/dist/knowledge/abap/rap-feature-control.md +185 -0
  31. package/dist/knowledge/abap/rap-numbering.md +280 -0
  32. package/dist/knowledge/abap/rap-service-exposure.md +163 -0
  33. package/dist/knowledge/abap/rap-unmanaged.md +468 -0
  34. package/dist/knowledge/abap/string-processing.md +180 -0
  35. package/dist/knowledge/abap/unit-testing.md +303 -0
  36. package/dist/knowledge/abap-cds/access-control.md +241 -0
  37. package/dist/knowledge/abap-cds/annotations.md +331 -0
  38. package/dist/knowledge/abap-cds/associations.md +254 -0
  39. package/dist/knowledge/abap-cds/expressions.md +230 -0
  40. package/dist/knowledge/abap-cds/functions.md +245 -0
  41. package/dist/knowledge/abap-cds/metadata-extensions.md +294 -0
  42. package/dist/knowledge/cap/authentication.md +278 -0
  43. package/dist/knowledge/cap/cdl-syntax.md +247 -0
  44. package/dist/knowledge/cap/cql-queries.md +266 -0
  45. package/dist/knowledge/cap/deployment.md +343 -0
  46. package/dist/knowledge/cap/event-handlers.md +287 -0
  47. package/dist/knowledge/cap/fiori-integration.md +303 -0
  48. package/dist/knowledge/cap/service-definitions.md +287 -0
  49. package/dist/knowledge/fiori/annotations.md +347 -0
  50. package/dist/knowledge/fiori/deployment.md +340 -0
  51. package/dist/knowledge/fiori/fiori-elements.md +332 -0
  52. package/dist/knowledge/fiori/fiori-side-effects.md +107 -0
  53. package/dist/knowledge/fiori/fiori-valuelist.md +144 -0
  54. package/dist/knowledge/fiori/ui5-controllers.md +358 -0
  55. package/dist/knowledge/fiori/ui5-data-binding.md +311 -0
  56. package/dist/knowledge/fiori/ui5-fragments-dialogs.md +330 -0
  57. package/dist/knowledge/fiori/ui5-manifest.md +411 -0
  58. package/dist/knowledge/fiori/ui5-routing.md +303 -0
  59. package/dist/knowledge/fiori/ui5-xml-views.md +294 -0
  60. package/dist/logger.js +114 -0
  61. package/dist/system-profile.js +207 -0
  62. package/dist/tools/abap-doc.js +72 -0
  63. package/dist/tools/abapgit.js +161 -0
  64. package/dist/tools/activate.js +68 -0
  65. package/dist/tools/atc-check.js +117 -0
  66. package/dist/tools/auth-object.js +56 -0
  67. package/dist/tools/breakpoints.js +76 -0
  68. package/dist/tools/call-hierarchy.js +84 -0
  69. package/dist/tools/cds-annotations.js +98 -0
  70. package/dist/tools/cds-dependencies.js +65 -0
  71. package/dist/tools/check.js +47 -0
  72. package/dist/tools/code-completion.js +70 -0
  73. package/dist/tools/code-coverage.js +111 -0
  74. package/dist/tools/create-amdp.js +111 -0
  75. package/dist/tools/create-dcl.js +81 -0
  76. package/dist/tools/create-transport.js +38 -0
  77. package/dist/tools/create.js +285 -0
  78. package/dist/tools/data-preview.js +37 -0
  79. package/dist/tools/delete.js +45 -0
  80. package/dist/tools/deploy-bsp.js +298 -0
  81. package/dist/tools/discovery.js +59 -0
  82. package/dist/tools/element-info.js +93 -0
  83. package/dist/tools/enhancements.js +186 -0
  84. package/dist/tools/extract-method.js +44 -0
  85. package/dist/tools/function-group.js +59 -0
  86. package/dist/tools/knowledge.js +275 -0
  87. package/dist/tools/lock-object.js +75 -0
  88. package/dist/tools/message-class.js +67 -0
  89. package/dist/tools/navigate.js +80 -0
  90. package/dist/tools/number-range.js +57 -0
  91. package/dist/tools/object-documentation.js +43 -0
  92. package/dist/tools/object-structure.js +78 -0
  93. package/dist/tools/object-versions.js +57 -0
  94. package/dist/tools/package-contents.js +60 -0
  95. package/dist/tools/pretty-printer.js +35 -0
  96. package/dist/tools/publish-binding.js +49 -0
  97. package/dist/tools/quick-fix.js +69 -0
  98. package/dist/tools/read.js +167 -0
  99. package/dist/tools/refactor-rename.js +60 -0
  100. package/dist/tools/release-transport.js +24 -0
  101. package/dist/tools/released-apis.js +51 -0
  102. package/dist/tools/repository-tree.js +90 -0
  103. package/dist/tools/scaffold-rap.js +642 -0
  104. package/dist/tools/search.js +73 -0
  105. package/dist/tools/shared/data-format.js +101 -0
  106. package/dist/tools/sql-console.js +17 -0
  107. package/dist/tools/system-info.js +270 -0
  108. package/dist/tools/traces.js +66 -0
  109. package/dist/tools/transport-contents.js +83 -0
  110. package/dist/tools/transports.js +67 -0
  111. package/dist/tools/unit-test.js +135 -0
  112. package/dist/tools/where-used.js +59 -0
  113. package/dist/tools/write.js +101 -0
  114. 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 |