@sapui5/sap.ushell 1.119.3 → 1.120.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 (392) hide show
  1. package/package.json +1 -1
  2. package/src/main/js/sap/ushell/.library +3 -3
  3. package/src/main/js/sap/ushell/Container.js +272 -41
  4. package/src/main/js/sap/ushell/Fiori20Adapter.js +1 -1
  5. package/src/main/js/sap/ushell/Fiori20AdapterTest.js +3 -2
  6. package/src/main/js/sap/ushell/NWBCInterface.js +1 -1
  7. package/src/main/js/sap/ushell/SessionHandler.js +11 -6
  8. package/src/main/js/sap/ushell/TechnicalParameters.js +1 -1
  9. package/src/main/js/sap/ushell/URLTemplateProcessor.js +1 -1
  10. package/src/main/js/sap/ushell/Ui5NativeServiceFactory.js +1 -1
  11. package/src/main/js/sap/ushell/Ui5ServiceFactory.js +1 -1
  12. package/src/main/js/sap/ushell/User.js +26 -35
  13. package/src/main/js/sap/ushell/_ApplicationType/urlTemplateResolution.js +1 -1
  14. package/src/main/js/sap/ushell/_URLTemplateProcessor/DefinitionParameterSetBuilder.js +1 -1
  15. package/src/main/js/sap/ushell/_URLTemplateProcessor/DependencyGraph.js +1 -1
  16. package/src/main/js/sap/ushell/_URLTemplateProcessor/Functions.js +1 -1
  17. package/src/main/js/sap/ushell/_URLTemplateProcessor/Resolvers.js +1 -1
  18. package/src/main/js/sap/ushell/_URLTemplateProcessor/TemplateParameterParser.js +1 -1
  19. package/src/main/js/sap/ushell/_URLTemplateProcessor/utils.js +1 -1
  20. package/src/main/js/sap/ushell/adapters/cdm/ClientSideTargetResolutionAdapter.js +1 -1
  21. package/src/main/js/sap/ushell/adapters/cdm/CommonDataModelAdapter.js +15 -11
  22. package/src/main/js/sap/ushell/adapters/cdm/ConfigurationDefaultsAdapter.js +1 -1
  23. package/src/main/js/sap/ushell/adapters/cdm/ContainerAdapter.js +1 -1
  24. package/src/main/js/sap/ushell/adapters/cdm/LaunchPageAdapter.js +1 -1
  25. package/src/main/js/sap/ushell/adapters/cdm/PagesCommonDataModelAdapter.js +16 -11
  26. package/src/main/js/sap/ushell/adapters/cdm/PersonalizationAdapter.js +1 -1
  27. package/src/main/js/sap/ushell/adapters/cdm/PersonalizationV2Adapter.js +18 -0
  28. package/src/main/js/sap/ushell/adapters/cdm/Ui5ComponentLoaderAdapter.js +1 -1
  29. package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/modifyHome.js +1 -1
  30. package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/readCatalogs.js +1 -1
  31. package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/readHome.js +1 -1
  32. package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/uri.transform.js +1 -1
  33. package/src/main/js/sap/ushell/adapters/cdm/util/AppForInbound.js +1 -1
  34. package/src/main/js/sap/ushell/adapters/cdm/util/cdmSiteUtils.js +1 -1
  35. package/src/main/js/sap/ushell/adapters/cdm/v3/AdapterBase.js +1 -1
  36. package/src/main/js/sap/ushell/adapters/cdm/v3/LaunchPageAdapter.js +1 -1
  37. package/src/main/js/sap/ushell/adapters/cdm/v3/StaticGroupsAdapter.js +1 -1
  38. package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readApplications.js +1 -1
  39. package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readCatalogs.js +1 -1
  40. package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readHome.js +1 -1
  41. package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readPages.js +1 -1
  42. package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readUtils.js +1 -1
  43. package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readVisualizations.js +1 -1
  44. package/src/main/js/sap/ushell/adapters/cep/NavTargetResolutionAdapter.js +1 -1
  45. package/src/main/js/sap/ushell/adapters/cep/SearchCEPAdapter.js +1 -1
  46. package/src/main/js/sap/ushell/adapters/cflp/UserDefaultParameterPersistenceAdapter.js +1 -1
  47. package/src/main/js/sap/ushell/adapters/local/AdapterContainer.js +1 -1
  48. package/src/main/js/sap/ushell/adapters/local/AppStateAdapter.js +24 -18
  49. package/src/main/js/sap/ushell/adapters/local/ClientSideTargetResolutionAdapter.js +1 -1
  50. package/src/main/js/sap/ushell/adapters/local/ContainerAdapter.js +1 -1
  51. package/src/main/js/sap/ushell/adapters/local/LaunchPageAdapter.js +1 -1
  52. package/src/main/js/sap/ushell/adapters/local/MenuAdapter.js +4 -7
  53. package/src/main/js/sap/ushell/adapters/local/NavTargetResolutionAdapter.js +17 -22
  54. package/src/main/js/sap/ushell/adapters/local/PageBuildingAdapter.js +1 -1
  55. package/src/main/js/sap/ushell/adapters/local/PagePersistenceAdapter.js +1 -1
  56. package/src/main/js/sap/ushell/adapters/local/PersonalizationAdapter.js +1 -1
  57. package/src/main/js/sap/ushell/adapters/local/PersonalizationV2Adapter.js +19 -0
  58. package/src/main/js/sap/ushell/adapters/local/SearchAdapter.js +1 -1
  59. package/src/main/js/sap/ushell/adapters/local/SearchCEPAdapter.js +1 -1
  60. package/src/main/js/sap/ushell/adapters/local/SupportTicketAdapter.js +1 -1
  61. package/src/main/js/sap/ushell/adapters/local/Ui5ComponentLoaderAdapter.js +1 -1
  62. package/src/main/js/sap/ushell/adapters/local/UserDefaultParameterPersistenceAdapter.js +11 -7
  63. package/src/main/js/sap/ushell/adapters/local/UserInfoAdapter.js +8 -8
  64. package/src/main/js/sap/ushell/api/RTA.js +47 -0
  65. package/src/main/js/sap/ushell/appRuntime/ui5/AppRuntime.js +12 -5
  66. package/src/main/js/sap/ushell/appRuntime/ui5/AppRuntimeContext.js +2 -2
  67. package/src/main/js/sap/ushell/appRuntime/ui5/services/adapters/Ui5ComponentLoaderAdapter.js +1 -1
  68. package/src/main/js/sap/ushell/bootstrap/SchedulingAgent.js +2 -2
  69. package/src/main/js/sap/ushell/bootstrap/_SchedulingAgent/logger.js +1 -1
  70. package/src/main/js/sap/ushell/bootstrap/_SchedulingAgent/state.js +1 -1
  71. package/src/main/js/sap/ushell/bootstrap/cdm/cdm-def-dev.js +6 -3
  72. package/src/main/js/sap/ushell/bootstrap/common/common.configure.ui5datetimeformat.js +1 -1
  73. package/src/main/js/sap/ushell/bootstrap/common/common.configure.ushell.js +3 -0
  74. package/src/main/js/sap/ushell/bootstrap/common/common.load.launchpad.js +1 -1
  75. package/src/main/js/sap/ushell/bootstrap/common/common.util.js +34 -2
  76. package/src/main/js/sap/ushell/bootstrap/sandbox2.js +7 -2
  77. package/src/main/js/sap/ushell/components/ComponentKeysHandler.js +1 -1
  78. package/src/main/js/sap/ushell/components/HomepageManager.js +5 -5
  79. package/src/main/js/sap/ushell/components/SharedComponentUtils.js +7 -10
  80. package/src/main/js/sap/ushell/components/_HeaderManager/ShellHeader.controller.js +3 -3
  81. package/src/main/js/sap/ushell/components/_HomepageManager/DashboardLoadingManager.js +5 -0
  82. package/src/main/js/sap/ushell/components/_HomepageManager/PagingManager.js +5 -0
  83. package/src/main/js/sap/ushell/components/_HomepageManager/PersistentPageOperationAdapter.js +5 -0
  84. package/src/main/js/sap/ushell/components/_HomepageManager/TransientPageOperationAdapter.js +5 -0
  85. package/src/main/js/sap/ushell/components/appfinder/AppFinderView.js +1 -1
  86. package/src/main/js/sap/ushell/components/appfinder/CatalogView.js +1 -1
  87. package/src/main/js/sap/ushell/components/appfinder/EasyAccess.controller.js +3 -3
  88. package/src/main/js/sap/ushell/components/appfinder/EasyAccessView.js +0 -8
  89. package/src/main/js/sap/ushell/components/appfinder/HierarchyApps.controller.js +4 -4
  90. package/src/main/js/sap/ushell/components/appfinder/HierarchyFolders.controller.js +18 -16
  91. package/src/main/js/sap/ushell/components/appfinder/manifest.json +2 -2
  92. package/src/main/js/sap/ushell/components/applicationIntegration/AppLifeCycle.js +2 -2
  93. package/src/main/js/sap/ushell/components/applicationIntegration/application/Application.js +1 -1
  94. package/src/main/js/sap/ushell/components/applicationIntegration/application/BlueBoxHandler.js +1 -1
  95. package/src/main/js/sap/ushell/components/applicationIntegration/application/PostMessageAPI.js +2 -2
  96. package/src/main/js/sap/ushell/components/applicationIntegration/configuration/AppMeta.js +1 -1
  97. package/src/main/js/sap/ushell/components/applicationIntegration/elements/model.js +1 -1
  98. package/src/main/js/sap/ushell/components/applicationIntegration/relatedServices/RelatedServices.js +1 -1
  99. package/src/main/js/sap/ushell/components/applicationIntegration/relatedShellElements/RelatedShellElements.js +1 -1
  100. package/src/main/js/sap/ushell/components/cards/Card.controller.js +2 -2
  101. package/src/main/js/sap/ushell/components/container/ApplicationContainer.js +92 -71
  102. package/src/main/js/sap/ushell/components/contentFinder/Component.js +1 -1
  103. package/src/main/js/sap/ushell/components/contentFinder/controller/AppSearch.controller.js +1 -1
  104. package/src/main/js/sap/ushell/components/contentFinder/controller/ContentFinderDialog.controller.js +1 -1
  105. package/src/main/js/sap/ushell/components/contentFinder/controller/WidgetGallery.controller.js +1 -1
  106. package/src/main/js/sap/ushell/components/contentFinder/manifest.json +1 -1
  107. package/src/main/js/sap/ushell/components/contentFinder/model/formatter.js +4 -4
  108. package/src/main/js/sap/ushell/components/factsheet/Component.js +1 -1
  109. package/src/main/js/sap/ushell/components/homeApp/error/manifest.json +1 -1
  110. package/src/main/js/sap/ushell/components/homepage/ActionMode.js +1 -1
  111. package/src/main/js/sap/ushell/components/homepage/DashboardContent.view.js +1 -1
  112. package/src/main/js/sap/ushell/components/homepage/DashboardGroupsBox.js +1 -1
  113. package/src/main/js/sap/ushell/components/homepage/DashboardUIActions.js +1 -1
  114. package/src/main/js/sap/ushell/components/homepage/manifest.json +2 -2
  115. package/src/main/js/sap/ushell/components/pages/ActionMode.js +5 -5
  116. package/src/main/js/sap/ushell/components/pages/Component.js +1 -1
  117. package/src/main/js/sap/ushell/components/pages/MyHomeImport.js +1 -1
  118. package/src/main/js/sap/ushell/components/pages/StateManager.js +37 -24
  119. package/src/main/js/sap/ushell/components/pages/controller/ImportDialog.controller.js +1 -1
  120. package/src/main/js/sap/ushell/components/pages/controller/PageRuntime.controller.js +1 -1
  121. package/src/main/js/sap/ushell/components/pages/manifest.json +2 -2
  122. package/src/main/js/sap/ushell/components/runtimeSwitcher/controller/RuntimeSwitcher.controller.js +7 -4
  123. package/src/main/js/sap/ushell/components/runtimeSwitcher/manifest.json +1 -1
  124. package/src/main/js/sap/ushell/components/shell/MenuBar/controller/MenuBar.controller.js +6 -7
  125. package/src/main/js/sap/ushell/components/shell/MenuBar/manifest.json +2 -2
  126. package/src/main/js/sap/ushell/components/shell/NavigationBarMenu/controller/NavigationBarMenu.controller.js +39 -13
  127. package/src/main/js/sap/ushell/components/shell/NavigationBarMenu/manifest.json +3 -3
  128. package/src/main/js/sap/ushell/components/shell/Notifications/Component.js +5 -5
  129. package/src/main/js/sap/ushell/components/shell/Notifications/Notifications.controller.js +25 -45
  130. package/src/main/js/sap/ushell/components/shell/PostLoadingHeaderEnhancement/Component.js +2 -2
  131. package/src/main/js/sap/ushell/components/shell/ProductSwitch/Component.js +1 -1
  132. package/src/main/js/sap/ushell/components/shell/Search/ESearch.js +1 -1
  133. package/src/main/js/sap/ushell/components/shell/Search/manifest.json +2 -2
  134. package/src/main/js/sap/ushell/components/shell/SearchCEP/Component.js +2 -2
  135. package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchCEP.controller.js +3 -3
  136. package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/FrequentActivityProvider.js +1 -1
  137. package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/RecentSearchProvider.js +1 -1
  138. package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/SearchProvider.js +1 -1
  139. package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/SearchServiceProvider.js +1 -1
  140. package/src/main/js/sap/ushell/components/shell/Settings/Component.js +4 -4
  141. package/src/main/js/sap/ushell/components/shell/Settings/ProfilingLoader.js +4 -0
  142. package/src/main/js/sap/ushell/components/shell/Settings/UserSettings.controller.js +4 -0
  143. package/src/main/js/sap/ushell/components/shell/Settings/UserSettings.view.xml +4 -3
  144. package/src/main/js/sap/ushell/components/shell/Settings/homepage/HomepageEntry.js +10 -13
  145. package/src/main/js/sap/ushell/components/shell/Settings/notifications/NotificationsSetting.controller.js +13 -22
  146. package/src/main/js/sap/ushell/components/shell/Settings/userAccount/UserAccountSelector.controller.js +2 -2
  147. package/src/main/js/sap/ushell/components/shell/Settings/userActivities/UserActivitiesSetting.controller.js +11 -14
  148. package/src/main/js/sap/ushell/components/shell/Settings/userDefaults/manifest.json +1 -1
  149. package/src/main/js/sap/ushell/components/shell/UserActionsMenu/Component.js +1 -1
  150. package/src/main/js/sap/ushell/components/shell/UserActionsMenu/UserActionsMenu.controller.js +2 -2
  151. package/src/main/js/sap/ushell/components/shell/UserImage/Component.js +2 -2
  152. package/src/main/js/sap/ushell/components/tiles/indicatorTileUtils/smartBusinessUtil.js +4 -6
  153. package/src/main/js/sap/ushell/components/visualizationOrganizer/Component.js +14 -18
  154. package/src/main/js/sap/ushell/components/workPageBuilder/Component.js +1 -1
  155. package/src/main/js/sap/ushell/components/workPageBuilder/controller/WorkPageBuilder.accessibility.js +1 -1
  156. package/src/main/js/sap/ushell/components/workPageBuilder/controller/WorkPageBuilder.controller.js +16 -12
  157. package/src/main/js/sap/ushell/components/workPageBuilder/controller/WorkPageHost.js +1 -1
  158. package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPage.js +1 -1
  159. package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageButton.js +1 -1
  160. package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageCell.js +1 -1
  161. package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageColumn.js +1 -1
  162. package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageColumnResizer.js +1 -1
  163. package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageRow.js +1 -1
  164. package/src/main/js/sap/ushell/components/workPageBuilder/manifest.json +1 -1
  165. package/src/main/js/sap/ushell/components/workPageBuilder/view/WorkPageBuilder.view.xml +3 -3
  166. package/src/main/js/sap/ushell/components/workPageRuntime/Component.js +1 -1
  167. package/src/main/js/sap/ushell/components/workPageRuntime/controller/WorkPageRuntime.controller.js +1 -2
  168. package/src/main/js/sap/ushell/components/workPageRuntime/manifest.json +1 -1
  169. package/src/main/js/sap/ushell/components/workPageRuntime/services/NavigationResolver.js +1 -1
  170. package/src/main/js/sap/ushell/components/workPageRuntime/services/WorkPage.js +1 -1
  171. package/src/main/js/sap/ushell/designtime/ApplicationContainer.designtime.js +1 -1
  172. package/src/main/js/sap/ushell/library.js +1 -1
  173. package/src/main/js/sap/ushell/navigationMode.js +1 -1
  174. package/src/main/js/sap/ushell/performance/ShellAnalytics.js +1 -1
  175. package/src/main/js/sap/ushell/performance/StatisticalRecord.js +1 -1
  176. package/src/main/js/sap/ushell/plugins/appwarmup/Component.js +1 -1
  177. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/AccessKeysHandler.js +1 -1
  178. package/src/main/js/sap/ushell/renderer/History.js +84 -0
  179. package/src/main/js/sap/ushell/renderer/LogonFrameProvider.js +96 -0
  180. package/src/main/js/sap/ushell/renderer/Renderer.js +2851 -0
  181. package/src/main/js/sap/ushell/renderer/Shell.controller.js +3155 -0
  182. package/src/main/js/sap/ushell/{renderers/fiori2/ShellAsync.view.js → renderer/Shell.view.js} +29 -18
  183. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/ShellLayout.js +3 -3
  184. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/allMyApps/AllMyApps.controller.js +4 -4
  185. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/allMyApps/AllMyApps.view.xml +1 -1
  186. package/src/main/js/sap/ushell/renderer/allMyApps/AllMyAppsKeyboardHandler.js +108 -0
  187. package/src/main/js/sap/ushell/renderer/allMyApps/AllMyAppsManager.js +453 -0
  188. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources.properties +4 -0
  189. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/Component.js +3 -3
  190. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/controller/CEPSearchApp.controller.js +1 -1
  191. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/controller/SearchApp.controller.js +1 -1
  192. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/manifest.json +2 -2
  193. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/view/CEPSearchApp.view.js +2 -2
  194. package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/view/SearchApp.view.js +2 -2
  195. package/src/main/js/sap/ushell/renderers/fiori2/History.js +7 -68
  196. package/src/main/js/sap/ushell/renderers/fiori2/LogonFrameProvider.js +9 -79
  197. package/src/main/js/sap/ushell/renderers/fiori2/Renderer.js +101 -1882
  198. package/src/main/js/sap/ushell/renderers/fiori2/RendererExtensions.js +2 -3
  199. package/src/main/js/sap/ushell/renderers/fiori2/Shell.controller.js +8 -3130
  200. package/src/main/js/sap/ushell/renderers/fiori2/Shell.view.js +7 -7
  201. package/src/main/js/sap/ushell/renderers/fiori2/allMyApps/AllMyAppsKeyboardHandler.js +7 -92
  202. package/src/main/js/sap/ushell/renderers/fiori2/allMyApps/AllMyAppsManager.js +8 -438
  203. package/src/main/js/sap/ushell/resources.js +1 -1
  204. package/src/main/js/sap/ushell/services/AllMyApps.js +16 -7
  205. package/src/main/js/sap/ushell/services/AppConfiguration.js +12 -0
  206. package/src/main/js/sap/ushell/services/AppLifeCycle.js +11 -14
  207. package/src/main/js/sap/ushell/services/AppState.js +12 -8
  208. package/src/main/js/sap/ushell/services/Bookmark.js +15 -13
  209. package/src/main/js/sap/ushell/services/BookmarkV2.js +919 -0
  210. package/src/main/js/sap/ushell/services/ClientSideTargetResolution.js +229 -241
  211. package/src/main/js/sap/ushell/services/CommonDataModel.js +14 -4
  212. package/src/main/js/sap/ushell/services/Configuration.js +12 -11
  213. package/src/main/js/sap/ushell/services/ConfigurationDefaults.js +13 -10
  214. package/src/main/js/sap/ushell/services/Container.js +1 -1
  215. package/src/main/js/sap/ushell/services/ContentExtensionAdapterFactory.js +1 -1
  216. package/src/main/js/sap/ushell/services/CrossApplicationNavigation.js +8 -6
  217. package/src/main/js/sap/ushell/services/DarkModeSupport.js +16 -10
  218. package/src/main/js/sap/ushell/services/EndUserFeedback.js +1 -1
  219. package/src/main/js/sap/ushell/services/Extension/FloatingContainer.js +103 -0
  220. package/src/main/js/sap/ushell/services/Extension/Footer.js +61 -0
  221. package/src/main/js/sap/ushell/services/Extension/Header.js +193 -0
  222. package/src/main/js/sap/ushell/services/Extension/Item.js +195 -0
  223. package/src/main/js/sap/ushell/services/Extension/SidePane.js +155 -0
  224. package/src/main/js/sap/ushell/services/Extension/ToolArea.js +152 -0
  225. package/src/main/js/sap/ushell/services/Extension.js +381 -0
  226. package/src/main/js/sap/ushell/services/LaunchPage.js +1 -1
  227. package/src/main/js/sap/ushell/services/Menu.js +48 -59
  228. package/src/main/js/sap/ushell/services/Message.js +15 -14
  229. package/src/main/js/sap/ushell/services/MessageBroker.js +12 -12
  230. package/src/main/js/sap/ushell/services/NavTargetResolution.js +48 -70
  231. package/src/main/js/sap/ushell/services/Navigation/utils.js +565 -0
  232. package/src/main/js/sap/ushell/services/Navigation.js +152 -139
  233. package/src/main/js/sap/ushell/services/NavigationDataProvider.js +11 -8
  234. package/src/main/js/sap/ushell/services/Notifications.js +118 -1523
  235. package/src/main/js/sap/ushell/services/NotificationsV2.js +1872 -0
  236. package/src/main/js/sap/ushell/services/PageBuilding.js +11 -8
  237. package/src/main/js/sap/ushell/services/PagePersistence.js +11 -8
  238. package/src/main/js/sap/ushell/services/PageReferencing.js +11 -8
  239. package/src/main/js/sap/ushell/services/Pages.js +11 -15
  240. package/src/main/js/sap/ushell/services/Personalization.js +5 -3
  241. package/src/main/js/sap/ushell/services/PersonalizationV2/ContextContainer.js +410 -0
  242. package/src/main/js/sap/ushell/services/PersonalizationV2/Personalizer.js +109 -0
  243. package/src/main/js/sap/ushell/services/PersonalizationV2/TransientPersonalizer.js +57 -0
  244. package/src/main/js/sap/ushell/services/PersonalizationV2/Variant.js +180 -0
  245. package/src/main/js/sap/ushell/services/PersonalizationV2/VariantSet.js +296 -0
  246. package/src/main/js/sap/ushell/services/PersonalizationV2/VariantSetAdapter.js +125 -0
  247. package/src/main/js/sap/ushell/services/PersonalizationV2/WindowAdapter.js +71 -0
  248. package/src/main/js/sap/ushell/services/PersonalizationV2/WindowAdapterContainer.js +172 -0
  249. package/src/main/js/sap/ushell/services/PersonalizationV2/constants.js +23 -0
  250. package/src/main/js/sap/ushell/services/PersonalizationV2/constants.private.js +18 -0
  251. package/src/main/js/sap/ushell/services/PersonalizationV2/utils.js +233 -0
  252. package/src/main/js/sap/ushell/services/PersonalizationV2.js +641 -0
  253. package/src/main/js/sap/ushell/services/PluginManager.js +47 -55
  254. package/src/main/js/sap/ushell/services/ReferenceResolver.js +61 -54
  255. package/src/main/js/sap/ushell/services/Search.js +15 -2
  256. package/src/main/js/sap/ushell/services/SearchCEP.js +40 -44
  257. package/src/main/js/sap/ushell/services/SearchableContent.js +9 -9
  258. package/src/main/js/sap/ushell/services/ShellNavigation.js +14 -13
  259. package/src/main/js/sap/ushell/services/SmartNavigation.js +1 -1
  260. package/src/main/js/sap/ushell/services/SpaceContent.js +9 -10
  261. package/src/main/js/sap/ushell/services/SupportTicket.js +14 -14
  262. package/src/main/js/sap/ushell/services/UITracer.js +31 -35
  263. package/src/main/js/sap/ushell/services/URLParsing.js +9 -11
  264. package/src/main/js/sap/ushell/services/URLShortening.js +1 -1
  265. package/src/main/js/sap/ushell/services/URLTemplate.js +14 -13
  266. package/src/main/js/sap/ushell/services/Ui5ComponentLoader.js +29 -26
  267. package/src/main/js/sap/ushell/services/UsageAnalytics.js +6 -0
  268. package/src/main/js/sap/ushell/services/UserDefaultParameterPersistence.js +11 -7
  269. package/src/main/js/sap/ushell/services/UserDefaultParameters.js +20 -26
  270. package/src/main/js/sap/ushell/services/UserInfo.js +44 -23
  271. package/src/main/js/sap/ushell/services/UserRecents.js +13 -5
  272. package/src/main/js/sap/ushell/services/VisualizationDataProvider.js +12 -9
  273. package/src/main/js/sap/ushell/services/VisualizationInstantiation.js +10 -8
  274. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/Formatter.js +1 -1
  275. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/InboundIndex.js +1 -1
  276. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/InboundProvider.js +1 -1
  277. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/PrelaunchOperations.js +1 -1
  278. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/Search.js +1 -1
  279. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/StagedLogger.js +1 -1
  280. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/SystemContext.js +1 -1
  281. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/Utils.js +3 -4
  282. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/VirtualInbounds.js +4 -4
  283. package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/XAppStateProcessing.js +1 -1
  284. package/src/main/js/sap/ushell/services/_CommonDataModel/SiteConverter.js +1 -1
  285. package/src/main/js/sap/ushell/services/_ContentExtensionAdapterFactory/ContentExtensionAdapterConfig.js +1 -1
  286. package/src/main/js/sap/ushell/services/_ContentExtensionAdapterFactory/FeaturedGroupConfig.js +1 -1
  287. package/src/main/js/sap/ushell/services/_CrossApplicationNavigation/utils.js +2 -1
  288. package/src/main/js/sap/ushell/services/_MessageBroker/MessageBrokerEngine.js +1 -1
  289. package/src/main/js/sap/ushell/services/_PageReferencing/PageReferencer.js +1 -1
  290. package/src/main/js/sap/ushell/services/_Personalization/ContextContainer.js +6 -0
  291. package/src/main/js/sap/ushell/services/_Personalization/PersonalizationContainer.js +5 -1
  292. package/src/main/js/sap/ushell/services/_Personalization/PersonalizationContainerVariant.js +13 -9
  293. package/src/main/js/sap/ushell/services/_Personalization/PersonalizationContainerVariantSet.js +17 -13
  294. package/src/main/js/sap/ushell/services/_Personalization/Personalizer.js +5 -0
  295. package/src/main/js/sap/ushell/services/_Personalization/TransientPersonalizer.js +5 -1
  296. package/src/main/js/sap/ushell/services/_Personalization/Variant.js +4 -0
  297. package/src/main/js/sap/ushell/services/_Personalization/VariantSet.js +17 -9
  298. package/src/main/js/sap/ushell/services/_Personalization/VariantSetAdapter.js +4 -6
  299. package/src/main/js/sap/ushell/services/_Personalization/WindowAdapter.js +5 -44
  300. package/src/main/js/sap/ushell/services/_Personalization/WindowAdapterContainer.js +5 -101
  301. package/src/main/js/sap/ushell/services/_Personalization/constants.js +3 -0
  302. package/src/main/js/sap/ushell/services/_Personalization/constants.private.js +3 -0
  303. package/src/main/js/sap/ushell/services/_Personalization/utils.js +3 -0
  304. package/src/main/js/sap/ushell/services/_PluginManager/Extensions.js +1 -1
  305. package/src/main/js/sap/ushell/services/_PluginManager/HeaderExtensions.js +1 -1
  306. package/src/main/js/sap/ushell/services/_PluginManager/MenuExtensions.js +1 -1
  307. package/src/main/js/sap/ushell/services/_Ui5ComponentLoader/utils.js +29 -5
  308. package/src/main/js/sap/ushell/services/_UserRecents/UserRecentsBase.js +19 -27
  309. package/src/main/js/sap/ushell/services/_VisualizationInstantiation/VizInstance.js +4 -0
  310. package/src/main/js/sap/ushell/services/_VisualizationInstantiation/VizInstanceAbap.js +3 -0
  311. package/src/main/js/sap/ushell/services/_VisualizationInstantiation/VizInstanceLink.js +1 -1
  312. package/src/main/js/sap/ushell/services/personalization/VariantSetAdapter.js +13 -15
  313. package/src/main/js/sap/ushell/support/plugins/flpConfig/FlpConfigurationPlugin.js +1 -1
  314. package/src/main/js/sap/ushell/themes/sap_horizon/ShellAppTitle.less +4 -4
  315. package/src/main/js/sap/ushell/themes/sap_horizon_dark/ShellAppTitle.less +4 -4
  316. package/src/main/js/sap/ushell/themes/sap_horizon_hcb/ShellAppTitle.less +2 -2
  317. package/src/main/js/sap/ushell/themes/sap_horizon_hcw/ShellAppTitle.less +2 -2
  318. package/src/main/js/sap/ushell/ui/AppContainer.js +2 -2
  319. package/src/main/js/sap/ushell/ui/ContentNodeSelector.js +2 -2
  320. package/src/main/js/sap/ushell/ui/ShellHeader.js +2 -2
  321. package/src/main/js/sap/ushell/ui/cards/RecentActivitiesExtension.js +1 -1
  322. package/src/main/js/sap/ushell/ui/footerbar/AddBookmarkButton.js +8 -12
  323. package/src/main/js/sap/ushell/ui/launchpad/ExtendedChangeDetection.js +1 -1
  324. package/src/main/js/sap/ushell/ui/launchpad/Page.js +1 -1
  325. package/src/main/js/sap/ushell/ui/launchpad/Section.js +21 -8
  326. package/src/main/js/sap/ushell/ui/launchpad/TileState.js +0 -1
  327. package/src/main/js/sap/ushell/ui/launchpad/section/CompactArea.js +1 -1
  328. package/src/main/js/sap/ushell/ui/shell/ShellAppTitle.js +1 -1
  329. package/src/main/js/sap/ushell/ui/shell/ShellHeadItem.js +1 -1
  330. package/src/main/js/sap/ushell/ui/shell/SysInfoBar.js +1 -1
  331. package/src/main/js/sap/ushell/ui/shell/ToolAreaItem.js +1 -1
  332. package/src/main/js/sap/ushell/ui/utils.js +1 -1
  333. package/src/main/js/sap/ushell/ui5service/ShellUIService.js +1 -1
  334. package/src/main/js/sap/ushell/ui5service/UserStatus.js +1 -1
  335. package/src/main/js/sap/ushell/ui5service/_ShellUIService/shelluiservice.class.factory.js +14 -26
  336. package/src/main/js/sap/ushell/utils/Deferred.js +88 -0
  337. package/src/main/js/sap/ushell/utils/UrlShortening.js +1 -1
  338. package/src/main/js/sap/ushell/utils/WindowUtils.js +8 -8
  339. package/src/main/js/sap/ushell/utils.js +31 -67
  340. package/src/test/js/sap/ushell/bootstrap/sandbox.js +7 -2
  341. package/ui5.yaml +8 -2
  342. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/HeadEndItemsOverflowPopover.fragment.xml +0 -0
  343. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ar.properties +0 -0
  344. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_bg.properties +0 -0
  345. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ca.properties +0 -0
  346. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_cs.properties +0 -0
  347. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_cy.properties +0 -0
  348. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_da.properties +0 -0
  349. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_de.properties +0 -0
  350. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_el.properties +0 -0
  351. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en.properties +0 -0
  352. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_GB.properties +0 -0
  353. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_US_sappsd.properties +0 -0
  354. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_US_saprigi.properties +0 -0
  355. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_US_saptrc.properties +0 -0
  356. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_es.properties +0 -0
  357. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_es_MX.properties +0 -0
  358. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_et.properties +0 -0
  359. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_fi.properties +0 -0
  360. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_fr.properties +0 -0
  361. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_fr_CA.properties +0 -0
  362. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_hi.properties +0 -0
  363. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_hr.properties +0 -0
  364. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_hu.properties +0 -0
  365. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_id.properties +0 -0
  366. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_it.properties +0 -0
  367. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_iw.properties +0 -0
  368. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ja.properties +0 -0
  369. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_kk.properties +0 -0
  370. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ko.properties +0 -0
  371. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_lt.properties +0 -0
  372. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_lv.properties +0 -0
  373. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ms.properties +0 -0
  374. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_nl.properties +0 -0
  375. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_no.properties +0 -0
  376. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_pl.properties +0 -0
  377. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_pt.properties +0 -0
  378. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_pt_PT.properties +0 -0
  379. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ro.properties +0 -0
  380. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ru.properties +0 -0
  381. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sh.properties +0 -0
  382. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sk.properties +0 -0
  383. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sl.properties +0 -0
  384. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sv.properties +0 -0
  385. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_th.properties +0 -0
  386. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_tr.properties +0 -0
  387. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_uk.properties +0 -0
  388. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_vi.properties +0 -0
  389. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_zh_CN.properties +0 -0
  390. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_zh_TW.properties +0 -0
  391. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/util.js +0 -0
  392. /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/utils.js +0 -0
@@ -0,0 +1,1872 @@
1
+ // Copyright (c) 2009-2023 SAP SE, All Rights Reserved
2
+
3
+ sap.ui.define([
4
+ "sap/base/Log",
5
+ "sap/ushell/utils/Deferred",
6
+ "sap/ui/core/Core",
7
+ "sap/ui/core/Configuration",
8
+ "sap/ui/core/ws/SapPcpWebSocket",
9
+ "sap/ui/model/json/JSONModel",
10
+ "sap/ui/thirdparty/datajs",
11
+ "sap/ushell/utils"
12
+ ], function (
13
+ Log,
14
+ Deferred,
15
+ Core,
16
+ Configuration,
17
+ SapPcpWebSocket,
18
+ JSONModel,
19
+ OData,
20
+ ushellUtils
21
+ ) {
22
+ "use strict";
23
+
24
+ /*eslint consistent-this: ["error", "oNotificationsService"]*/
25
+
26
+ const S_DEFAULT_WEBSOCKET_URL = "/sap/bc/apc/iwngw/notification_push_apc";
27
+ const I_DEFAULT_POLLING_INTERVAL = 60; // Seconds
28
+
29
+ /**
30
+ * @alias sap.ushell.services.NotificationsV2
31
+ * @class
32
+ * @classdesc UShell service for fetching user notification data from the Notification center/service<br>
33
+ * and exposing them to the Unified Shell and Fiori applications UI controls.
34
+ *
35
+ * <b>Note:</b> To retrieve a valid instance of this service, it is necessary to call
36
+ * <code>sap.ushell.Container.getServiceAsync("NotificationsV2")</code>. For details, see
37
+ * {@link sap.ushell.services.Container#getServiceAsync}.
38
+ *
39
+ * In order to get user notifications, Unified Shell notification service issues OData requests<br>
40
+ * to the service defined by the configuration property <code>serviceUrl</code>,<br>
41
+ * for example: "/sap/opu/odata4/iwngw/notification/default/iwngw/notification_srv/0001"<br>.
42
+ *
43
+ * Unified Shell Notification service has several working modes, depending on the environment and the available resources:<br>
44
+ * PackagedApp mode: Fiori launchpad runs in the context of PackagedApp<br>
45
+ * FioriClient mode: Fiori launchpad runs in the context of FioriLaunchpad<br>
46
+ * WebSocket mode: Fiori launchpad runs in a browser, and WebSocket connection to the notifications provider is available<br>
47
+ * Polling mode: Fiori launchpad in runs in a browser, and WebSocket connection to the notifications provider is not available<br>
48
+ *
49
+ * The notification service exposes an API that includes:
50
+ * - Service enabling and initialization<br>
51
+ * - Registration of callback functions (by Shell/FLP controls) that will be called for every data update<br>.
52
+ * - Retrieval of notification data (e.g. notifications, number of unseen notifications)
53
+ * - Execution of a notification actions
54
+ * - Marking user notifications as seen
55
+ *
56
+ * @param {object} oContainerInterface The interface provided by the container
57
+ * @param {object} sParameters Not used in this service
58
+ * @param {object} oServiceConfiguration configuration
59
+ *
60
+ * @hideconstructor
61
+ *
62
+ * @since 1.119
63
+ * @public
64
+ */
65
+ function Notifications (oContainerInterface, sParameters, oServiceConfiguration) {
66
+ const oModel = new JSONModel();
67
+ const oServiceConfig = oServiceConfiguration && oServiceConfiguration.config;
68
+ const aRequestURIs = {
69
+ getNotifications: {},
70
+ getNotificationsByType: {},
71
+ getNotificationsInGroup: {},
72
+ getBadgeNumber: {},
73
+ resetBadgeNumber: {},
74
+ getNotificationTypesSettings: {},
75
+ getNotificationsGroupHeaders: {},
76
+ getMobileSupportSettings: {},
77
+ getEmailSupportSettings: {},
78
+ getWebSocketValidity: {},
79
+ getNotificationCount: {}
80
+ };
81
+ const aUpdateNotificationsCallbacks = [];
82
+ const aUpdateNotificationsCountCallbacks = [];
83
+ const tWebSocketRecoveryPeriod = 5000;
84
+ const tFioriClientInitializationPeriod = 6000;
85
+ const oOperationEnum = {
86
+ NOTIFICATIONS: 0,
87
+ NOTIFICATIONS_BY_TYPE: 1,
88
+ GET_BADGE_NUMBER: 2,
89
+ RESET_BADGE_NUMBER: 3,
90
+ GET_SETTINGS: 4,
91
+ GET_MOBILE_SUPPORT_SETTINGS: 5,
92
+ NOTIFICATIONS_GROUP_HEADERS: 6,
93
+ NOTIFICATIONS_IN_GROUP: 7,
94
+ GET_NOTIFICATIONS_COUNT: 8,
95
+ VALIDATE_WEBSOCKET_CHANNEL: 9,
96
+ GET_EMAIL_SUPPORT_SETTINGS: 10,
97
+ NOTIFICATIONS_BY_DATE_DESCENDING: "notificationsByDateDescending",
98
+ NOTIFICATIONS_BY_DATE_ASCENDING: "notificationsByDateAscending",
99
+ NOTIFICATIONS_BY_PRIORITY_DESCENDING: "notificationsByPriorityDescending",
100
+ NOTIFICATIONS_BY_TYPE_DESCENDING: "notificationsByTypeDescending"
101
+ };
102
+ const oModesEnum = {
103
+ PACKAGED_APP: 0,
104
+ FIORI_CLIENT: 1,
105
+ WEB_SOCKET: 2,
106
+ POLLING: 3
107
+ };
108
+ const oUserFlagsReadFromPersonalizationDeferred = new Deferred();
109
+ const oNotificationSettingsAvailabilityDeferred = new Deferred();
110
+ const oUserFlagsReadFromPersonalizationPromise = oUserFlagsReadFromPersonalizationDeferred.promise();
111
+ const oDummyItems = {};
112
+ const iInitialBufferSize = 10;
113
+
114
+ let tInitializationTimestamp = new Date();
115
+ let oWebSocket;
116
+ let initialReadTimer;
117
+ let webSocketRecoveryTimer;
118
+ let pollingTimer;
119
+ let bIntentBasedConsumption = false;
120
+ let aConsumedIntents = [];
121
+ let bInitialized = false;
122
+ let bOnServiceStop = false;
123
+ let bEnabled = true;
124
+ let sHeaderXcsrfToken;
125
+ let sDataServiceVersion;
126
+ let bWebSocketRecoveryAttempted = false;
127
+ let oCurrentMode;
128
+ let bFirstDataLoaded = false;
129
+ let bHighPriorityBannerEnabled = true;
130
+ let bNotificationSettingsMobileSupport;
131
+ let bNotificationSettingsEmailSupport;
132
+ let bUseDummyItems = false;
133
+ let bInvalidCsrfTokenRecoveryMode = false;
134
+ let bCsrfDataSet = false;
135
+ let aDismissNotifications = [];
136
+
137
+ // *************************************************************************************************
138
+ // ************************************* Service API - Begin ***************************************
139
+
140
+ /**
141
+ * Indicates whether notification service is enabled.<br>
142
+ * Enabling is based on the <code>enable</code> service configuration flag.<br>
143
+ * The service configuration must also include serviceUrl attribute.<br>
144
+ *
145
+ * @returns {boolean} A boolean value indicating whether the notifications service is enabled
146
+ * @public
147
+ * @alias sap.ushell.services.NotificationsV2#isEnabled
148
+ */
149
+ this.isEnabled = function () {
150
+ if (!oServiceConfig.enabled || !oServiceConfig.serviceUrl) {
151
+ bEnabled = false;
152
+ if (oServiceConfig.enabled && !oServiceConfig.serviceUrl) {
153
+ Log.warning("No serviceUrl was found in the service configuration");
154
+ }
155
+ } else {
156
+ bEnabled = true;
157
+ }
158
+ return bEnabled;
159
+ };
160
+
161
+ /**
162
+ * Initializes the notification service
163
+ *
164
+ * Initialization is performed only if the following two conditions are fulfilled:<br>
165
+ * 1. Notification service is enabled<br>
166
+ * 2. Notification service hasn't been initialized yet<br>
167
+ *
168
+ * The main initialization functionality is determining and setting the mode in which notifications are consumed.<br>
169
+ * The possible modes are:<br>
170
+ * PACKAGED_APP - Notifications are fetched when a callback is called by PackagedApp environment<br>
171
+ * FIORI_CLIENT - Notifications are fetched when a callback is called by FioriClient environment<br>
172
+ * WEB_SOCKET - Notifications are fetched on WebSocket "ping"<br>
173
+ * POLLING - Notifications are fetched using periodic polling mechanism<br>
174
+ *
175
+ * @public
176
+ * @alias sap.ushell.services.NotificationsV2#init
177
+ */
178
+ this.init = function () {
179
+ if (!bInitialized && this.isEnabled()) {
180
+ Core.getEventBus().subscribe("launchpad", "sessionTimeout", this.destroy, this);
181
+ this.lastNotificationDate = new Date();
182
+ this._setWorkingMode();
183
+ bInitialized = true;
184
+ this.bUpdateDependencyInitiatorExists = false;
185
+ this._userSettingInitialization();
186
+ }
187
+
188
+ // Listen for requests to enable or disable the connection to the server
189
+ Core.getEventBus().subscribe("launchpad", "setConnectionToServer", this._onSetConnectionToServer, this);
190
+ };
191
+
192
+ /**
193
+ * This event handler enables or disables the connection to the server
194
+ *
195
+ * @param {string} channelID Channel ID of the event
196
+ * @param {string} eventID Event ID of the event
197
+ * @param {{active: boolean}} data Indicates if the connection is to be enabled or disabled
198
+ *
199
+ * @private
200
+ * @alias sap.ushell.services.NotificationsV2#_onSetConnectionToServer
201
+ */
202
+ this._onSetConnectionToServer = function (channelID, eventID, data) {
203
+ if (data.active) {
204
+ this._resumeConnection();
205
+ } else {
206
+ this._closeConnection();
207
+ }
208
+ };
209
+
210
+ /**
211
+ * Returns the number of unseen notifications<br>
212
+ * e.g. Notifications that the user hasn't seen yet.
213
+ *
214
+ * @returns {Promise} Promise resolves with the number of unread notifications of the user
215
+ * @public
216
+ * @alias sap.ushell.services.NotificationsV2#getUnseenNotificationsCount
217
+ */
218
+ this.getUnseenNotificationsCount = function () {
219
+ return Promise.resolve(oModel.getProperty("/UnseenCount"));
220
+ };
221
+ /**
222
+ * Returns the number of notifications<br>
223
+ * e.g. Notifications for user.
224
+ *
225
+ * @returns {int} Returns the number of notifications of the user
226
+ * @public
227
+ * @alias sap.ushell.services.NotificationsV2#getNotificationsCount
228
+ */
229
+ this.getNotificationsCount = function () {
230
+ return oModel.getProperty("/NotificationsCount") || "0";
231
+ };
232
+
233
+ this._createRequest = function (sUri) {
234
+ const oHeader = {
235
+ "Accept-Language": Configuration.getLanguageTag(),
236
+ "X-CSRF-Token": this._getHeaderXcsrfToken() || "fetch" // fetch if not token was obtained previously
237
+ };
238
+ return {
239
+ requestUri: sUri,
240
+ headers: oHeader
241
+ };
242
+ };
243
+
244
+ /**
245
+ * Returns the notifications of the user sorted by type include the group headers and the notifications
246
+ *
247
+ * @returns {Promise} Promise for all notification items
248
+ * @public
249
+ * @alias sap.ushell.services.NotificationsV2#getNotificationsByTypeWithGroupHeaders
250
+ */
251
+ this.getNotificationsByTypeWithGroupHeaders = function () {
252
+ const oRequest = this._createRequest(this._getRequestURI(oOperationEnum.NOTIFICATIONS_BY_TYPE));
253
+
254
+ return new Promise((resolve, reject) => {
255
+ OData.request(oRequest, resolve, (oMessage) => {
256
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
257
+ resolve(oMessage.response.body);
258
+ } else {
259
+ Log.error("Notification service - oData executeAction failed: ", oMessage, "sap.ushell.services.NotificationsV2");
260
+ reject(oMessage);
261
+ }
262
+ });
263
+ });
264
+ };
265
+
266
+ /**
267
+ * Returns the group headers of the user notifications
268
+ *
269
+ * @returns {Promise} Promise for all group headers
270
+ * @public
271
+ * @alias sap.ushell.services.NotificationsV2#getNotificationsGroupHeaders
272
+ */
273
+ this.getNotificationsGroupHeaders = function () {
274
+ const oRequest = this._createRequest(this._getRequestURI(oOperationEnum.NOTIFICATIONS_GROUP_HEADERS));
275
+
276
+ return new Promise((resolve, reject) => {
277
+ OData.request(oRequest, resolve, (oMessage) => {
278
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
279
+ resolve(oMessage.response.body);
280
+ } else {
281
+ Log.error("Notification service - oData executeAction failed: ", oMessage, "sap.ushell.services.NotificationsV2");
282
+ reject();
283
+ }
284
+ });
285
+ });
286
+ };
287
+
288
+ // Private. The function is used in Notifications.controller.
289
+ this.getNotificationsBufferInGroup = function (sGroup, iSkip, iTop) {
290
+ if (bUseDummyItems === true) {
291
+ const aResponse = oDummyItems[oOperationEnum.NOTIFICATIONS_IN_GROUP].slice(iSkip, iSkip + iTop);
292
+ const oResponse = JSON.stringify({
293
+ "@odata.context": "$metadata#Notifications",
294
+ value: aResponse
295
+ });
296
+
297
+ return new Promise((resolve) => {
298
+ window.setTimeout(() => resolve(oResponse), 1000);
299
+ });
300
+ }
301
+
302
+ const oNotificationsService = this;
303
+ const oArgs = {
304
+ group: sGroup,
305
+ skip: iSkip,
306
+ top: iTop
307
+ };
308
+ const oRequest = this._createRequest(this._getRequestURI(oOperationEnum.NOTIFICATIONS_IN_GROUP, oArgs));
309
+
310
+ return new Promise((resolve, reject) => {
311
+ OData.request(oRequest,
312
+ (oResult) => {
313
+ oNotificationsService._updateCSRF(oResult.response);
314
+ resolve(oResult.value);
315
+ },
316
+ (oMessage) => {
317
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
318
+ oNotificationsService._updateCSRF(oMessage.response);
319
+ resolve(JSON.parse(oMessage.response.body).value);
320
+ } else {
321
+ Log.error("Notification service - oData executeAction failed: ", oMessage, "sap.ushell.services.NotificationsV2");
322
+ reject();
323
+ }
324
+ });
325
+ });
326
+ };
327
+
328
+ // Private. The function is used in Notifications.controller.
329
+ this.getNotificationsBufferBySortingType = function (sSortingType, iSkip, iTop) {
330
+ if (bUseDummyItems === true) {
331
+ const oResponse = JSON.stringify({
332
+ "@odata.context": "$metadata#Notifications",
333
+ value: oDummyItems[sSortingType].slice(iSkip, iSkip + iTop)
334
+ });
335
+ return new Promise((resolve) => window.setTimeout(() => resolve(oResponse), 1000));
336
+ }
337
+
338
+ const oNotificationsService = this;
339
+ const oArgs = {
340
+ skip: iSkip,
341
+ top: iTop
342
+ };
343
+ const oRequestObject = this._createRequest(this._getRequestURI(sSortingType, oArgs));
344
+
345
+ return new Promise((resolve, reject) => {
346
+ OData.request(oRequestObject,
347
+ (oResult) => {
348
+ oNotificationsService._updateCSRF(oResult.response);
349
+ resolve(oResult.value);
350
+ },
351
+ (oMessage) => {
352
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
353
+ oNotificationsService._updateCSRF(oMessage.response);
354
+ resolve(JSON.parse(oMessage.response.body).value);
355
+ } else {
356
+ Log.error("Notification service - oData executeAction failed: ", oMessage, "sap.ushell.services.NotificationsV2");
357
+ reject();
358
+ }
359
+ });
360
+ });
361
+ };
362
+
363
+ /**
364
+ * Returns the 10 most recent notifications of the user
365
+ *
366
+ * @returns {Promise} Promise object that on success - returns the 10 most recent user notification items
367
+ * @private
368
+ * @alias sap.ushell.services.NotificationsV2#getNotifications
369
+ */
370
+ this.getNotifications = function () {
371
+ if ((oCurrentMode === oModesEnum.FIORI_CLIENT) || (oCurrentMode === oModesEnum.PACKAGED_APP)) {
372
+ // In Fiori Client mode, notification service fetches notification on initialization,
373
+ // and after that - notification data is updated only by pushed notifications.
374
+ // hence, there's no way that Notification service is updated regarding other changes
375
+ // for example: if the user approved/rejected a notification via other device.
376
+ // In order to solve this - we bring updated data when getNotifications is called from Fiori Client
377
+ return this._readNotificationsData(false).then(() => oModel.getProperty("/Notifications"));
378
+ }
379
+ // In case of offline testing (when OData calls fail):
380
+ // Comment the following line and uncomment the next one
381
+ return Promise.resolve(oModel.getProperty("/Notifications"));
382
+ // return Promise.resolve(this._getDummyJSON());
383
+ };
384
+
385
+ /**
386
+ * Launches a notification action oData call.<br>
387
+ * After launching the action, the function gets updated notification data in order to push the updated data to the consumers.
388
+ *
389
+ * @param {string} sNotificationGroupId The ID of the notification header/group whose action is being executed
390
+ * @param {string} sActionId The ID of the action that is being executed
391
+ * @returns {Promise} Promise object that on success resolves to undefined or it is rejected with failed notifications
392
+ * @public
393
+ * @alias sap.ushell.services.NotificationsV2#executeBulkAction
394
+ */
395
+ this.executeBulkAction = function (sNotificationGroupId, sActionId) {
396
+ return new Promise((resolve, reject) => {
397
+ this.sendBulkAction(sNotificationGroupId, sActionId).then((res) => {
398
+ const aSucceededNotifications = [];
399
+ const aFailedNotifications = [];
400
+ res.forEach((oNotification) => {
401
+ const sNotificationId = oNotification.NotificationId;
402
+ if (oNotification.Success) {
403
+ aSucceededNotifications.push(sNotificationId);
404
+ } else {
405
+ aFailedNotifications.push(sNotificationId);
406
+ }
407
+ });
408
+ const oResult = {
409
+ succededNotifications: aSucceededNotifications,
410
+ failedNotifications: aFailedNotifications
411
+ };
412
+ if (aFailedNotifications.length) {
413
+ reject(oResult);
414
+ } else {
415
+ resolve(oResult);
416
+ }
417
+ });
418
+ });
419
+ };
420
+
421
+ this.dismissBulkNotifications = function (sNotificationGroupId) {
422
+ return this.sendBulkDismiss(sNotificationGroupId);
423
+ };
424
+
425
+ this.executeAction = function (sNotificationId, sActionId) {
426
+ const oNotificationsService = this;
427
+ const sActionUrl = oServiceConfig.serviceUrl + "/ExecuteAction";
428
+ const oRequestBody = { NotificationId: sNotificationId, ActionId: sActionId };
429
+ const oRequestObject = {
430
+ requestUri: sActionUrl,
431
+ method: "POST",
432
+ data: oRequestBody,
433
+ headers: {
434
+ "X-Requested-With": "XMLHttpRequest",
435
+ "Content-Type": "application/json",
436
+ DataServiceVersion: sDataServiceVersion,
437
+ "X-CSRF-Token": sHeaderXcsrfToken
438
+ }
439
+ };
440
+ return new Promise((resolve, reject) => {
441
+ OData.request(
442
+ oRequestObject,
443
+ (oResult) => {
444
+ const responseAck = { isSucessfull: true, message: "" };
445
+ if (oResult && oResult.response && oResult.response.statusCode === 200 && oResult.response.body) {
446
+ const responseAckJson = JSON.parse(oResult.response.body);
447
+ responseAck.isSucessfull = responseAckJson.Success;
448
+ responseAck.message = responseAckJson.MessageText;
449
+ }
450
+ resolve(responseAck);
451
+ },
452
+ (oMessage) => {
453
+ const responseAck = { isSucessfull: false, message: "" };
454
+
455
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
456
+ const responseAckJson = JSON.parse(oMessage.response.body);
457
+ responseAck.isSucessfull = responseAckJson.Success;
458
+ responseAck.message = responseAckJson.MessageText;
459
+ resolve(responseAck);
460
+ } else if (oNotificationsService._csrfTokenInvalid(oMessage) && (bInvalidCsrfTokenRecoveryMode === false)) {
461
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.executeAction, [sNotificationId, sActionId]);
462
+ } else {
463
+ Log.error("Notification service - oData executeAction failed: ", oMessage, "sap.ushell.services.NotificationsV2");
464
+ reject(oMessage);
465
+ }
466
+ });
467
+ });
468
+ };
469
+
470
+ this.sendBulkAction = function (sParentId, sActionId) {
471
+ const oNotificationsService = this;
472
+ const sActionUrl = oServiceConfig.serviceUrl + "/BulkActionByHeader";
473
+ const oRequestBody = { ParentId: sParentId, ActionId: sActionId };
474
+ const oRequestObject = {
475
+ requestUri: sActionUrl,
476
+ method: "POST",
477
+ data: oRequestBody,
478
+ headers: {
479
+ "X-Requested-With": "XMLHttpRequest",
480
+ "Content-Type": "application/json",
481
+ DataServiceVersion: sDataServiceVersion,
482
+ "X-CSRF-Token": sHeaderXcsrfToken
483
+ }
484
+ };
485
+
486
+ return new Promise((resolve, reject) => {
487
+ OData.request(
488
+ oRequestObject,
489
+ (oResult) => {
490
+ let responseAck;
491
+ if (oResult && oResult.response && oResult.response.statusCode === 200 && oResult.response.body) {
492
+ let responseAckJson = JSON.parse(oResult.response.body);
493
+ responseAck = responseAckJson.value;
494
+ }
495
+ resolve(responseAck);
496
+ },
497
+ (oResult) => {
498
+ if (oResult.response && oResult.response.statusCode === 200 && oResult.response.body) {
499
+ let responseAckJson = JSON.parse(oResult.response.body);
500
+ let responseAck = responseAckJson.value;
501
+ resolve(responseAck);
502
+ } else if (oNotificationsService._csrfTokenInvalid(oResult) && (bInvalidCsrfTokenRecoveryMode === false)) {
503
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.sendBulkAction, [sParentId, sActionId]);
504
+ } else {
505
+ Log.error("Notification service - oData executeBulkAction failed: ", oResult.message, "sap.ushell.services.NotificationsV2");
506
+ reject();
507
+ }
508
+ });
509
+ });
510
+ };
511
+
512
+ this.sendBulkDismiss = function (sParentId) {
513
+ const oNotificationsService = this;
514
+ const sActionUrl = oServiceConfig.serviceUrl + "/DismissAll";
515
+ const oRequestBody = { ParentId: sParentId };
516
+ const oRequestObject = {
517
+ requestUri: sActionUrl,
518
+ method: "POST",
519
+ data: oRequestBody,
520
+ headers: {
521
+ "X-Requested-With": "XMLHttpRequest",
522
+ "Content-Type": "application/json",
523
+ DataServiceVersion: sDataServiceVersion,
524
+ "X-CSRF-Token": sHeaderXcsrfToken
525
+ }
526
+ };
527
+
528
+ return new Promise((resolve, reject) => {
529
+ OData.request(oRequestObject, () => resolve(), (oResult) => {
530
+ if (oResult.response && oResult.response.statusCode === 200) {
531
+ resolve();
532
+ } else if (oNotificationsService._csrfTokenInvalid(oResult) && (bInvalidCsrfTokenRecoveryMode === false)) {
533
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.sendBulkDismiss, [sParentId]);
534
+ } else {
535
+ const oMessage = oResult ? oResult.message : "";
536
+ Log.error("Notification service - oData executeBulkAction failed: ", oMessage, "sap.ushell.services.NotificationsV2");
537
+ reject();
538
+ }
539
+ });
540
+ });
541
+ };
542
+
543
+ /**
544
+ * Launches mark as read notification call.<br>
545
+ * After launching the action, the function gets updated notification data in order to push the updated data to the consumers.
546
+ *
547
+ * @param {string} sNotificationId The ID of the notification whose action is being executed
548
+ * @returns {Promise<undefined>} Promise object that on success resolves to undefined or it is rejected with a message object
549
+ * @public
550
+ * @alias sap.ushell.services.NotificationsV2#markRead
551
+ */
552
+ this.markRead = function (sNotificationId) {
553
+ const oNotificationsService = this;
554
+ const sActionUrl = oServiceConfig.serviceUrl + "/MarkRead";
555
+ const oRequestBody = { NotificationId: sNotificationId };
556
+ const oRequestObject = {
557
+ requestUri: sActionUrl,
558
+ method: "POST",
559
+ data: oRequestBody,
560
+ headers: {
561
+ "X-Requested-With": "XMLHttpRequest",
562
+ "Content-Type": "application/json",
563
+ DataServiceVersion: sDataServiceVersion,
564
+ "X-CSRF-Token": sHeaderXcsrfToken
565
+ }
566
+ };
567
+
568
+ return new Promise((resolve, reject) => {
569
+ OData.request(oRequestObject, () => resolve(), (oMessage) => {
570
+ if (oNotificationsService._csrfTokenInvalid(oMessage) && (bInvalidCsrfTokenRecoveryMode === false)) {
571
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.markRead, [sNotificationId]);
572
+ } else {
573
+ Log.error("Notification service - oData reset badge number failed: ", oMessage, "sap.ushell.services.NotificationsV2");
574
+ reject(oMessage);
575
+ }
576
+ });
577
+ });
578
+ };
579
+
580
+ /**
581
+ * Launches dismiss notification call.<br>
582
+ *
583
+ * @param {string} sNotificationId The ID of the notification whose action is being executed
584
+ * @returns {Promise<undefined>} Promise object that on success resolves to undefined or it is rejected with a message object
585
+ * @public
586
+ * @alias sap.ushell.services.NotificationsV2#dismissNotification
587
+ */
588
+ this.dismissNotification = function (sNotificationId) {
589
+ const sActionUrl = oServiceConfig.serviceUrl + "/Dismiss";
590
+ const oNotificationsService = this;
591
+ const oRequestBody = { NotificationId: sNotificationId };
592
+ const oRequestObject = {
593
+ requestUri: sActionUrl,
594
+ method: "POST",
595
+ data: oRequestBody,
596
+ headers: {
597
+ "X-Requested-With": "XMLHttpRequest",
598
+ "Content-Type": "application/json",
599
+ DataServiceVersion: sDataServiceVersion,
600
+ "X-CSRF-Token": sHeaderXcsrfToken
601
+ }
602
+ };
603
+
604
+ return new Promise((resolve, reject) => {
605
+ OData.request(
606
+ oRequestObject,
607
+ () => {
608
+ oNotificationsService._addDismissNotifications(sNotificationId);
609
+ resolve();
610
+ },
611
+ (oMessage) => {
612
+ if (oNotificationsService._csrfTokenInvalid(oMessage) && (bInvalidCsrfTokenRecoveryMode === false)) {
613
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.dismissNotification, [sNotificationId]);
614
+ } else {
615
+ Log.error("Notification service - oData dismiss notification failed: ", oMessage, "sap.ushell.services.NotificationsV2");
616
+ reject(oMessage);
617
+ }
618
+ });
619
+ });
620
+ };
621
+
622
+ /**
623
+ * Gets a callback function that will be called when updated notifications data is available.
624
+ *
625
+ * @param {function} callback The callback function that is registered and called on data update.
626
+ * @public
627
+ * @alias sap.ushell.services.NotificationsV2#registerNotificationsUpdateCallback
628
+ */
629
+ this.registerNotificationsUpdateCallback = function (callback) {
630
+ aUpdateNotificationsCallbacks.push(callback);
631
+ };
632
+
633
+ /**
634
+ * Gets a callback function that will be called when updated unseen notifications count is available.
635
+ *
636
+ * @param {function} callback The callback function that is registered and called on data update.
637
+ * @public
638
+ * @alias sap.ushell.services.NotificationsV2#registerNotificationCountUpdateCallback
639
+ */
640
+ this.registerNotificationCountUpdateCallback = function (callback) {
641
+ aUpdateNotificationsCountCallbacks.push(callback);
642
+ };
643
+
644
+ /**
645
+ * @returns {boolean} boolean value whether first request was already performed and data was returned.<br>
646
+ * @public
647
+ * @alias sap.ushell.services.NotificationsV2#isFirstDataLoaded
648
+ */
649
+ this.isFirstDataLoaded = function () {
650
+ return bFirstDataLoaded;
651
+ };
652
+
653
+ /**
654
+ * @returns {Promise} promise with the user settings flags
655
+ * @private
656
+ */
657
+ this.getUserSettingsFlags = function () {
658
+ return oUserFlagsReadFromPersonalizationPromise.then(() => {
659
+ return { highPriorityBannerEnabled: bHighPriorityBannerEnabled };
660
+ });
661
+ };
662
+
663
+ this.setUserSettingsFlags = function (oFlags) {
664
+ bHighPriorityBannerEnabled = oFlags.highPriorityBannerEnabled;
665
+ this._writeUserSettingsFlagsToPersonalization(oFlags);
666
+ };
667
+
668
+ /**
669
+ * @returns {boolean} value indicating whether the Push to Mobile capability is supported by the Notification channel
670
+ * @private
671
+ */
672
+ this._getNotificationSettingsMobileSupport = function () {
673
+ return bNotificationSettingsMobileSupport;
674
+ };
675
+
676
+ /**
677
+ * @returns {Array} dismissed notifications
678
+ * @private
679
+ */
680
+ this._getDismissNotifications = function () {
681
+ return aDismissNotifications;
682
+ };
683
+
684
+ this.filterDismisssedItems = function (aRecentNotificationsArray, aNotifications) {
685
+ return aRecentNotificationsArray.filter((oRecentItem) => {
686
+ return !aNotifications.some((sDismissItem) => sDismissItem === oRecentItem.originalItemId);
687
+ });
688
+ };
689
+
690
+ /**
691
+ * adds an item to the array of dissmissed notifications
692
+ * @param {string} sId Notification ID.
693
+ * @private
694
+ */
695
+ this._addDismissNotifications = function (sId) {
696
+ if (aDismissNotifications.indexOf(sId) === -1) {
697
+ aDismissNotifications.push(sId);
698
+ }
699
+ };
700
+
701
+ /**
702
+ * initialize array of dissmissed notifications
703
+ * @private
704
+ */
705
+ this._initializeDismissNotifications = function () {
706
+ aDismissNotifications = [];
707
+ };
708
+
709
+ /**
710
+ * @returns {boolean} value indicating whether the Push to Mobile capability is supported by the Notification channel
711
+ * @private
712
+ */
713
+ this._getNotificationSettingsEmailSupport = function () {
714
+ return bNotificationSettingsEmailSupport;
715
+ };
716
+
717
+ this.destroy = function () {
718
+ bOnServiceStop = true;
719
+
720
+ // Clear timers
721
+ if (initialReadTimer) {
722
+ clearTimeout(initialReadTimer);
723
+ } else if (webSocketRecoveryTimer) {
724
+ clearTimeout(webSocketRecoveryTimer);
725
+ } else if (pollingTimer) {
726
+ clearTimeout(pollingTimer);
727
+ }
728
+
729
+ // Close web socket
730
+ if ((oCurrentMode === oModesEnum.WEB_SOCKET) && oWebSocket) {
731
+ oWebSocket.close();
732
+ }
733
+
734
+ // Clear event subscriptions
735
+ Core.getEventBus().unsubscribe("launchpad", "sessionTimeout", this.destroy, this);
736
+ Core.getEventBus().unsubscribe("launchpad", "setConnectionToServer",
737
+ this._onSetConnectionToServer, this);
738
+ };
739
+
740
+ // ************************************** Service API - End ****************************************
741
+ // *************************************************************************************************
742
+
743
+ // *************************************************************************************************
744
+ // ********************************* oData functionality - Begin ***********************************
745
+
746
+ /**
747
+ * Fetching the number of notifications that the user hasn't seen yet <br>
748
+ * and announcing the relevant consumers by calling all registered callback functions.<br>
749
+ *
750
+ * This function is similar to _readNotificationsData.
751
+ * In the future the two functions will be sent together in a single batch request, when batch is supported.
752
+ *
753
+ * @returns {Promise} promise
754
+ * @private
755
+ */
756
+ this._readUnseenNotificationsCount = function () {
757
+ const oNotificationsService = this;
758
+ const oRequestObject = this._createRequest(this._getRequestURI(oOperationEnum.GET_BADGE_NUMBER));
759
+
760
+ return new Promise((resolve, reject) => {
761
+ OData.read(
762
+ oRequestObject,
763
+ (oResult, oResponseData) => {
764
+ oModel.setProperty("/UnseenCount", oResponseData.data.GetBadgeNumber.Number);
765
+ oNotificationsService._setNativeIconBadge(oResponseData.data.GetBadgeNumber.Number);
766
+ resolve(oResponseData.data.GetBadgeNumber.Number);
767
+ },
768
+ (oMessage) => {
769
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
770
+ const oReturnedObject = JSON.parse(oMessage.response.body);
771
+ oModel.setProperty("/UnseenCount", oReturnedObject.value);
772
+ oNotificationsService._setNativeIconBadge(oReturnedObject.value);
773
+ resolve(oReturnedObject.value);
774
+ } else {
775
+ Log.error("Notification service - oData read unseen notifications count failed: ", oMessage.message, "sap.ushell.services.NotificationsV2");
776
+ reject(oMessage);
777
+ }
778
+ }
779
+ );
780
+ });
781
+ };
782
+
783
+ /**
784
+ * Fetching the number of notifications for user<br>
785
+ * @returns {object} promise with notifications count
786
+ */
787
+ this.readNotificationsCount = function () {
788
+ const oRequestObject = this._createRequest(this._getRequestURI(oOperationEnum.GET_NOTIFICATIONS_COUNT));
789
+ return new Promise((resolve, reject) => {
790
+ OData.read(
791
+ oRequestObject,
792
+ (oResult, oResponseData) => resolve(oResponseData.data),
793
+ (oMessage) => {
794
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
795
+ const oReturnedObject = JSON.parse(oMessage.response.body);
796
+ resolve(oReturnedObject.value);
797
+ } else {
798
+ Log.error("Notification service - oData read notifications count failed: ", oMessage.message, "sap.ushell.services.NotificationsV2");
799
+ reject(oMessage);
800
+ }
801
+ }
802
+ );
803
+ });
804
+ };
805
+
806
+ /**
807
+ * @returns {Promise} Returns promise object that is resolved if Notification settings data is available
808
+ * @private
809
+ */
810
+ this._getNotificationSettingsAvailability = function () {
811
+ return oNotificationSettingsAvailabilityDeferred.promise();
812
+ };
813
+
814
+ /**
815
+ * Mark all notifications as seen.<br>
816
+ * the main use-case is when the user navigated to the notification center and sees all the pending notifications.
817
+ * @returns {Promise} Promise taht resolves when operation is finished
818
+ *
819
+ * @public
820
+ * @alias sap.ushell.services.NotificationsV2#notificationsSeen
821
+ */
822
+ this.notificationsSeen = function () {
823
+ const oNotificationsService = this;
824
+ const oRequestObject = {
825
+ requestUri: this._getRequestURI(oOperationEnum.RESET_BADGE_NUMBER),
826
+ method: "POST",
827
+ headers: {
828
+ "X-Requested-With": "XMLHttpRequest",
829
+ "Content-Type": "application/json",
830
+ DataServiceVersion: sDataServiceVersion,
831
+ "X-CSRF-Token": sHeaderXcsrfToken
832
+ }
833
+ };
834
+
835
+ if (this._isFioriClientMode() === true || this._isPackagedMode() === true) {
836
+ this._setNativeIconBadge(0);
837
+ }
838
+
839
+ return new Promise((resolve, reject) => {
840
+ OData.request(
841
+ oRequestObject,
842
+ resolve,
843
+ function (oMessage) {
844
+ if (oNotificationsService._csrfTokenInvalid(oMessage) && (bInvalidCsrfTokenRecoveryMode === false)) {
845
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.notificationsSeen);
846
+ } else {
847
+ Log.error("Notification service - oData reset badge number failed: ", oMessage, "sap.ushell.services.NotificationsV2");
848
+ reject(oMessage);
849
+ }
850
+ }
851
+ );
852
+ });
853
+ };
854
+
855
+ /**
856
+ * Basic notifications data read flow, occurs either on service initialization or on web-socket/polling update event.
857
+ * Includes two read operations:
858
+ * - Read UnseenNotificationsCount and update consumers
859
+ * - Read several (i.e. iInitialBufferSize) notification items
860
+ *
861
+ * The two returned promise objects are pushed into an array, and after resolved, the following steps are performed:
862
+ * - Notifications (unseen) count consumers are updated
863
+ * - Service model is updated with the read notification objects
864
+ * - Notifications update consumers are updated
865
+ *
866
+ * @param {boolean} bUpdateConsumers value indicating whether the consumers should be updated
867
+ * @returns {Promise} promise indicating success of both read actions
868
+ * @private
869
+ */
870
+ this._readNotificationsData = function (bUpdateConsumers) {
871
+ const oNotificationsService = this;
872
+
873
+ this.readNotificationsCount().then((oResponseData) => oModel.setProperty("/NotificationsCount", oResponseData));
874
+
875
+ const oReadUnseenCountPromise = this._readUnseenNotificationsCount(bUpdateConsumers).then(() => {
876
+ if (bUpdateConsumers === true) {
877
+ oNotificationsService._updateNotificationsCountConsumers();
878
+ }
879
+ });
880
+
881
+ const oReadNotificationsPromise = this.getNotificationsBufferBySortingType(oOperationEnum.NOTIFICATIONS_BY_DATE_DESCENDING, 0, iInitialBufferSize)
882
+ .then((oResponseData) => {
883
+ // Measure notification
884
+ oModel.setProperty("/Notifications", oResponseData);
885
+ oNotificationsService._notificationAlert(oResponseData);
886
+ if (bUpdateConsumers === true) {
887
+ oNotificationsService._updateNotificationsConsumers();
888
+ }
889
+ });
890
+
891
+ return Promise.all([oReadUnseenCountPromise, oReadNotificationsPromise]);
892
+ };
893
+
894
+ this._getHeaderXcsrfToken = function () {
895
+ return sHeaderXcsrfToken;
896
+ };
897
+
898
+ this._getDataServiceVersion = function () {
899
+ return sDataServiceVersion;
900
+ };
901
+
902
+ /**
903
+ * Returns the appropriate URI that should be used in an OData request according to the nature of the request and according to filtering that might be required.
904
+ * The object aRequestURIs is filled with the basic and/or byIntents-filter URI, and is used for maintaining the URIs throughout the session.
905
+ *
906
+ * @param {object} oRequiredURI value form the enumeration oOperationEnum, representing the relevant request
907
+ * @param {object} oArgs additional arguments
908
+ * @returns {string} The URI that should be user in the OData.read call
909
+ */
910
+ this._getRequestURI = function (oRequiredURI, oArgs) {
911
+ const sEncodedConsumedIntents = encodeURI(this._getConsumedIntents(oRequiredURI));
912
+ let sReturnedURI;
913
+
914
+ switch (oRequiredURI) {
915
+ // Get notifications
916
+ case oOperationEnum.NOTIFICATIONS:
917
+ if (aRequestURIs.getNotifications.basic === undefined) {
918
+ aRequestURIs.getNotifications.basic = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams&$filter=IsGroupHeader%20eq%20false";
919
+ }
920
+ if (this._isIntentBasedConsumption()) {
921
+ if (aRequestURIs.getNotifications.byIntents === undefined) {
922
+ aRequestURIs.getNotifications.byIntents = aRequestURIs.getNotifications.basic.concat("&intents%20eq%20" + sEncodedConsumedIntents);
923
+ }
924
+ return aRequestURIs.getNotifications.byIntents;
925
+ }
926
+ return aRequestURIs.getNotifications.basic;
927
+ // Get notifications, grouped by type
928
+ case oOperationEnum.NOTIFICATIONS_BY_TYPE:
929
+ if (aRequestURIs.getNotificationsByType.basic === undefined) {
930
+ aRequestURIs.getNotificationsByType.basic = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams";
931
+ }
932
+ if (this._isIntentBasedConsumption()) {
933
+ if (aRequestURIs.getNotificationsByType.byIntents === undefined) {
934
+ aRequestURIs.getNotificationsByType.byIntents = aRequestURIs.getNotificationsByType.basic.concat("&$filter=intents%20eq%20" + sEncodedConsumedIntents);
935
+ }
936
+ return aRequestURIs.getNotificationsByType.byIntents;
937
+ }
938
+ return aRequestURIs.getNotificationsByType.basic;
939
+
940
+ // Get notifications group Headers
941
+ case oOperationEnum.NOTIFICATIONS_GROUP_HEADERS:
942
+ if (aRequestURIs.getNotificationsGroupHeaders.basic === undefined) {
943
+ aRequestURIs.getNotificationsGroupHeaders.basic = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams&$filter=IsGroupHeader%20eq%20true";
944
+ }
945
+ if (this._isIntentBasedConsumption()) {
946
+ if (aRequestURIs.getNotificationsGroupHeaders.byIntents === undefined) {
947
+ aRequestURIs.getNotificationsGroupHeaders.byIntents = aRequestURIs.getNotificationsGroupHeaders.basic.concat("&intents%20eq%20" + sEncodedConsumedIntents);
948
+ }
949
+ return aRequestURIs.getNotificationsGroupHeaders.byIntents;
950
+ }
951
+ return aRequestURIs.getNotificationsGroupHeaders.basic;
952
+
953
+ // Get notifications in group
954
+ case oOperationEnum.NOTIFICATIONS_IN_GROUP:
955
+ sReturnedURI = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams&$orderby=CreatedAt desc&$filter=IsGroupHeader eq false and ParentId eq "
956
+ + oArgs.group + "&$skip=" + oArgs.skip + "&$top=" + oArgs.top;
957
+
958
+ if (this._isIntentBasedConsumption() === true) {
959
+ sReturnedURI = sReturnedURI.concat("&intents%20eq%20" + sEncodedConsumedIntents);
960
+ }
961
+ break;
962
+
963
+ // Get badge number
964
+ case oOperationEnum.GET_BADGE_NUMBER:
965
+ if (aRequestURIs.getBadgeNumber.basic === undefined) {
966
+ aRequestURIs.getBadgeNumber.basic = oServiceConfig.serviceUrl + "/GetBadgeNumber()";
967
+ }
968
+ if (this._isIntentBasedConsumption()) {
969
+ if (aRequestURIs.getBadgeNumber.byIntents === undefined) {
970
+ aRequestURIs.getBadgeNumber.byIntents = oServiceConfig.serviceUrl + "/GetBadgeCountByIntent(" + sEncodedConsumedIntents + ")";
971
+ }
972
+ return aRequestURIs.getBadgeNumber.byIntents;
973
+ }
974
+ return aRequestURIs.getBadgeNumber.basic;
975
+
976
+ // Get Notification Count
977
+ case oOperationEnum.GET_NOTIFICATIONS_COUNT:
978
+ if (aRequestURIs.getNotificationCount.basic === undefined) {
979
+ aRequestURIs.getNotificationCount.basic = oServiceConfig.serviceUrl + "/Notifications/$count";
980
+ }
981
+ return aRequestURIs.getNotificationCount.basic;
982
+
983
+ // Reset badge number (i.e. mark all notifications as "seen")
984
+ case oOperationEnum.RESET_BADGE_NUMBER:
985
+ if (aRequestURIs.resetBadgeNumber.basic === undefined) {
986
+ aRequestURIs.resetBadgeNumber.basic = oServiceConfig.serviceUrl + "/ResetBadgeNumber";
987
+ }
988
+ return aRequestURIs.resetBadgeNumber.basic;
989
+
990
+ // Get user settings
991
+ case oOperationEnum.GET_SETTINGS:
992
+ if (aRequestURIs.getNotificationTypesSettings.basic === undefined) {
993
+ aRequestURIs.getNotificationTypesSettings.basic = oServiceConfig.serviceUrl + "/NotificationTypePersonalizationSet";
994
+ }
995
+ return aRequestURIs.getNotificationTypesSettings.basic;
996
+
997
+ case oOperationEnum.GET_MOBILE_SUPPORT_SETTINGS:
998
+ if (aRequestURIs.getMobileSupportSettings.basic === undefined) {
999
+ aRequestURIs.getMobileSupportSettings.basic = oServiceConfig.serviceUrl + "/Channels(ChannelId='SAP_SMP')";
1000
+ }
1001
+ return aRequestURIs.getMobileSupportSettings.basic;
1002
+
1003
+ case oOperationEnum.GET_EMAIL_SUPPORT_SETTINGS:
1004
+ if (aRequestURIs.getEmailSupportSettings.basic === undefined) {
1005
+ aRequestURIs.getEmailSupportSettings.basic = oServiceConfig.serviceUrl + "/Channels(ChannelId='SAP_EMAIL')";
1006
+ }
1007
+ return aRequestURIs.getEmailSupportSettings.basic;
1008
+
1009
+ case oOperationEnum.VALIDATE_WEBSOCKET_CHANNEL:
1010
+ if (aRequestURIs.getWebSocketValidity.basic === undefined) {
1011
+ aRequestURIs.getWebSocketValidity.basic = oServiceConfig.serviceUrl + "/Channels('SAP_WEBSOCKET')";
1012
+ }
1013
+ return aRequestURIs.getWebSocketValidity.basic;
1014
+
1015
+ // Get a buffer of notifications (using $skip, $top and $orderby options) sorted by date in descending order
1016
+ case oOperationEnum.NOTIFICATIONS_BY_DATE_DESCENDING:
1017
+ sReturnedURI = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams&$orderby=CreatedAt%20desc&$filter=IsGroupHeader%20eq%20false&$skip="
1018
+ + oArgs.skip + "&$top=" + oArgs.top;
1019
+ if (this._isIntentBasedConsumption() === true) {
1020
+ sReturnedURI = sReturnedURI.concat("&intents%20eq%20" + sEncodedConsumedIntents);
1021
+ }
1022
+ break;
1023
+
1024
+ // Get a buffer of notifications (using $skip, $top and $orderby options) sorted by date in ascending order
1025
+ case oOperationEnum.NOTIFICATIONS_BY_DATE_ASCENDING:
1026
+ sReturnedURI = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams&$orderby=CreatedAt%20asc&$filter=IsGroupHeader%20eq%20false&$skip="
1027
+ + oArgs.skip + "&$top=" + oArgs.top;
1028
+ if (this._isIntentBasedConsumption() === true) {
1029
+ sReturnedURI = sReturnedURI.concat("&intents%20eq%20" + sEncodedConsumedIntents);
1030
+ }
1031
+ break;
1032
+
1033
+ // Get a buffer of notifications (using $skip, $top and $orderby options) sorted by priority in ascending order
1034
+ case oOperationEnum.NOTIFICATIONS_BY_PRIORITY_DESCENDING:
1035
+ sReturnedURI = oServiceConfig.serviceUrl + "/Notifications?$expand=Actions,NavigationTargetParams&$orderby=Priority%20desc&$filter=IsGroupHeader%20eq%20false&$skip="
1036
+ + oArgs.skip + "&$top=" + oArgs.top;
1037
+ if (this._isIntentBasedConsumption() === true) {
1038
+ sReturnedURI = sReturnedURI.concat("&intents%20eq%20" + sEncodedConsumedIntents);
1039
+ }
1040
+ break;
1041
+
1042
+ default:
1043
+ sReturnedURI = "";
1044
+ }
1045
+ return sReturnedURI;
1046
+ };
1047
+
1048
+ /**
1049
+ * @returns {Promise} Promise object that is resolved with the settings from the sever
1050
+ * @private
1051
+ */
1052
+ this.readSettings = function () {
1053
+ const oRequestObject = this._createRequest(this._getRequestURI(oOperationEnum.GET_SETTINGS));
1054
+
1055
+ return new Promise((resolve, reject) => {
1056
+ OData.request(
1057
+ oRequestObject,
1058
+ (oResult) => resolve(oResult.results),
1059
+ (oMessage) => {
1060
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
1061
+ resolve(oMessage.response.body);
1062
+ } else {
1063
+ Log.error("Notification service - oData get settings failed: ", oMessage, "sap.ushell.services.NotificationsV2");
1064
+ reject(oMessage);
1065
+ }
1066
+ });
1067
+ });
1068
+ };
1069
+
1070
+ /**
1071
+ * Verifying whether the "push notifications to mobile" feature is supported.
1072
+ *
1073
+ * @returns {object} A Deferred.promise object that is always resolved even if the request failed.<br>
1074
+ * In case of failure - the response property successStatus gets the value <code>false</code>
1075
+ */
1076
+ this._readMobileSettingsFromServer = function () {
1077
+ return this._readChannelSettingsFromServer(oOperationEnum.GET_MOBILE_SUPPORT_SETTINGS);
1078
+ };
1079
+
1080
+ /**
1081
+ * Verifying whether the "push notifications to mobile" feature is supported.
1082
+ *
1083
+ * @returns {Promise} promise is always resolved even if the request failed.<br>
1084
+ * In case of failure - the response property successStatus gets the value <code>false</code>
1085
+ */
1086
+ this._readEmailSettingsFromServer = function () {
1087
+ return this._readChannelSettingsFromServer(oOperationEnum.GET_EMAIL_SUPPORT_SETTINGS);
1088
+ };
1089
+
1090
+ this._readChannelSettingsFromServer = function (operation) {
1091
+ const sRequestUrl = this._getRequestURI(operation);
1092
+ const oRequestObject = this._createRequest(sRequestUrl);
1093
+ let oResponseObject;
1094
+ let sUpdatedResponseString;
1095
+
1096
+ return new Promise((resolve) => {
1097
+ OData.request(
1098
+ oRequestObject,
1099
+ (oResult) => {
1100
+ if (typeof (oResult.results) === "string") {
1101
+ oResponseObject = JSON.parse(oResult.results);
1102
+ oResponseObject.successStatus = true;
1103
+ sUpdatedResponseString = JSON.stringify(oResponseObject);
1104
+ resolve(sUpdatedResponseString);
1105
+ } else {
1106
+ oResult.results.successStatus = true;
1107
+ resolve(oResult.results);
1108
+ }
1109
+ },
1110
+ (oMessage) => {
1111
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
1112
+ oResponseObject = JSON.parse(oMessage.response.body);
1113
+ oResponseObject.successStatus = true;
1114
+ sUpdatedResponseString = JSON.stringify(oResponseObject);
1115
+ resolve(sUpdatedResponseString);
1116
+ } else {
1117
+ Log.error("Notification service - oData get settings failed: ", oMessage, "sap.ushell.services.NotificationsV2");
1118
+ resolve(JSON.stringify({ successStatus: false }));
1119
+ }
1120
+ }
1121
+ );
1122
+ });
1123
+ };
1124
+
1125
+ /**
1126
+ * Verifying whether the WebSocket is active (while it is already opened)
1127
+ *
1128
+ * @returns {Promise} promise is always resolved even if the request fails.<br>
1129
+ * The actual response is returned as the done function's boolean parameter:<br>
1130
+ * In case of active WebSocket - the value <code>true</code> is returned, and <code>false</code> otherwise.
1131
+ */
1132
+ this._checkWebSocketActivity = function () {
1133
+ const oRequestObject = this._createRequest(this._getRequestURI(oOperationEnum.VALIDATE_WEBSOCKET_CHANNEL));
1134
+ return new Promise((resolve) => {
1135
+ OData.request(
1136
+ oRequestObject,
1137
+ (oResult) => {
1138
+ if (typeof (oResult.results) === "string") {
1139
+ const oResponseObject = JSON.parse(oResult.results);
1140
+ resolve(oResponseObject.IsActive);
1141
+ } else {
1142
+ resolve(false);
1143
+ }
1144
+ },
1145
+ (oMessage) => {
1146
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
1147
+ const oResponseObject = JSON.parse(oMessage.response.body);
1148
+ resolve(oResponseObject.IsActive);
1149
+ } else {
1150
+ Log.error("Notification service - oData get settings failed: ", oMessage, "sap.ushell.services.NotificationsV2");
1151
+ resolve(false);
1152
+ }
1153
+ });
1154
+ });
1155
+ };
1156
+
1157
+ /**
1158
+ * @param {object} oEntry Settings entry to be saved
1159
+ * @returns {Promise} Save settings promise
1160
+ * @private
1161
+ */
1162
+ this.saveSettingsEntry = function (oEntry) {
1163
+ const oNotificationsService = this;
1164
+ const sSetSettingsUrl = this._getRequestURI(oOperationEnum.GET_SETTINGS) + "(NotificationTypeId=" + oEntry.NotificationTypeId + ")";
1165
+ const oRequestObject = {
1166
+ requestUri: sSetSettingsUrl,
1167
+ method: "PUT",
1168
+ headers: {
1169
+ "X-Requested-With": "XMLHttpRequest",
1170
+ "Content-Type": "application/json",
1171
+ DataServiceVersion: sDataServiceVersion,
1172
+ "X-CSRF-Token": sHeaderXcsrfToken
1173
+ }
1174
+ };
1175
+
1176
+ // make sure to always send the entire set of properties to the backend
1177
+ oRequestObject.data = JSON.parse(JSON.stringify(oEntry));
1178
+ oRequestObject.data["@odata.context"] = "$metadata#NotificationTypePersonalizationSet/$entity";
1179
+
1180
+ return new Promise((resolve, reject) => {
1181
+ OData.request(
1182
+ oRequestObject,
1183
+ resolve,
1184
+ (oMessage) => {
1185
+ if (oMessage.response && oMessage.response.statusCode === 200 && oMessage.response.body) {
1186
+ resolve(oMessage.response.body);
1187
+ } else if (oNotificationsService._csrfTokenInvalid(oMessage) && (bInvalidCsrfTokenRecoveryMode === false)) {
1188
+ oNotificationsService._invalidCsrfTokenRecovery(resolve, reject, oNotificationsService.saveSettingsEntry, [oEntry]);
1189
+ } else {
1190
+ Log.error("Notification service - oData set settings entry failed: ", oMessage, "sap.ushell.services.NotificationsV2");
1191
+ reject(oMessage);
1192
+ }
1193
+ });
1194
+ });
1195
+ };
1196
+
1197
+ // ********************************** oData functionality - End ************************************
1198
+ // *************************************************************************************************
1199
+
1200
+ this._updateNotificationsConsumers = function () {
1201
+ aUpdateNotificationsCallbacks.forEach(callback => callback());
1202
+ };
1203
+
1204
+ this._updateNotificationsCountConsumers = function () {
1205
+ aUpdateNotificationsCountCallbacks.forEach(callback => callback());
1206
+ };
1207
+
1208
+ this._updateAllConsumers = function () {
1209
+ this._updateNotificationsConsumers();
1210
+ this._updateNotificationsCountConsumers();
1211
+ };
1212
+
1213
+ this._getModel = function () {
1214
+ return oModel;
1215
+ };
1216
+
1217
+ //*************************************************************************************************
1218
+ //*********************** Handle Notifications consumption / modes - Begin ***********************
1219
+
1220
+ this._getMode = function () {
1221
+ return oCurrentMode;
1222
+ };
1223
+
1224
+ /**
1225
+ * There are four possible modes of working of Notification service, defined by oModesEnum.
1226
+ * The following functions (i.e. steps) are executes sequentially, from _setWorkingMode (step 1) downwards
1227
+ * in order to find what is the relevant working mode for notification service and to activate it.
1228
+ */
1229
+
1230
+ /**
1231
+ * Starting the process of defining the mode in which notifications service consume notifications data.
1232
+ * Step 1. Handle packagedApp mode
1233
+ */
1234
+ this._setWorkingMode = function () {
1235
+ let aConsumedIntentsFromConfig;
1236
+
1237
+ // check service configuration for ConsumedIntents enabling flag and data
1238
+ if (oServiceConfig.intentBasedConsumption === true) {
1239
+ aConsumedIntents = this._getIntentsFromConfiguration(oServiceConfig.consumedIntents);
1240
+ if (aConsumedIntents.length > 0) {
1241
+ // First setting of the flag is from service configuration
1242
+ bIntentBasedConsumption = true;
1243
+ }
1244
+ }
1245
+
1246
+ // Check if this is packagedApp use-case
1247
+ if (this._isPackagedMode()) {
1248
+ oCurrentMode = oModesEnum.PACKAGED_APP;
1249
+
1250
+ // Consumed intents are read from PackagedApp configuration, if exist
1251
+ aConsumedIntentsFromConfig = this._getIntentsFromConfiguration(window.fiori_client_appConfig.applications);
1252
+ if (aConsumedIntentsFromConfig.length > 0) {
1253
+ aConsumedIntents = aConsumedIntentsFromConfig;
1254
+ }
1255
+
1256
+ if (aConsumedIntents.length > 0) {
1257
+ // Second setting of the flag (to true) is done in case of PackagedApp mode and if any intents were configured
1258
+ bIntentBasedConsumption = true;
1259
+ }
1260
+
1261
+ this._registerForPush();
1262
+ this._readNotificationsData(true);
1263
+
1264
+ this._setNativeIconBadgeWithDelay();
1265
+
1266
+ return;
1267
+ }
1268
+
1269
+ // Call step 2: Perform the first oData read request
1270
+ this._performFirstRead();
1271
+ };
1272
+
1273
+ /**
1274
+ * Step 2. Issue the initial oData call for getting notification data, then wait until it is possible to check if we're in Fiori Client mode:
1275
+ * The execution of the _isFioriClientMode check must be delayed by 6000ms for initial loading since it relies on the flag sap.FioriClient that is set by FioriClient
1276
+ */
1277
+ this._performFirstRead = function () {
1278
+ const oNotificationsService = this;
1279
+
1280
+ this._readNotificationsData(true).then(() => {
1281
+ // Calculate time left until Fiori Client mode can be checked
1282
+ const tFioriClientRemainingDelay = oNotificationsService._getFioriClientRemainingDelay();
1283
+ if (tFioriClientRemainingDelay <= 0) {
1284
+ oNotificationsService._fioriClientStep();
1285
+ } else {
1286
+ initialReadTimer = setTimeout(function () {
1287
+ oNotificationsService._fioriClientStep();
1288
+ }, tFioriClientRemainingDelay);
1289
+ }
1290
+ bFirstDataLoaded = true;
1291
+ }).catch((sMsg) => {
1292
+ Log.error("Notifications oData read failed. Error: " + sMsg);
1293
+ });
1294
+ };
1295
+
1296
+ /**
1297
+ * Step 3. waiting the delay necessary for Fiori Client - Check if this is indeed Fiori Client mode
1298
+ * If so - initialize Fiori Client mode. If not - go to the nest step (webSocket)
1299
+ */
1300
+ this._fioriClientStep = function () {
1301
+ if (this._isFioriClientMode()) {
1302
+ oCurrentMode = oModesEnum.FIORI_CLIENT;
1303
+ this._addPushNotificationHandler();
1304
+
1305
+ this.getUnseenNotificationsCount()
1306
+ .then(function (iBadgeValue) {
1307
+ this._setNativeIconBadge(iBadgeValue, () => { });
1308
+ }.bind(this))
1309
+ .catch(() => { });
1310
+ } else {
1311
+ this._webSocketStep();
1312
+ }
1313
+ };
1314
+
1315
+ /**
1316
+ * Step 4. WebSocket step
1317
+ */
1318
+ this._webSocketStep = function () {
1319
+ oCurrentMode = oModesEnum.WEB_SOCKET;
1320
+ this._establishWebSocketConnection();
1321
+ };
1322
+
1323
+ /**
1324
+ * Step 5. WebSocket recovery step
1325
+ * Called on WebSocket onClose event.
1326
+ * In this case there is one additional trial to establish the WebSocket connection.
1327
+ * If the additional attempt also fails - move to polling
1328
+ */
1329
+ this._webSocketRecoveryStep = function () {
1330
+ if (bWebSocketRecoveryAttempted === false) {
1331
+ bWebSocketRecoveryAttempted = true;
1332
+ webSocketRecoveryTimer = window.setTimeout(this._webSocketStep.bind(this), tWebSocketRecoveryPeriod);
1333
+ } else {
1334
+ // Since the first request for notifications data was already issued -
1335
+ // the first polling request is delayed by (iPollingInterval * 1000) seconds
1336
+ this._activatePollingAfterInterval();
1337
+ }
1338
+ };
1339
+
1340
+ this._activatePollingAfterInterval = function () {
1341
+ const iPollingInterval = oServiceConfig.pollingIntervalInSeconds || I_DEFAULT_POLLING_INTERVAL;
1342
+
1343
+ window.clearTimeout(pollingTimer);
1344
+ pollingTimer = window.setTimeout(this._activatePolling.bind(this), ushellUtils.sanitizeTimeoutDelay(iPollingInterval * 1000));
1345
+ };
1346
+
1347
+ /**
1348
+ * Step 6. Polling
1349
+ */
1350
+ this._activatePolling = function () {
1351
+ const iPollingInterval = oServiceConfig.pollingIntervalInSeconds || I_DEFAULT_POLLING_INTERVAL;
1352
+
1353
+ oCurrentMode = oModesEnum.POLLING;
1354
+ this._readNotificationsData(true);
1355
+ // Call again after a delay
1356
+ window.clearTimeout(pollingTimer);
1357
+ pollingTimer = window.setTimeout(this._activatePolling.bind(this, iPollingInterval, false), ushellUtils.sanitizeTimeoutDelay(iPollingInterval * 1000));
1358
+ };
1359
+
1360
+ this._formatAsDate = function (sUnformatted) {
1361
+ return new Date(sUnformatted);
1362
+ };
1363
+
1364
+ this._notificationAlert = function (results) {
1365
+ // If alerts/banners for HIGH priority notifications are disabled by the user - then return
1366
+ if (bHighPriorityBannerEnabled === false) {
1367
+ return;
1368
+ }
1369
+
1370
+ const aNewNotifications = [];
1371
+ let nextLastNotificationDate = 0;
1372
+
1373
+ for (const oNotification in results) {
1374
+ if (this.lastNotificationDate && this._formatAsDate(results[oNotification].CreatedAt) > this.lastNotificationDate) {
1375
+ if (results[oNotification].Priority === "HIGH") {
1376
+ aNewNotifications.push(results[oNotification]);
1377
+ }
1378
+ }
1379
+ // get the last notification date
1380
+ if (nextLastNotificationDate < this._formatAsDate(results[oNotification].CreatedAt)) {
1381
+ nextLastNotificationDate = this._formatAsDate(results[oNotification].CreatedAt);
1382
+ }
1383
+ }
1384
+ if (this.lastNotificationDate && aNewNotifications.length > 0) {
1385
+ Core.getEventBus().publish("sap.ushell.services.Notifications", "onNewNotifications", aNewNotifications);
1386
+ }
1387
+ this.lastNotificationDate = nextLastNotificationDate;
1388
+ };
1389
+
1390
+ /**
1391
+ * Returning the time, in milliseconds, left until the end of FioriClient waiting period.
1392
+ * The required period is represented by tFioriClientInitializationPeriod, and we reduce the time passed from service initialization until now
1393
+ * @returns {int} Remaining delay
1394
+ */
1395
+ this._getFioriClientRemainingDelay = function () {
1396
+ return tFioriClientInitializationPeriod - (new Date() - tInitializationTimestamp);
1397
+ };
1398
+
1399
+ /**
1400
+ * Establishing a WebSocket connection for push updates
1401
+ */
1402
+ this._establishWebSocketConnection = function () {
1403
+ const oNotificationsService = this;
1404
+ let bDeliberateClose = false;
1405
+
1406
+ try {
1407
+ // Init WebSocket connection
1408
+ oWebSocket = this._getWebSocketObjectObject(oServiceConfig.webSocketUrl || S_DEFAULT_WEBSOCKET_URL, [SapPcpWebSocket.SUPPORTED_PROTOCOLS.v10]);
1409
+
1410
+ oWebSocket.attachMessage(this, function (oMessage/*, oData*/) {
1411
+ const oPcpFields = oMessage.getParameter("pcpFields");
1412
+ if ((oPcpFields) && (oPcpFields.Command) && (oPcpFields.Command === "Notification")) {
1413
+ // Receive "pings" for Notification EntitySet
1414
+ // Another optional "ping" would be oPcpFields.Command === "Badge" for new Badge Number, but is currently not supported.
1415
+ oNotificationsService._readNotificationsData(true);
1416
+ }
1417
+ });
1418
+
1419
+ oWebSocket.attachOpen(this, function () {
1420
+ oNotificationsService._checkWebSocketActivity().then((bIsActive) => {
1421
+ // In case when bIsActive is false, the webSocket is not active although the connection is opened.
1422
+ // in this case we should close the WebSocket connection and switch to polling step.
1423
+ if (!bIsActive) {
1424
+ bDeliberateClose = true;
1425
+ oWebSocket.close();
1426
+ oNotificationsService._activatePollingAfterInterval();
1427
+ }
1428
+ });
1429
+ Log.info("Notifications UShell service WebSocket: webSocket connection opened");
1430
+ });
1431
+
1432
+ oWebSocket.attachClose(this, function (oEvent) {
1433
+ Log.warning("Notifications UShell service WebSocket: attachClose called with code: " + oEvent.mParameters.code + " and reason: " + oEvent.mParameters.reason);
1434
+ if ((!bOnServiceStop) && (!bDeliberateClose)) {
1435
+ oNotificationsService._webSocketRecoveryStep();
1436
+ }
1437
+ });
1438
+
1439
+ // attachError is not being handled since each attachError is followed by a call to attachClose (...which includes handling)
1440
+ oWebSocket.attachError(this, function () {
1441
+ Log.warning("Notifications UShell service WebSocket: attachError called!");
1442
+ });
1443
+ } catch (e) {
1444
+ Log.error("Exception occurred while creating new sap.ui.core.ws.SapPcpWebSocket. Message: " + e.message);
1445
+ }
1446
+ };
1447
+
1448
+ // *********************** Handle Notifications consumption / modes - End **************************
1449
+ // *************************************************************************************************
1450
+
1451
+ // *************************************************************************************************
1452
+ // **************** Helper functions for Fiori client and PackagedApp mode - Begin *****************
1453
+
1454
+ this._isFioriClientMode = function () {
1455
+ return !(sap.FioriClient === undefined);
1456
+ };
1457
+
1458
+ /**
1459
+ * Helper function for Packaged App mode
1460
+ */
1461
+ this._isPackagedMode = function () {
1462
+ return (window.fiori_client_appConfig && window.fiori_client_appConfig.prepackaged === true);
1463
+ };
1464
+
1465
+ this._setNativeIconBadge = function (iBadgeValue) {
1466
+ if (sap.Push && sap.Push.setBadgeNumber) {
1467
+ sap.Push.setBadgeNumber(iBadgeValue, () => { });
1468
+ }
1469
+ };
1470
+
1471
+ this._setNativeIconBadgeWithDelay = function () {
1472
+ setTimeout(function () {
1473
+ this.getUnseenNotificationsCount().then(function (iBadgeValue) {
1474
+ this._setNativeIconBadge(iBadgeValue);
1475
+ }.bind(this))
1476
+ .catch(() => { });
1477
+ }.bind(this), 4000);
1478
+ };
1479
+
1480
+ this._getIntentsFromConfiguration = function (aInput) {
1481
+ const aTempConsumedIntents = [];
1482
+ if (aInput && aInput.length > 0) {
1483
+ let sTempIntent;
1484
+
1485
+ for (let index = 0; index < aInput.length; index++) {
1486
+ sTempIntent = aInput[index].intent;
1487
+ aTempConsumedIntents.push(sTempIntent);
1488
+ }
1489
+ }
1490
+ return aTempConsumedIntents;
1491
+ };
1492
+
1493
+ this._handlePushedNotification = function (oNotificationData) {
1494
+ let sSemanticObject;
1495
+ let sAction;
1496
+ let oParameters;
1497
+ let aParameters = [];
1498
+
1499
+ if (oNotificationData !== undefined) {
1500
+ // Either oNotificationData.additionalData is not defined
1501
+ // OR oNotificationData.additionalData has the value "true" (foreground use-case)
1502
+ if ((oNotificationData.additionalData === undefined) || (oNotificationData.additionalData.foreground === true)) {
1503
+ // The given notification object is ignored, and we relate to this use-case as a "ping",
1504
+ // telling us that notifications data (in the Notification Center) was changed, hence the call to _readNotificationsData
1505
+ this._readNotificationsData(true);
1506
+
1507
+ // Background use-case (oNotificationData.additionalData is defined and equals "false")
1508
+ } else {
1509
+ // Read the semantic object, the action and the navigation parameters from the additionalData part of the notification,
1510
+ // or as a fallback - from the notification item's data
1511
+
1512
+ if (oNotificationData.additionalData && oNotificationData.additionalData.NavigationTargetObject) {
1513
+ sSemanticObject = oNotificationData.additionalData.NavigationTargetObject;
1514
+ } else {
1515
+ sSemanticObject = oNotificationData.NavigationTargetObject;
1516
+ }
1517
+
1518
+ if (oNotificationData.additionalData && oNotificationData.additionalData.NavigationTargetAction) {
1519
+ sAction = oNotificationData.additionalData.NavigationTargetAction;
1520
+ } else {
1521
+ sAction = oNotificationData.NavigationTargetAction;
1522
+ }
1523
+
1524
+ if (oNotificationData.additionalData && oNotificationData.additionalData.NavigationTargetParam) {
1525
+ oParameters = oNotificationData.additionalData.NavigationTargetParam;
1526
+ } else {
1527
+ oParameters = oNotificationData.NavigationTargetParam;
1528
+ }
1529
+
1530
+ if (oParameters) {
1531
+ if (typeof oParameters === "string" || oParameters instanceof String) {
1532
+ aParameters[0] = oParameters;
1533
+ } else if (Array.isArray(oParameters) === true) {
1534
+ aParameters = oParameters;
1535
+ }
1536
+ }
1537
+
1538
+ const sNotificationId = oNotificationData.NotificationId;
1539
+
1540
+ if (sSemanticObject && sAction) {
1541
+ // Perform a navigation action according to the pushed notification's intent
1542
+ ushellUtils.toExternalWithParameters(sSemanticObject, sAction, aParameters);
1543
+ }
1544
+
1545
+ this.markRead(sNotificationId);
1546
+
1547
+ this._readNotificationsData(true);
1548
+ }
1549
+ }
1550
+ };
1551
+
1552
+ this._registerForPush = function () {
1553
+ if (sap.Push) {
1554
+ sap.Push.initPush(this._handlePushedNotification.bind(this));
1555
+ }
1556
+ };
1557
+
1558
+ /**
1559
+ * For Fiori Client use case on mobile platform.
1560
+ * This function registers the callback this._handlePushedNotification for the deviceready event
1561
+ */
1562
+ this._addPushNotificationHandler = function () {
1563
+ document.addEventListener("deviceready", this._registerForPush.bind(this), false);
1564
+ };
1565
+
1566
+ this._isIntentBasedConsumption = function () {
1567
+ return bIntentBasedConsumption;
1568
+ };
1569
+
1570
+ /**
1571
+ * Creates and returns the intents filter string of an OData request
1572
+ * For example: &NavigationIntent%20eq%20%27Action-toappstatesample%27%20or%20NavigationIntent%20eq%20%27Action-toappnavsample%27
1573
+ */
1574
+ this._getConsumedIntents = function (oRequestURI) {
1575
+ let sConsumedIntents = "";
1576
+
1577
+ if (!this._isIntentBasedConsumption()) {
1578
+ return sConsumedIntents;
1579
+ }
1580
+
1581
+ if (aConsumedIntents.length > 0) {
1582
+ // If it is not GetBadgeNumber use-case then the intents filter string should start with "&"
1583
+ if (oRequestURI !== oOperationEnum.GET_BADGE_NUMBER) {
1584
+ sConsumedIntents = "&";
1585
+ }
1586
+
1587
+ for (let index = 0; index < aConsumedIntents.length; index++) {
1588
+ // If it is GetBadgeNumber use case then the intent are comma separated
1589
+ if (oRequestURI === oOperationEnum.GET_BADGE_NUMBER) {
1590
+ if (index === 0) {
1591
+ sConsumedIntents = aConsumedIntents[index];
1592
+ } else {
1593
+ sConsumedIntents = sConsumedIntents + "," + aConsumedIntents[index];
1594
+ }
1595
+ } else {
1596
+ sConsumedIntents = sConsumedIntents + "NavigationIntent%20eq%20%27" + aConsumedIntents[index] + "%27";
1597
+ }
1598
+ }
1599
+ }
1600
+ return sConsumedIntents;
1601
+ };
1602
+
1603
+ this._revalidateCsrfToken = function () {
1604
+ sHeaderXcsrfToken = undefined;
1605
+ bCsrfDataSet = false;
1606
+
1607
+ return this.getNotificationsBufferBySortingType(oOperationEnum.NOTIFICATIONS_BY_DATE_DESCENDING, 0, 1);
1608
+ };
1609
+
1610
+ this._csrfTokenInvalid = function (oMessage) {
1611
+ const oResponse = oMessage.response;
1612
+ const bAuthorizationError = oResponse && oResponse.statusCode === 403;
1613
+ const sCSRFTokenHeader = oResponse ? oResponse.headers["x-csrf-token"] : "";
1614
+ // There have been instances of services returning "Required" as well as "required",
1615
+ // therefore the method toLowerCase is used.
1616
+ const bCSRFTokenRequired = sCSRFTokenHeader.toLowerCase() === "required";
1617
+ return bAuthorizationError && bCSRFTokenRequired;
1618
+ };
1619
+
1620
+ /**
1621
+ * Called in case that the CSRF token becomes invalid during the session.
1622
+ *
1623
+ * This problem (i.e., invalid CSRF token) is found when a POST oData call fails (e.g, markRead).
1624
+ * in such a case this function is called in order to perform the recovery flow.
1625
+ *
1626
+ * The recovery flow includes two main steps:
1627
+ * 1. Obtaining the new/valid CSRF token from the notification channel
1628
+ * 2. Calling the function that failed (with the same parameters)
1629
+ * 3. resolving/rejecting the deferred object of the first function call (the one that failed because the token became invalid) in order to continue with the original flow
1630
+ *
1631
+ * This function doesn't return anything, instead it calls the provided resolve or reject callbacks
1632
+ *
1633
+ * @private
1634
+ */
1635
+ this._invalidCsrfTokenRecovery = function (resolve, reject, fnFailedFunction, aArgsArray) {
1636
+ const oNotificationsService = this;
1637
+
1638
+ bInvalidCsrfTokenRecoveryMode = true;
1639
+
1640
+ // Getting the new/valid CSRF token
1641
+ this._revalidateCsrfToken().then(() => {
1642
+ // Call the failed function (with the same parameters)
1643
+ fnFailedFunction.apply(oNotificationsService, aArgsArray)
1644
+ .then(resolve)
1645
+ .catch((e) => {
1646
+ if (e.response && e.response.statusCode === 200 && e.response.body) {
1647
+ resolve(e.response.body);
1648
+ } else {
1649
+ reject(e);
1650
+ }
1651
+ })
1652
+ .finally(() => {
1653
+ bInvalidCsrfTokenRecoveryMode = false;
1654
+ });
1655
+ }).catch((e) => {
1656
+ bInvalidCsrfTokenRecoveryMode = false;
1657
+ Log.error("Notification service - oData markRead failed: ", e.message, "sap.ushell.services.NotificationsV2");
1658
+ reject(e);
1659
+ });
1660
+ };
1661
+
1662
+ // **************** Helper functions for Fiori client and PackagedApp mode - End *****************
1663
+ // ***********************************************************************************************
1664
+
1665
+ this._notificationsAscendingSortBy = function (aNotifications, sPropertyToSortBy) {
1666
+ aNotifications.sort((x, y) => {
1667
+ let val1 = x[sPropertyToSortBy];
1668
+ let val2 = y[sPropertyToSortBy];
1669
+
1670
+ if (val1 === val2) {
1671
+ val1 = x.id;
1672
+ val2 = y.id;
1673
+ }
1674
+ return val2 > val1 ? -1 : 1;
1675
+ });
1676
+ return aNotifications;
1677
+ };
1678
+
1679
+ this._getWebSocketObjectObject = function (sWebSocketUrl, aVersionProtocol) {
1680
+ return new SapPcpWebSocket(sWebSocketUrl, aVersionProtocol);
1681
+ };
1682
+
1683
+ this.getOperationEnum = function () {
1684
+ return oOperationEnum;
1685
+ };
1686
+
1687
+ /**
1688
+ * Read user settings flags from the personalization and update the variable bHighPriorityBannerEnabled.
1689
+ * If the data does not yet exists in the personalization,
1690
+ * write the default value of bHighPriorityBannerEnabled to the personalization
1691
+ */
1692
+ this._readUserSettingsFlagsFromPersonalization = function () {
1693
+ const oNotificationsService = this;
1694
+ this._getUserSettingsPersonalizer()
1695
+ .then((oPersonalizer) => {
1696
+ oPersonalizer.getPersData()
1697
+ .then((oFlagsData) => {
1698
+ if (oFlagsData === undefined) {
1699
+ oNotificationsService._writeUserSettingsFlagsToPersonalization({
1700
+ highPriorityBannerEnabled: bHighPriorityBannerEnabled
1701
+ });
1702
+ } else {
1703
+ bHighPriorityBannerEnabled = oFlagsData.highPriorityBannerEnabled;
1704
+ }
1705
+ oUserFlagsReadFromPersonalizationDeferred.resolve();
1706
+ })
1707
+ .catch(() => {
1708
+ Log.error("Reading User Settings flags from Personalization service failed");
1709
+ });
1710
+ })
1711
+ .catch((error) => {
1712
+ Log.error("Personalization service does not work:");
1713
+ Log.error(error.name + ": " + error.message);
1714
+ Log.error("Reading User Settings flags from Personalization service failed");
1715
+ });
1716
+ };
1717
+
1718
+ /**
1719
+ * Write/save user settings flags to the personalization.
1720
+ * The saved data consists of the user's show high-priority notifications alerts flag value.
1721
+ */
1722
+ this._writeUserSettingsFlagsToPersonalization = function (oFlags) {
1723
+ return this._getUserSettingsPersonalizer()
1724
+ .then((oPersonalizer) => oPersonalizer.setPersData(oFlags))
1725
+ .catch((error) => {
1726
+ Log.error("Personalization service does not work:");
1727
+ Log.error(error.name + ": " + error.message);
1728
+ });
1729
+ };
1730
+
1731
+ this._getUserSettingsPersonalizer = function () {
1732
+ if (!this.oUserSettingsPersonalizerPromise) {
1733
+ this.oUserSettingsPersonalizerPromise = sap.ushell.Container.getServiceAsync("PersonalizationV2")
1734
+ .then((PersonalizationService) => {
1735
+ const oScope = {
1736
+ keyCategory: PersonalizationService.constants.keyCategory.FIXED_KEY,
1737
+ writeFrequency: PersonalizationService.constants.writeFrequency.LOW,
1738
+ clientStorageAllowed: true
1739
+ };
1740
+
1741
+ const oPersId = {
1742
+ container: "sap.ushell.services.Notifications",
1743
+ item: "userSettingsData"
1744
+ };
1745
+
1746
+ return PersonalizationService.getPersonalizer(oPersId, oScope);
1747
+ });
1748
+ }
1749
+
1750
+ return this.oUserSettingsPersonalizerPromise;
1751
+ };
1752
+
1753
+ this._updateCSRF = function (oResponseData) {
1754
+ if ((bCsrfDataSet === true) || (oResponseData.headers === undefined)) {
1755
+ return;
1756
+ }
1757
+ if (!this._getHeaderXcsrfToken()) {
1758
+ sHeaderXcsrfToken = oResponseData.headers["x-csrf-token"] || oResponseData.headers["X-CSRF-Token"] || oResponseData.headers["X-Csrf-Token"];
1759
+ }
1760
+ if (!this._getDataServiceVersion()) {
1761
+ sDataServiceVersion = oResponseData.headers.DataServiceVersion || oResponseData.headers["odata-version"];
1762
+ }
1763
+ bCsrfDataSet = true;
1764
+ };
1765
+
1766
+ /**
1767
+ * Handles all the required steps in order to initialize Notification Settings UI
1768
+ *
1769
+ * Issues two calls to the Notifications channel backend system in order to check whether settings feature and Push to Mobile features are supported
1770
+ */
1771
+ this._userSettingInitialization = function () {
1772
+ // Contains three boolean flags:
1773
+ // - settingsAvailable: Is the settings feature supported by the notification channel backend system
1774
+ // - mobileAvailable: Is the "push to mobile" feature supported by the notification channel backend system
1775
+ // - emailAvailable: Is the "send email" feature supported by the notification channel backend system
1776
+ const oSettingsStatus = {
1777
+ settingsAvailable: false,
1778
+ mobileAvailable: false,
1779
+ emailAvailable: false
1780
+ };
1781
+
1782
+ // Read the part of user settings data that is kept in personalization service
1783
+ this._readUserSettingsFlagsFromPersonalization();
1784
+
1785
+ // 1st asynchronous call: Get setting data from the backend, for the purpose of verifying that the feature is supported
1786
+ const oSettingsPromise = this.readSettings();
1787
+ // 2nd asynchronous call: verify Push To Mobile capability
1788
+ const oMobileSettingsPromise = this._readMobileSettingsFromServer();
1789
+ const oEmailSettingsPromise = this._readEmailSettingsFromServer();
1790
+
1791
+ const aPromises = [oSettingsPromise, oMobileSettingsPromise, oEmailSettingsPromise];
1792
+
1793
+ oSettingsPromise.then(() => {
1794
+ // Notification setting supported
1795
+ oSettingsStatus.settingsAvailable = true;
1796
+ }).catch(() => {
1797
+ Log.warning("User settings for the Notification service are not available.");
1798
+ oNotificationSettingsAvailabilityDeferred.promise().catch(() => { });
1799
+ oNotificationSettingsAvailabilityDeferred.reject();
1800
+ });
1801
+
1802
+ oMobileSettingsPromise.then((oResult) => {
1803
+ const oResponseObject = JSON.parse(oResult);
1804
+ // Push to Mobile validation returned
1805
+ if (oResponseObject.successStatus) {
1806
+ bNotificationSettingsMobileSupport = oResult ? oResponseObject.IsActive : false;
1807
+ oSettingsStatus.mobileAvailable = bNotificationSettingsMobileSupport;
1808
+ } else {
1809
+ bNotificationSettingsMobileSupport = false;
1810
+ oSettingsStatus.mobileAvailable = false;
1811
+ }
1812
+ }).catch(() => {
1813
+ Log.warning("Mobile settings for the Notification service are not available.");
1814
+ bNotificationSettingsMobileSupport = false;
1815
+ oSettingsStatus.mobileAvailable = false;
1816
+ });
1817
+
1818
+ oEmailSettingsPromise.then((oResult) => {
1819
+ const oResponseObject = JSON.parse(oResult);
1820
+ if (oResponseObject.successStatus) {
1821
+ bNotificationSettingsEmailSupport = oResult ? oResponseObject.IsActive : false;
1822
+ oSettingsStatus.emailAvailable = bNotificationSettingsEmailSupport;
1823
+ } else {
1824
+ bNotificationSettingsEmailSupport = false;
1825
+ oSettingsStatus.emailAvailable = false;
1826
+ }
1827
+ }).catch(() => {
1828
+ Log.warning("Email settings for the Notification service are not available.");
1829
+ bNotificationSettingsEmailSupport = false;
1830
+ oSettingsStatus.emailAvailable = false;
1831
+ });
1832
+
1833
+ // Resolve the deferred object on which the setting UI depends after the two OData calls returned, no matter if they were successful or not
1834
+ Promise.all(aPromises).then(() => {
1835
+ // After both calls returned - the deferred object (on which the rendering of Notification Settings UI depends) is resolved
1836
+ oNotificationSettingsAvailabilityDeferred.resolve(oSettingsStatus);
1837
+ }).catch(() => Log.warning("Settings for the Notification service are not loaded completely."));
1838
+ };
1839
+
1840
+ /**
1841
+ * Used to close all notification connection. In order to resume connection use _resumeConnection method
1842
+ * @private
1843
+ */
1844
+ this._closeConnection = function () {
1845
+ if (!bOnServiceStop) {
1846
+ if (oCurrentMode === oModesEnum.WEB_SOCKET && oWebSocket) {
1847
+ oWebSocket.close();
1848
+ bOnServiceStop = true;
1849
+ }
1850
+ if (oCurrentMode === oModesEnum.POLLING && pollingTimer) {
1851
+ window.clearTimeout(pollingTimer);
1852
+ bOnServiceStop = true;
1853
+ }
1854
+ }
1855
+ };
1856
+
1857
+ /**
1858
+ * Used to open closed notification connection. Firstly, try to re-establish the websocket connection.
1859
+ * If the websocket connection can not be established, the polling start automatically after failed attempt
1860
+ * @private
1861
+ */
1862
+ this._resumeConnection = function () {
1863
+ if (bOnServiceStop) {
1864
+ bOnServiceStop = false;
1865
+ this._webSocketStep();
1866
+ }
1867
+ };
1868
+ }
1869
+
1870
+ Notifications.hasNoAdapter = true;
1871
+ return Notifications;
1872
+ }, true /* bExport */);