@sapui5/sap.ushell_abap 1.152.1 → 1.154.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 (121) hide show
  1. package/package.json +1 -1
  2. package/src/main/js/sap/ushell_abap/.library +1 -1
  3. package/src/main/js/sap/ushell_abap/adapters/abap/AppStateAdapter.js +53 -63
  4. package/src/main/js/sap/ushell_abap/adapters/abap/ClientSideTargetResolutionAdapter.js +1 -1
  5. package/src/main/js/sap/ushell_abap/adapters/abap/CommonDataModelAdapter.js +1 -1
  6. package/src/main/js/sap/ushell_abap/adapters/abap/ConfigurationDefaultsAdapter.js +1 -1
  7. package/src/main/js/sap/ushell_abap/adapters/abap/ContainerAdapter.js +1 -1
  8. package/src/main/js/sap/ushell_abap/adapters/abap/FlpLaunchPageAdapter.js +62 -4
  9. package/src/main/js/sap/ushell_abap/adapters/abap/LaunchPageAdapter.js +1 -1
  10. package/src/main/js/sap/ushell_abap/adapters/abap/NavTargetResolutionAdapter.js +1 -1
  11. package/src/main/js/sap/ushell_abap/adapters/abap/NavTargetResolutionInternalAdapter.js +1 -1
  12. package/src/main/js/sap/ushell_abap/adapters/abap/PageBuildingAdapter.js +1 -1
  13. package/src/main/js/sap/ushell_abap/adapters/abap/PagePersistenceAdapter.js +8 -8
  14. package/src/main/js/sap/ushell_abap/adapters/abap/PersonalizationAdapter.js +1 -1
  15. package/src/main/js/sap/ushell_abap/adapters/abap/PersonalizationV2Adapter.js +1 -1
  16. package/src/main/js/sap/ushell_abap/adapters/abap/SearchAdapter.js +1 -1
  17. package/src/main/js/sap/ushell_abap/adapters/abap/SupportTicketAdapter.js +1 -1
  18. package/src/main/js/sap/ushell_abap/adapters/abap/Ui5ComponentLoaderAdapter.js +1 -1
  19. package/src/main/js/sap/ushell_abap/adapters/abap/UserInfoAdapter.js +11 -11
  20. package/src/main/js/sap/ushell_abap/adapters/abap/VisualizationInstantiationAdapter.js +76 -0
  21. package/src/main/js/sap/ushell_abap/adapters/hana/ContainerAdapter.js +1 -1
  22. package/src/main/js/sap/ushell_abap/adapters/local/ClientSideTargetResolutionAdapter.js +123 -0
  23. package/src/main/js/sap/ushell_abap/adapters/local/FlpLaunchPageAdapter.js +115 -0
  24. package/src/main/js/sap/ushell_abap/adapters/local/MenuAdapter.js +92 -0
  25. package/src/main/js/sap/ushell_abap/adapters/local/PageBuildingAdapter.js +242 -0
  26. package/src/main/js/sap/ushell_abap/adapters/local/PagePersistenceAdapter.js +308 -0
  27. package/src/main/js/sap/ushell_abap/api/S4MyHome.js +58 -0
  28. package/src/main/js/sap/ushell_abap/bootstrap/DirectAppStart.js +28 -15
  29. package/src/main/js/sap/ushell_abap/bootstrap/LoadLaunchpad/CreateRenderer.js +4 -2
  30. package/src/main/js/sap/ushell_abap/bootstrap/LoadLaunchpad/RequestPages.js +2 -6
  31. package/src/main/js/sap/ushell_abap/bootstrap/PlatformConfig.js +5 -5
  32. package/src/main/js/sap/ushell_abap/bootstrap/XhrLogonEventHandler.js +6 -7
  33. package/src/main/js/sap/ushell_abap/bootstrap/abapConstants.js +30 -0
  34. package/src/main/js/sap/ushell_abap/components/SideNavigation/modules/Favorites.js +549 -0
  35. package/src/main/js/sap/ushell_abap/components/SideNavigation/modules/GenericNavigationListProvider.js +241 -0
  36. package/src/main/js/sap/ushell_abap/components/cards/Card.controller.js +117 -0
  37. package/src/main/js/sap/ushell_abap/components/cards/Card.view.xml +11 -0
  38. package/src/main/js/sap/ushell_abap/components/cards/Configuration.controller.js +280 -0
  39. package/src/main/js/sap/ushell_abap/components/cards/Configuration.view.xml +27 -0
  40. package/src/main/js/sap/ushell_abap/components/cards/ManifestPropertyHelper.js +298 -0
  41. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/Component.js +90 -0
  42. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/TransactionCode.controller.js +110 -0
  43. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/TransactionCode.view.xml +16 -0
  44. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n.properties +17 -0
  45. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ar.properties +10 -0
  46. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_bg.properties +10 -0
  47. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ca.properties +10 -0
  48. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_cnr.properties +10 -0
  49. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_cs.properties +10 -0
  50. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_cy.properties +10 -0
  51. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_da.properties +10 -0
  52. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_de.properties +10 -0
  53. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_el.properties +10 -0
  54. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_en.properties +10 -0
  55. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_en_GB.properties +10 -0
  56. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_en_US_sappsd.properties +10 -0
  57. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_en_US_saprigi.properties +10 -0
  58. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_en_US_saptrc.properties +10 -0
  59. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_es.properties +10 -0
  60. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_es_MX.properties +10 -0
  61. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_et.properties +10 -0
  62. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_fi.properties +10 -0
  63. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_fr.properties +10 -0
  64. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_fr_CA.properties +10 -0
  65. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_hi.properties +10 -0
  66. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_hr.properties +10 -0
  67. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_hu.properties +10 -0
  68. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_id.properties +10 -0
  69. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_it.properties +10 -0
  70. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_iw.properties +10 -0
  71. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ja.properties +10 -0
  72. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_kk.properties +10 -0
  73. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ko.properties +10 -0
  74. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_lt.properties +10 -0
  75. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_lv.properties +10 -0
  76. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_mk.properties +10 -0
  77. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ms.properties +10 -0
  78. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_nl.properties +10 -0
  79. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_no.properties +10 -0
  80. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_pl.properties +10 -0
  81. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_pt.properties +10 -0
  82. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_pt_PT.properties +10 -0
  83. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ro.properties +10 -0
  84. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_ru.properties +10 -0
  85. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_sh.properties +10 -0
  86. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_sk.properties +10 -0
  87. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_sl.properties +10 -0
  88. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_sr.properties +10 -0
  89. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_sv.properties +10 -0
  90. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_th.properties +10 -0
  91. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_tr.properties +10 -0
  92. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_uk.properties +10 -0
  93. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_vi.properties +10 -0
  94. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_zh_CN.properties +10 -0
  95. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/i18n/i18n_zh_TW.properties +10 -0
  96. package/src/main/js/sap/ushell_abap/components/settings/TransactionCode/manifest.json +96 -0
  97. package/src/main/js/sap/ushell_abap/components/tiles/action/ActionTile.controller.js +189 -0
  98. package/src/main/js/sap/ushell_abap/components/tiles/action/ActionTile.view.xml +13 -0
  99. package/src/main/js/sap/ushell_abap/components/tiles/action/Configuration.controller.js +193 -0
  100. package/src/main/js/sap/ushell_abap/components/tiles/action/Configuration.view.xml +333 -0
  101. package/src/main/js/sap/ushell_abap/components/tiles/applauncher/Component.js +41 -0
  102. package/src/main/js/sap/ushell_abap/components/tiles/applauncher/Configuration.controller.js +114 -0
  103. package/src/main/js/sap/ushell_abap/components/tiles/applauncher/Configuration.view.xml +208 -0
  104. package/src/main/js/sap/ushell_abap/components/tiles/applauncher/StaticTile.controller.js +497 -0
  105. package/src/main/js/sap/ushell_abap/components/tiles/applauncher/StaticTile.view.js +61 -0
  106. package/src/main/js/sap/ushell_abap/components/tiles/applauncherdynamic/Component.js +45 -0
  107. package/src/main/js/sap/ushell_abap/components/tiles/applauncherdynamic/Configuration.controller.js +113 -0
  108. package/src/main/js/sap/ushell_abap/components/tiles/applauncherdynamic/Configuration.view.xml +231 -0
  109. package/src/main/js/sap/ushell_abap/components/tiles/applauncherdynamic/DynamicTile.controller.js +729 -0
  110. package/src/main/js/sap/ushell_abap/components/tiles/applauncherdynamic/DynamicTile.view.js +106 -0
  111. package/src/main/js/sap/ushell_abap/library.js +12 -1
  112. package/src/main/js/sap/ushell_abap/messagebundle.properties +6 -2
  113. package/src/main/js/sap/ushell_abap/pbServices/ui2/Chip.js +7 -3
  114. package/src/main/js/sap/ushell_abap/pbServices/ui2/ODataWrapper.js +3 -5
  115. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/configuration.js +54 -4
  116. package/src/main/js/sap/ushell_abap/services/NavigationDataProvider.js +4 -4
  117. package/src/main/js/sap/ushell_abap/ui/VisualizationInstantiation/ChipInstanceWrapper.js +248 -0
  118. package/src/main/js/sap/ushell_abap/ui/VisualizationInstantiation/VizInstanceAbap.js +134 -0
  119. package/src/main/js/sap/ushell_abap/ui/VisualizationInstantiation/VizInstanceAbapLink.js +145 -0
  120. package/src/main/js/sap/ushell_abap/utils/UserPersonalization.js +127 -0
  121. package/ui5.yaml +21 -3
@@ -0,0 +1,729 @@
1
+ // Copyright (c) 2009-2026 SAP SE, All Rights Reserved
2
+
3
+ sap.ui.define([
4
+ "sap/ui/core/EventBus",
5
+ "sap/ushell/library",
6
+ "sap/ui/core/mvc/Controller",
7
+ "sap/ushell_abap/utils/UserPersonalization",
8
+ "sap/ushell/components/tiles/utils",
9
+ "sap/ushell/Config",
10
+ "sap/ushell/utils/WindowUtils",
11
+ "sap/m/library",
12
+ "sap/ui/model/json/JSONModel",
13
+ "sap/base/Log",
14
+ "sap/ushell/utils/DynamicTileRequest",
15
+ "sap/ushell/base/UrlParsing",
16
+ "sap/ushell/utils",
17
+ "sap/ushell/EventHub",
18
+ "sap/ushell/Container",
19
+ "sap/ushell/utils/LaunchpadError"
20
+ ], (
21
+ EventBus,
22
+ ushellLibrary,
23
+ Controller,
24
+ UserPersonalization,
25
+ tileUtils,
26
+ Config,
27
+ WindowUtils,
28
+ mobileLibrary,
29
+ JSONModel,
30
+ Log,
31
+ DynamicTileRequest,
32
+ UrlParsing,
33
+ ushellUtils,
34
+ EventHub,
35
+ Container,
36
+ LaunchpadError
37
+ ) => {
38
+ "use strict";
39
+
40
+ // shortcut for sap.m.GenericTileScope
41
+ const GenericTileScope = mobileLibrary.GenericTileScope;
42
+
43
+ // shortcut for sap.m.GenericTileMode
44
+ const GenericTileMode = mobileLibrary.GenericTileMode;
45
+
46
+ // shortcut for sap.ushell.AppType
47
+ const AppType = ushellLibrary.AppType;
48
+
49
+ // shortcut for sap.m.FrameType
50
+ const FrameType = mobileLibrary.FrameType;
51
+
52
+ /* global hasher */
53
+
54
+ const COMPONENT_NAME = "sap.ushell_abap.components.tiles.applauncherdynamic.DynamicTile";
55
+
56
+ return Controller.extend(COMPONENT_NAME, {
57
+ _aDoables: [],
58
+
59
+ // handle to control/cancel data.js OData.read()
60
+ oDataRequest: null,
61
+
62
+ sConfigNavigationTargetUrlOld: "",
63
+
64
+ REFRESH_INTERVAL_MIN: 10,
65
+
66
+ constructTargetUrlWithSapSystem: function (sNavigationTargetUrl, sSystem) {
67
+ let oParsedHash;
68
+
69
+ if (sSystem) { // propagate system to target application
70
+ // when the navigation url is hash we want to make sure system parameter is in the parameters part
71
+ // BCP 1780450594
72
+ if (UrlParsing.isIntentUrl(sNavigationTargetUrl)) {
73
+ oParsedHash = UrlParsing.parseShellHash(sNavigationTargetUrl);
74
+ if (!oParsedHash.params) {
75
+ oParsedHash.params = {};
76
+ }
77
+ oParsedHash.params["sap-system"] = sSystem;
78
+ sNavigationTargetUrl = `#${UrlParsing.constructShellHash(oParsedHash)}`;
79
+ } else {
80
+ sNavigationTargetUrl += `${(sNavigationTargetUrl.indexOf("?") < 0) ? "?" : "&"}sap-system=${sSystem}`;
81
+ }
82
+ }
83
+ return sNavigationTargetUrl;
84
+ },
85
+
86
+ onInit: function () {
87
+ this._aDoables = [];
88
+ const that = this;
89
+ const oView = this.getView();
90
+ const oViewData = oView.getViewData();
91
+ const oTileApi = oViewData.chip;
92
+ const oConfig = tileUtils.getAppLauncherConfig(oTileApi, oTileApi.configurationUi.isEnabled(), false);
93
+ const sNavigationTargetUrlInit = oConfig.navigation_target_url;
94
+ const sSystem = oTileApi.url.getApplicationSystem();
95
+
96
+ this.sConfigNavigationTargetUrlOld = oConfig.navigation_target_url;
97
+ Log.setLevel(2, COMPONENT_NAME);
98
+
99
+ this.bIsRequestCompleted = false;
100
+ this.navigationTargetUrl = this.constructTargetUrlWithSapSystem(sNavigationTargetUrlInit, sSystem);
101
+
102
+ const oModel = new JSONModel({
103
+ sizeBehavior: Config.last("/core/home/sizeBehavior"),
104
+ wrappingType: Config.last("/core/home/wrappingType"),
105
+ config: oConfig,
106
+ // These initial values are overwritten by the types contract
107
+ mode: oConfig.display_mode || GenericTileMode.ContentMode,
108
+ frameType: FrameType.OneByOne,
109
+ data: tileUtils.getDataToDisplay(oConfig, {
110
+ number: ((oTileApi.preview && oTileApi.preview.isEnabled()) ? 1234 : "...")
111
+ }),
112
+ nav: { navigation_target_url: (oTileApi.configurationUi && oTileApi.configurationUi.isEnabled() ? "" : this.navigationTargetUrl) },
113
+ search: { display_highlight_terms: [] }
114
+ });
115
+ oView.setModel(oModel);
116
+ // listen for changes of the size behavior, as the end user can change it in the settings (if enabled)
117
+ this._aDoables.push(Config.on("/core/home/sizeBehavior").do((sSizeBehavior) => {
118
+ oModel.setProperty("/sizeBehavior", sSizeBehavior);
119
+ }));
120
+
121
+ // implement types contact
122
+ // default is Tile
123
+ if (oTileApi.types) {
124
+ oTileApi.types.attachSetType((sType) => {
125
+ if (that.tileType === sType) {
126
+ return;
127
+ }
128
+ let sMode = oModel.getProperty("/config/display_mode");
129
+ let sFrameType;
130
+ switch (sType) {
131
+ case "tilewide":
132
+ sMode ||= GenericTileMode.ContentMode;
133
+ sFrameType = FrameType.TwoByOne;
134
+ break;
135
+ case "flat":
136
+ sMode ||= GenericTileMode.ContentMode;
137
+ sFrameType = FrameType.OneByHalf;
138
+ break;
139
+ case "flatwide":
140
+ sMode ||= GenericTileMode.ContentMode;
141
+ sFrameType = FrameType.TwoByHalf;
142
+ break;
143
+ case "link":
144
+ sMode = GenericTileMode.LineMode;
145
+ sFrameType = FrameType.OneByOne;
146
+ break;
147
+
148
+ case "tile":
149
+ default:
150
+ sMode ||= GenericTileMode.ContentMode;
151
+ sFrameType = FrameType.OneByOne;
152
+ break;
153
+ }
154
+ oModel.setProperty("/mode", sMode);
155
+ oModel.setProperty("/frameType", sFrameType);
156
+
157
+ that.tileType = sType;
158
+ });
159
+ }
160
+
161
+ if (!this.tileType) {
162
+ this.tileType = "tile";
163
+ }
164
+
165
+ // implement search contract
166
+ if (oTileApi.search) {
167
+ // split and clean keyword string (may be comma + space delimited)
168
+ const sKeywords = oView.getModel().getProperty("/config/display_search_keywords");
169
+ const aKeywords = sKeywords
170
+ .split(/[, ]+/)
171
+ .filter((n, i) => { return n && n !== ""; });
172
+
173
+ // add title, subtitle, info and number unit (if present) to keywords for better FLP searching
174
+ if (oConfig.display_title_text && oConfig.display_title_text !== "" &&
175
+ aKeywords.indexOf(oConfig.display_title_text) === -1) {
176
+ aKeywords.push(oConfig.display_title_text);
177
+ }
178
+ if (oConfig.display_subtitle_text && oConfig.display_subtitle_text !== "" &&
179
+ aKeywords.indexOf(oConfig.display_subtitle_text) === -1) {
180
+ aKeywords.push(oConfig.display_subtitle_text);
181
+ }
182
+ if (oConfig.display_info_text && oConfig.display_info_text !== "" &&
183
+ aKeywords.indexOf(oConfig.display_info_text) === -1) {
184
+ aKeywords.push(oConfig.display_info_text);
185
+ }
186
+ // The Number Unit may not only be a currency but can also be something like "open leave requests"
187
+ // which the user may want to search for.
188
+ // Note: Number unit is the only not translatable property.
189
+ if (oConfig.display_number_unit && oConfig.display_number_unit !== "" &&
190
+ aKeywords.indexOf(oConfig.display_number_unit) === -1) {
191
+ aKeywords.push(oConfig.display_number_unit);
192
+ }
193
+
194
+ // defined in search contract:
195
+ oTileApi.search.setKeywords(aKeywords);
196
+ oTileApi.search.attachHighlight(
197
+ (aHighlightWords) => {
198
+ // update model for highlighted search term
199
+ oView.getModel().setProperty("/search/display_highlight_terms", aHighlightWords);
200
+ }
201
+ );
202
+ }
203
+
204
+ // implement bag update handler
205
+ if (oTileApi.bag && oTileApi.bag.attachBagsUpdated) {
206
+ // is only called by the FLP for bookmark tiles which have been updated via bookmark service
207
+ oTileApi.bag.attachBagsUpdated((aUpdatedBagIds) => {
208
+ if (aUpdatedBagIds.indexOf("tileProperties") > -1) {
209
+ tileUtils._updateTilePropertiesTexts(oView, oTileApi.bag.getBag("tileProperties"));
210
+ }
211
+ });
212
+ }
213
+
214
+ // implement configuration update handler
215
+ if (oTileApi.configuration) {
216
+ oTileApi.configuration.getTransactionCode().then((sEffective) => {
217
+ this.getView().getModel().setProperty("/config/display_transaction_code_effective", sEffective);
218
+ });
219
+
220
+ if (oTileApi.configuration.attachConfigurationUpdated) {
221
+ // is only called by the FLP for bookmark tiles which have been updated via bookmark service
222
+ oTileApi.configuration.attachConfigurationUpdated((aUpdatedConfigKeys) => {
223
+ if (aUpdatedConfigKeys.indexOf("tileConfiguration") > -1) {
224
+ tileUtils._updateTileConfiguration(oView, oTileApi.configuration.getParameterValueAsString("tileConfiguration"));
225
+ }
226
+
227
+ oTileApi.configuration.getTransactionCode().then((sEffective) => {
228
+ this.getView().getModel().setProperty("/config/display_transaction_code_effective", sEffective);
229
+ });
230
+ });
231
+ }
232
+ }
233
+
234
+ // implement preview contract
235
+ if (oTileApi.preview) {
236
+ oTileApi.preview.setTargetUrl(this.navigationTargetUrl);
237
+ oTileApi.preview.setPreviewIcon(oConfig.display_icon_url);
238
+ oTileApi.preview.setPreviewTitle(oConfig.display_title_text);
239
+ if (oTileApi.preview.setPreviewSubtitle && typeof oTileApi.preview.setPreviewSubtitle === "function") {
240
+ oTileApi.preview.setPreviewSubtitle(oConfig.display_subtitle_text);
241
+ }
242
+ }
243
+
244
+ // implement configurationUi contract: setup configuration UI
245
+ if (oTileApi.configurationUi.isEnabled()) {
246
+ oTileApi.configurationUi.setAsyncUiProvider(() => {
247
+ return tileUtils.getConfigurationUi(
248
+ oView,
249
+ "sap.ushell_abap.components.tiles.applauncherdynamic.Configuration"
250
+ ).then((oConfigurationUi) => {
251
+ oTileApi.configurationUi.attachCancel(that.onCancelConfiguration.bind(null, oConfigurationUi));
252
+ oTileApi.configurationUi.attachSave(that.onSaveConfiguration.bind(null, oConfigurationUi));
253
+ return oConfigurationUi;
254
+ });
255
+ });
256
+
257
+ this.getView().getContent()[0].setTooltip(
258
+ tileUtils.getResourceBundle()
259
+ .getText("edit_configuration.tooltip")
260
+ );
261
+ } else if (!oTileApi.preview || !oTileApi.preview.isEnabled()) {
262
+ if (!sSystem) {
263
+ Container.addRemoteSystemForServiceUrl(oConfig.service_url);
264
+ } // else registration is skipped because registration has been done already
265
+ // outside this controller (e.g. remote catalog registration)
266
+
267
+ // start fetching data from backend service if not in preview or admin mode
268
+ this.bNeedsRefresh = true;
269
+ this.iNrOfTimerRunning = 0;
270
+ }
271
+
272
+ // implement refresh contract
273
+ if (oTileApi.refresh) {
274
+ oTileApi.refresh.attachRefresh(this.refreshHandler.bind(this));
275
+ }
276
+
277
+ // implement visible contract
278
+ if (oTileApi.visible) {
279
+ oTileApi.visible.attachVisible(this.visibleHandler.bind(this));
280
+ }
281
+
282
+ // attach the tile actions provider for the actions contract
283
+ if (oTileApi.actions) {
284
+ let aExtendedActions;
285
+ const aActions = oConfig.actions;
286
+ if (aActions) {
287
+ aExtendedActions = aActions.slice();
288
+ } else {
289
+ aExtendedActions = [];
290
+ }
291
+
292
+ if (Config.last("/core/shell/enablePersonalization")) {
293
+ const sType = oModel.getProperty("/mode") === GenericTileMode.LineMode ? "link" : "tile";
294
+ const tileSettingsAction = tileUtils.getTileSettingsAction(oModel, this.onSaveRuntimeSettings.bind(this), sType);
295
+ aExtendedActions.push(tileSettingsAction);
296
+ }
297
+
298
+ oTileApi.actions.setActionsProvider(() => {
299
+ return aExtendedActions;
300
+ });
301
+ }
302
+ EventBus.getInstance().subscribe("launchpad", "sessionTimeout", this._clearRequest, this);
303
+ },
304
+
305
+ // convenience function to stop browser's timeout and OData calls
306
+ stopRequests: function () {
307
+ if (this.oDataRequest) {
308
+ // actual request abort
309
+ if (this.oDataRequest.abort()) {
310
+ // We didn't finish the last refresh, so we need todo one as soon as the tile becomes visible again
311
+ this.bNeedsRefresh = true;
312
+ }
313
+ }
314
+ },
315
+
316
+ _clearRequest: function () {
317
+ this.stopRequests();
318
+ clearTimeout(this.timer);
319
+ },
320
+
321
+ // destroy handler stops requests
322
+ onExit: function () {
323
+ if (this.oDataRequest) {
324
+ this._clearRequest();
325
+ this.oDataRequest.destroy();
326
+ }
327
+ EventBus.getInstance().unsubscribe("launchpad", "sessionTimeout", this._clearRequest, this);
328
+ this._aDoables.forEach((oDoable) => {
329
+ oDoable.off();
330
+ });
331
+ this._aDoables = [];
332
+ },
333
+
334
+ // trigger to show the configuration UI if the tile is pressed in Admin mode
335
+ onPress: function (oEvent) {
336
+ const oView = this.getView();
337
+ const oViewData = oView.getViewData();
338
+ const oModel = oView.getModel();
339
+ const sTargetUrl = oModel.getProperty("/nav/navigation_target_url");
340
+ const oTileApi = oViewData.chip;
341
+ const oTileConfig = oModel.getProperty("/config");
342
+
343
+ // scope is property of generic tile. It's default value is "Display"
344
+ if (oEvent.getSource().getScope && oEvent.getSource().getScope() === GenericTileScope.Display) {
345
+ if (oTileApi.configurationUi.isEnabled()) {
346
+ oTileApi.configurationUi.display();
347
+ } else if (sTargetUrl) {
348
+ EventHub.emit("UITracer.trace", {
349
+ reason: "LaunchApp",
350
+ source: "Tile",
351
+ data: {
352
+ targetUrl: sTargetUrl
353
+ }
354
+ });
355
+ if (sTargetUrl[0] === "#") {
356
+ hasher.setHash(sTargetUrl);
357
+ } else {
358
+ // add theURL to recent activity log
359
+ const bLogRecentActivity = Config.last("/core/shell/enableRecentActivity") && Config.last("/core/shell/enableRecentActivityLogging");
360
+ if (bLogRecentActivity) {
361
+ const oRecentEntry = {
362
+ title: oTileConfig.display_title_text,
363
+ appType: AppType.URL,
364
+ url: oTileConfig.navigation_target_url,
365
+ appId: oTileConfig.navigation_target_url
366
+ };
367
+ Container.getRendererInternal().logRecentActivity(oRecentEntry);
368
+ }
369
+
370
+ WindowUtils.openURL(sTargetUrl, "_blank");
371
+ }
372
+ }
373
+ }
374
+ },
375
+
376
+ // tile settings action UI save handler
377
+ onSaveRuntimeSettings: function (oSettingsView) {
378
+ const oView = this.getView();
379
+ const oViewModel = oView.getModel();
380
+ const oTileApi = oView.getViewData().chip;
381
+ const oConfigToSave = oViewModel.getProperty("/config");
382
+ const oSettingsViewModel = oSettingsView.getModel();
383
+
384
+ oConfigToSave.display_title_text = oSettingsViewModel.getProperty("/title") || "";
385
+ oConfigToSave.display_subtitle_text = oSettingsViewModel.getProperty("/subtitle") || "";
386
+ oConfigToSave.display_info_text = oSettingsViewModel.getProperty("/info") || "";
387
+ oConfigToSave.display_search_keywords = oSettingsViewModel.getProperty("/keywords") || "";
388
+
389
+ // use bag contract in order to store translatable properties
390
+ const tilePropertiesBag = oTileApi.bag.getBag("tileProperties");
391
+ tilePropertiesBag.setText("display_title_text", oConfigToSave.display_title_text);
392
+ tilePropertiesBag.setText("display_subtitle_text", oConfigToSave.display_subtitle_text);
393
+ tilePropertiesBag.setText("display_info_text", oConfigToSave.display_info_text);
394
+ tilePropertiesBag.setText("display_search_keywords", oConfigToSave.display_search_keywords);
395
+
396
+ // saving the relevant properties
397
+ tilePropertiesBag.save(
398
+ // success handler
399
+ () => {
400
+ Log.debug("property bag 'tileProperties' saved successfully");
401
+
402
+ // update the local tile's config - saving changes on the Model
403
+ oViewModel.setProperty("/config", oConfigToSave);
404
+
405
+ // update tile's model for changes to appear immediately
406
+ // (and not wait for the refresh handler which happens every 10 seconds)
407
+ oViewModel.setProperty("/data/display_title_text", oConfigToSave.display_title_text);
408
+ oViewModel.setProperty("/data/display_subtitle_text", oConfigToSave.display_subtitle_text);
409
+ oViewModel.setProperty("/data/display_info_text", oConfigToSave.display_info_text);
410
+
411
+ // call to refresh model which (due to the binding) will refresh the tile
412
+ oViewModel.refresh();
413
+ },
414
+ // fnFailure
415
+ (mErrorMessages, mErrorInfo) => {
416
+ const sFirstFailedBag = Object.keys(mErrorMessages)[0];
417
+
418
+ const oError = new LaunchpadError(`Bag save failed: ${mErrorMessages[sFirstFailedBag]}`, {
419
+ info: mErrorInfo[sFirstFailedBag],
420
+ otherMessages: mErrorMessages,
421
+ otherInfo: mErrorInfo
422
+ });
423
+ Log.error("Bag save failed", oError, COMPONENT_NAME);
424
+ }
425
+ );
426
+ },
427
+
428
+ // configuration save handler
429
+ onSaveConfiguration: async function (oConfigurationView) {
430
+ const oModel = oConfigurationView.getModel();
431
+ // tile model placed into configuration model by getConfigurationUi
432
+ const oTileModel = oModel.getProperty("/tileModel");
433
+ const oTileApi = oConfigurationView.getViewData().chip;
434
+ const aTileNavigationActions = tileUtils.tileActionsRows2TileActionsArray(oModel.getProperty("/config/tile_actions_rows"));
435
+ // get the configuration to save from the model
436
+ const configToSave = {
437
+ display_icon_url: oModel.getProperty("/config/display_icon_url"),
438
+ display_number_unit: oModel.getProperty("/config/display_number_unit"),
439
+ service_url: oModel.getProperty("/config/service_url"),
440
+ service_refresh_interval: oModel.getProperty("/config/service_refresh_interval"),
441
+ navigation_use_semantic_object: oModel.getProperty("/config/navigation_use_semantic_object"),
442
+ navigation_target_url: oModel.getProperty("/config/navigation_target_url"),
443
+ navigation_semantic_object: (oModel.getProperty("/config/navigation_semantic_object") || "").trim(),
444
+ navigation_semantic_action: (oModel.getProperty("/config/navigation_semantic_action") || "").trim(),
445
+ navigation_semantic_parameters: (oModel.getProperty("/config/navigation_semantic_parameters") || "").trim(),
446
+ display_search_keywords: oModel.getProperty("/config/display_search_keywords")
447
+ };
448
+ // If the input fields icon, semantic object and action are failing the input validations, then through an error message requesting the user to enter/correct those fields
449
+ let bReject = tileUtils.checkInputOnSaveConfig(oConfigurationView);
450
+ if (!bReject) {
451
+ bReject = tileUtils.checkTileActions(oConfigurationView);
452
+ }
453
+ if (bReject) {
454
+ throw new Error("mandatory_fields_missing");
455
+ }
456
+ // overwrite target URL in case of semantic object navigation
457
+ if (configToSave.navigation_use_semantic_object) {
458
+ configToSave.navigation_target_url = tileUtils.getSemanticNavigationUrl(configToSave);
459
+ oModel.setProperty("/config/navigation_target_url", configToSave.navigation_target_url);
460
+ }
461
+
462
+ // use bag contract in order to store translatable properties
463
+ const tilePropertiesBag = oTileApi.bag.getBag("tileProperties");
464
+ tilePropertiesBag.setText("display_title_text", oModel.getProperty("/config/display_title_text"));
465
+ tilePropertiesBag.setText("display_subtitle_text", oModel.getProperty("/config/display_subtitle_text"));
466
+ tilePropertiesBag.setText("display_info_text", oModel.getProperty("/config/display_info_text"));
467
+ tilePropertiesBag.setText("display_search_keywords", configToSave.display_search_keywords);
468
+
469
+ const tileNavigationActionsBag = oTileApi.bag.getBag("tileNavigationActions");
470
+ // forward populating of tile navigation actions array into the bag, to Utils
471
+ tileUtils.populateTileNavigationActionsBag(tileNavigationActionsBag, aTileNavigationActions);
472
+
473
+ const oSaveDeferred = Promise.withResolvers();
474
+
475
+ // use configuration contract to write parameter values
476
+ oTileApi.writeConfiguration.setParameterValues(
477
+ { tileConfiguration: JSON.stringify(configToSave) },
478
+ // success handler
479
+ () => {
480
+ const oConfigurationConfig = tileUtils.getAppLauncherConfig(oTileApi, false, false);
481
+ // get tile config data in admin mode
482
+ const oTileConfig = tileUtils.getAppLauncherConfig(oTileApi, true, false);
483
+ // switching the model under the tile -> keep the tile model
484
+ const oModel = new JSONModel({
485
+ config: oConfigurationConfig,
486
+ // keep tile model
487
+ tileModel: oTileModel
488
+ });
489
+ oConfigurationView.setModel(oModel);
490
+
491
+ // update tile model
492
+ oTileModel.setData({ data: oTileConfig, nav: { navigation_target_url: "" } }, false);
493
+ if (oTileApi.preview) {
494
+ oTileApi.preview.setTargetUrl(oConfigurationConfig.navigation_target_url);
495
+ oTileApi.preview.setPreviewIcon(oConfigurationConfig.display_icon_url);
496
+ oTileApi.preview.setPreviewTitle(oConfigurationConfig.display_title_text);
497
+ if (oTileApi.preview.setPreviewSubtitle && typeof oTileApi.preview.setPreviewSubtitle === "function") {
498
+ oTileApi.preview.setPreviewSubtitle(oConfigurationConfig.display_subtitle_text);
499
+ }
500
+ }
501
+
502
+ tilePropertiesBag.save(
503
+ // success handler
504
+ () => {
505
+ Log.debug("property bag 'tileProperties' saved successfully");
506
+ // update possibly changed values via contracts
507
+ if (oTileApi.title) {
508
+ oTileApi.title.setTitle(
509
+ oConfigurationConfig.display_title_text,
510
+ // success handler
511
+ () => {
512
+ oSaveDeferred.resolve();
513
+ },
514
+ // error handler
515
+ (sErrorMessage, oErrorInfo) => {
516
+ Log.error(`property bag 'tileProperties' save failed: ${sErrorMessage}`, null, COMPONENT_NAME);
517
+ oSaveDeferred.reject(new LaunchpadError(sErrorMessage, oErrorInfo));
518
+ }
519
+ );
520
+ } else {
521
+ oSaveDeferred.resolve();
522
+ }
523
+ },
524
+ // fnFailure
525
+ (mErrorMessages, mErrorInfo) => {
526
+ const sFirstFailedBag = Object.keys(mErrorMessages)[0];
527
+
528
+ const oError = new LaunchpadError(`Bag save failed: ${mErrorMessages[sFirstFailedBag]}`, {
529
+ info: mErrorInfo[sFirstFailedBag],
530
+ otherMessages: mErrorMessages,
531
+ otherInfo: mErrorInfo
532
+ });
533
+ Log.error("Bag save failed", oError, COMPONENT_NAME);
534
+ oSaveDeferred.reject(oError);
535
+ }
536
+ );
537
+
538
+ tileNavigationActionsBag.save(
539
+ // success handler
540
+ () => {
541
+ Log.debug("property bag 'navigationProperties' saved successfully");
542
+ },
543
+ // fnFailure
544
+ (mErrorMessages, mErrorInfo) => {
545
+ const sFirstFailedBag = Object.keys(mErrorMessages)[0];
546
+
547
+ const oError = new LaunchpadError(`Bag save failed: ${mErrorMessages[sFirstFailedBag]}`, {
548
+ info: mErrorInfo[sFirstFailedBag],
549
+ otherMessages: mErrorMessages,
550
+ otherInfo: mErrorInfo
551
+ });
552
+ Log.error("Bag save failed", oError, COMPONENT_NAME);
553
+ oSaveDeferred.reject(oError);
554
+ }
555
+ );
556
+ },
557
+ // error handler
558
+ (sErrorMessage, oErrorInfo) => {
559
+ Log.error(`property bag 'tileProperties' save failed: ${sErrorMessage}`, null, COMPONENT_NAME);
560
+ oSaveDeferred.reject(new LaunchpadError(sErrorMessage, oErrorInfo));
561
+ }
562
+ );
563
+
564
+ return oSaveDeferred.promise;
565
+ },
566
+
567
+ successHandlerFn: function (oResult) {
568
+ const oView = this.getView();
569
+ const oModel = oView.getModel();
570
+ const oConfig = oModel.getProperty("/config");
571
+ const sNavigationTargetUrl = oModel.getProperty("/config/navigation_target_url");
572
+ let iRefreshInterval = oModel.getProperty("/config/service_refresh_interval");
573
+ const sServiceUrl = oModel.getProperty("/config/service_url");
574
+ const oViewData = oView.getViewData();
575
+ const oTileApi = oViewData.chip;
576
+ const sSystem = oTileApi.url.getApplicationSystem();
577
+
578
+ if (oViewData.properties && oViewData.properties.info) {
579
+ if (typeof oResult === "object") {
580
+ oResult.info = oViewData.properties.info;
581
+ }
582
+ }
583
+
584
+ const oDataToDisplay = tileUtils.getDataToDisplay(oConfig, oResult);
585
+
586
+ // set data to display
587
+ oModel.setProperty("/data", oDataToDisplay);
588
+
589
+ // Update this.navigationTargetUrl in case that oConfig.navigation_target_url was changed
590
+ // BCP Incident: 1670570695
591
+ if (this.sConfigNavigationTargetUrlOld !== sNavigationTargetUrl) {
592
+ this.navigationTargetUrl = this.constructTargetUrlWithSapSystem(sNavigationTargetUrl, sSystem);
593
+ this.sConfigNavigationTargetUrlOld = this.navigationTargetUrl;
594
+ }
595
+
596
+ // rewrite target URL
597
+ oModel.setProperty("/nav/navigation_target_url", tileUtils.addParamsToUrl(
598
+ this.navigationTargetUrl,
599
+ oDataToDisplay
600
+ ));
601
+
602
+ if (iRefreshInterval > 0) {
603
+ iRefreshInterval = Math.max(iRefreshInterval, this.REFRESH_INTERVAL_MIN);
604
+
605
+ Log.info(`Wait ${iRefreshInterval} seconds before calling ${sServiceUrl} again`, null, COMPONENT_NAME);
606
+ this.refeshAfterInterval(iRefreshInterval);
607
+ }
608
+ },
609
+
610
+ // error handler
611
+ errorHandlerFn: function (oMessage, bIsWarning) {
612
+ const oView = this.getView();
613
+ const oModel = oView.getModel();
614
+ const sServiceUrl = oModel.getProperty("/config/service_url");
615
+ let sMessage = oMessage && oMessage.message ? oMessage.message : oMessage;
616
+
617
+ if (oMessage.statusText === "Abort" || oMessage.aborted === true) {
618
+ Log.info(`Data request from service ${sServiceUrl} was aborted`, null, COMPONENT_NAME);
619
+ } else {
620
+ if (oMessage.response) {
621
+ sMessage += ` - ${oMessage.response.statusCode} ${
622
+ oMessage.response.statusText}`;
623
+ }
624
+ const fnLogFunction = bIsWarning ? Log.warning : Log.error;
625
+
626
+ // Display error in English only
627
+ fnLogFunction(`Failed to update data via service\n service URL: ${sServiceUrl}\n ${sMessage}`, null, COMPONENT_NAME);
628
+
629
+ this._setTileIntoErrorState();
630
+ }
631
+ },
632
+
633
+ _setTileIntoErrorState: function () {
634
+ const oResourceBundle = tileUtils.getResourceBundle();
635
+ const oModel = this.getView().getModel();
636
+ const oConfig = oModel.getProperty("/config");
637
+
638
+ oModel.setProperty("/data",
639
+ tileUtils.getDataToDisplay(oConfig, {
640
+ number: "???",
641
+ info: oResourceBundle.getText("dynamic_data.error"),
642
+ infoState: "Critical"
643
+ })
644
+ );
645
+ },
646
+
647
+ // configuration cancel handler
648
+ onCancelConfiguration: function (oConfigurationView/* , successHandler, errorHandle */) {
649
+ // reload old configuration and display
650
+ const oViewData = oConfigurationView.getViewData();
651
+ const oModel = oConfigurationView.getModel();
652
+ // tile model placed into configuration model by getConfigurationUi
653
+ const oTileModel = oModel.getProperty("/tileModel");
654
+ const oTileApi = oViewData.chip;
655
+ const oCurrentConfig = tileUtils.getAppLauncherConfig(oTileApi, false, false);
656
+
657
+ oModel.setData({ config: oCurrentConfig, tileModel: oTileModel }, false);
658
+ },
659
+
660
+ loadData: function () {
661
+ const oView = this.getView();
662
+ const oTileApi = oView.getViewData().chip;
663
+ const oModel = oView.getModel();
664
+ let sUrl = oModel.getProperty("/config/service_url");
665
+
666
+ if (/;o=([;/?]|$)/.test(sUrl)) { // URL has placeholder segment parameter ;o=
667
+ sUrl = oTileApi.url.addSystemToServiceUrl(sUrl);
668
+ }
669
+
670
+ if (!sUrl) {
671
+ Log.error("No service URL given!", COMPONENT_NAME);
672
+ this._setTileIntoErrorState();
673
+ return;
674
+ }
675
+
676
+ // keep request until url changes
677
+ if (!this.oDataRequest || this.oDataRequest.sUrl !== sUrl) {
678
+ if (this.oDataRequest) {
679
+ this.oDataRequest.destroy();
680
+ }
681
+ this.sRequestUrl = sUrl;
682
+ const oOptions = {
683
+ dataSource: oModel.getProperty("/config/data_source")
684
+ };
685
+ this.oDataRequest = new DynamicTileRequest(sUrl, this.successHandlerFn.bind(this), this.errorHandlerFn.bind(this), "", oOptions);
686
+ } else if (this.oDataRequest) {
687
+ this.oDataRequest.refresh();
688
+ }
689
+ },
690
+
691
+ refreshTile: function () {
692
+ const oView = this.getView();
693
+ const oViewData = oView.getViewData();
694
+ const isVisible = oViewData.chip.visible.isVisible();
695
+ if (isVisible && this.bNeedsRefresh) {
696
+ this.bNeedsRefresh = false;
697
+ this.loadData();
698
+ }
699
+ },
700
+
701
+ refeshAfterInterval: function (iRefreshInterval) {
702
+ this.iNrOfTimerRunning++;
703
+ this.timer = window.setTimeout(() => {
704
+ this.iNrOfTimerRunning--;
705
+ if (this.iNrOfTimerRunning === 0) {
706
+ this.bNeedsRefresh = true;
707
+ this.refreshTile();
708
+ }
709
+ }, ushellUtils.sanitizeTimeoutDelay(iRefreshInterval * 1000));
710
+ },
711
+
712
+ refreshHandler: function () {
713
+ this.bNeedsRefresh = true;
714
+ this.refreshTile();
715
+ },
716
+
717
+ visibleHandler: function (isVisible) {
718
+ if (isVisible) {
719
+ this.refreshTile();
720
+ } else {
721
+ this.stopRequests();
722
+ }
723
+ },
724
+
725
+ formatters: {
726
+ leanURL: WindowUtils.getLeanURL.bind(WindowUtils)
727
+ }
728
+ });
729
+ });