@sapui5/sap.fe.core 1.95.0 → 1.98.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 (207) hide show
  1. package/package.json +5 -5
  2. package/src/sap/fe/core/.library +1 -1
  3. package/src/sap/fe/core/AnnotationHelper.js +3 -3
  4. package/src/sap/fe/core/AppComponent.js +9 -44
  5. package/src/sap/fe/core/AppStateHandler.js +2 -2
  6. package/src/sap/fe/core/BaseController.js +1 -1
  7. package/src/sap/fe/core/BusyLocker.js +13 -1
  8. package/src/sap/fe/core/CommonUtils.js +129 -219
  9. package/src/sap/fe/core/ExtensionAPI.js +14 -6
  10. package/src/sap/fe/core/PageController.js +9 -35
  11. package/src/sap/fe/core/RouterProxy.js +79 -75
  12. package/src/sap/fe/core/Synchronization.js +1 -1
  13. package/src/sap/fe/core/TemplateComponent.js +16 -7
  14. package/src/sap/fe/core/TemplateModel.js +1 -1
  15. package/src/sap/fe/core/TransactionHelper.js +183 -65
  16. package/src/sap/fe/core/actions/draft.js +50 -23
  17. package/src/sap/fe/core/actions/messageHandling.js +86 -7
  18. package/src/sap/fe/core/actions/nonDraft.js +1 -1
  19. package/src/sap/fe/core/actions/operations.js +75 -33
  20. package/src/sap/fe/core/actions/sticky.js +1 -1
  21. package/src/sap/fe/core/controllerextensions/ControllerExtensionMetadata.js +1 -1
  22. package/src/sap/fe/core/controllerextensions/EditFlow.js +276 -122
  23. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.js +1 -1
  24. package/src/sap/fe/core/controllerextensions/InternalEditFlow.js +14 -6
  25. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +90 -46
  26. package/src/sap/fe/core/controllerextensions/InternalRouting.js +234 -232
  27. package/src/sap/fe/core/controllerextensions/KPIManagement.js +539 -209
  28. package/src/sap/fe/core/controllerextensions/KPIManagement.ts +550 -213
  29. package/src/sap/fe/core/controllerextensions/MassEdit.js +79 -0
  30. package/src/sap/fe/core/controllerextensions/MessageHandler.js +227 -103
  31. package/src/sap/fe/core/controllerextensions/PageReady.js +2 -2
  32. package/src/sap/fe/core/controllerextensions/PageReady.ts +3 -7
  33. package/src/sap/fe/core/controllerextensions/Paginator.js +38 -12
  34. package/src/sap/fe/core/controllerextensions/Placeholder.js +16 -19
  35. package/src/sap/fe/core/controllerextensions/Routing.js +17 -2
  36. package/src/sap/fe/core/controllerextensions/RoutingListener.js +1 -1
  37. package/src/sap/fe/core/controllerextensions/Share.js +20 -7
  38. package/src/sap/fe/core/controllerextensions/SideEffects.js +8 -9
  39. package/src/sap/fe/core/controllerextensions/SideEffects.ts +19 -17
  40. package/src/sap/fe/core/controllerextensions/ViewState.js +54 -9
  41. package/src/sap/fe/core/controls/ActionParameterDialog.fragment.xml +40 -34
  42. package/src/sap/fe/core/controls/ActionParameterDialogValueHelp.fragment.xml +35 -0
  43. package/src/sap/fe/core/controls/CommandExecution.js +1 -1
  44. package/src/sap/fe/core/controls/ConditionalWrapper.js +1 -1
  45. package/src/sap/fe/core/controls/CustomQuickViewPage.js +110 -109
  46. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.js +7 -4
  47. package/src/sap/fe/core/controls/FieldWrapper.js +10 -4
  48. package/src/sap/fe/core/controls/FilterBar.js +1 -1
  49. package/src/sap/fe/core/controls/FormElementWrapper.js +1 -6
  50. package/src/sap/fe/core/controls/MultiValueParameterDelegate.js +45 -0
  51. package/src/sap/fe/core/controls/NonComputedVisibleKeyFieldsDialog.fragment.xml +1 -1
  52. package/src/sap/fe/core/controls/filterbar/FilterContainer.js +1 -1
  53. package/src/sap/fe/core/controls/filterbar/VisualFilter.js +1 -1
  54. package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.js +1 -1
  55. package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.js +1 -1
  56. package/src/sap/fe/core/controls/massEdit/MassEditDialog.fragment.xml +106 -0
  57. package/src/sap/fe/core/controls/massEdit/MassEditHandlers.js +78 -0
  58. package/src/sap/fe/core/converters/ConverterContext.js +13 -1
  59. package/src/sap/fe/core/converters/ConverterContext.ts +10 -0
  60. package/src/sap/fe/core/converters/ManifestSettings.js +2 -1
  61. package/src/sap/fe/core/converters/ManifestSettings.ts +7 -1
  62. package/src/sap/fe/core/converters/ManifestWrapper.js +18 -7
  63. package/src/sap/fe/core/converters/ManifestWrapper.ts +15 -6
  64. package/src/sap/fe/core/converters/MetaModelConverter.js +920 -882
  65. package/src/sap/fe/core/converters/MetaModelConverter.ts +829 -853
  66. package/src/sap/fe/core/converters/annotations/DataField.js +54 -4
  67. package/src/sap/fe/core/converters/annotations/DataField.ts +53 -3
  68. package/src/sap/fe/core/converters/common/AnnotationConverter.js +83 -48
  69. package/src/sap/fe/core/converters/controls/Common/Action.js +15 -3
  70. package/src/sap/fe/core/converters/controls/Common/Action.ts +12 -3
  71. package/src/sap/fe/core/converters/controls/Common/Chart.js +1 -3
  72. package/src/sap/fe/core/converters/controls/Common/Chart.ts +0 -2
  73. package/src/sap/fe/core/converters/controls/Common/Form.js +68 -21
  74. package/src/sap/fe/core/converters/controls/Common/Form.ts +60 -16
  75. package/src/sap/fe/core/converters/controls/Common/KPI.js +331 -248
  76. package/src/sap/fe/core/converters/controls/Common/KPI.ts +355 -287
  77. package/src/sap/fe/core/converters/controls/Common/Table.js +426 -332
  78. package/src/sap/fe/core/converters/controls/Common/Table.ts +516 -383
  79. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +468 -0
  80. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +609 -0
  81. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +30 -13
  82. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +31 -12
  83. package/src/sap/fe/core/converters/controls/ListReport/VisualFilters.js +2 -2
  84. package/src/sap/fe/core/converters/controls/ListReport/VisualFilters.ts +1 -1
  85. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +15 -7
  86. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +27 -6
  87. package/src/sap/fe/core/converters/helpers/Aggregation.js +8 -1
  88. package/src/sap/fe/core/converters/helpers/Aggregation.ts +9 -1
  89. package/src/sap/fe/core/converters/helpers/BindingHelper.js +3 -2
  90. package/src/sap/fe/core/converters/helpers/BindingHelper.ts +2 -2
  91. package/src/sap/fe/core/converters/helpers/ID.js +9 -1
  92. package/src/sap/fe/core/converters/helpers/ID.ts +6 -2
  93. package/src/sap/fe/core/converters/helpers/IssueManager.js +7 -5
  94. package/src/sap/fe/core/converters/helpers/IssueManager.ts +6 -4
  95. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +2 -2
  96. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +1 -1
  97. package/src/sap/fe/core/converters/templates/ListReportConverter.js +34 -4
  98. package/src/sap/fe/core/converters/templates/ListReportConverter.ts +36 -7
  99. package/src/sap/fe/core/converters/templates/ObjectPageConverter.js +2 -5
  100. package/src/sap/fe/core/converters/templates/ObjectPageConverter.ts +1 -2
  101. package/src/sap/fe/core/designtime/AppComponent.designtime.js +11 -2
  102. package/src/sap/fe/core/formatters/FPMFormatter.js +1 -1
  103. package/src/sap/fe/core/formatters/FPMFormatter.ts +8 -3
  104. package/src/sap/fe/core/formatters/TableFormatter.js +27 -4
  105. package/src/sap/fe/core/formatters/TableFormatter.ts +20 -3
  106. package/src/sap/fe/core/formatters/ValueFormatter.js +30 -5
  107. package/src/sap/fe/core/formatters/ValueFormatter.ts +25 -3
  108. package/src/sap/fe/core/fpm/Component.js +2 -2
  109. package/src/sap/fe/core/helpers/AppStartupHelper.js +359 -0
  110. package/src/sap/fe/core/helpers/AppStartupHelper.ts +388 -0
  111. package/src/sap/fe/core/helpers/BindingExpression.js +199 -111
  112. package/src/sap/fe/core/helpers/BindingExpression.ts +193 -102
  113. package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.js +1 -1
  114. package/src/sap/fe/core/helpers/EditState.js +1 -1
  115. package/src/sap/fe/core/helpers/ExcelFormatHelper.js +1 -3
  116. package/src/sap/fe/core/helpers/FPMHelper.js +1 -1
  117. package/src/sap/fe/core/helpers/KeepAliveHelper.js +211 -0
  118. package/src/sap/fe/core/helpers/KeepAliveHelper.ts +202 -0
  119. package/src/sap/fe/core/helpers/KeepAliveRefreshTypes.js +32 -0
  120. package/src/sap/fe/core/helpers/KeepAliveRefreshTypes.ts +36 -0
  121. package/src/sap/fe/core/helpers/MassEditHelper.js +678 -0
  122. package/src/sap/fe/core/helpers/ModelHelper.js +64 -1
  123. package/src/sap/fe/core/helpers/PasteHelper.js +7 -1
  124. package/src/sap/fe/core/helpers/SemanticDateOperators.js +1 -1
  125. package/src/sap/fe/core/helpers/SemanticKeyHelper.js +1 -1
  126. package/src/sap/fe/core/helpers/StableIdHelper.js +2 -2
  127. package/src/sap/fe/core/helpers/StableIdHelper.ts +1 -1
  128. package/src/sap/fe/core/library.js +28 -2
  129. package/src/sap/fe/core/library.support.js +10 -4
  130. package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.js +62 -0
  131. package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.ts +66 -0
  132. package/src/sap/fe/core/messagebundle.properties +67 -3
  133. package/src/sap/fe/core/messagebundle_ar.properties +40 -3
  134. package/src/sap/fe/core/messagebundle_bg.properties +40 -3
  135. package/src/sap/fe/core/messagebundle_ca.properties +41 -4
  136. package/src/sap/fe/core/messagebundle_cs.properties +41 -4
  137. package/src/sap/fe/core/messagebundle_cy.properties +40 -3
  138. package/src/sap/fe/core/messagebundle_da.properties +40 -3
  139. package/src/sap/fe/core/messagebundle_de.properties +40 -3
  140. package/src/sap/fe/core/messagebundle_el.properties +40 -3
  141. package/src/sap/fe/core/messagebundle_en.properties +37 -0
  142. package/src/sap/fe/core/messagebundle_en_GB.properties +37 -0
  143. package/src/sap/fe/core/messagebundle_en_US_sappsd.properties +37 -0
  144. package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +46 -2
  145. package/src/sap/fe/core/messagebundle_en_US_saptrc.properties +44 -0
  146. package/src/sap/fe/core/messagebundle_es.properties +40 -3
  147. package/src/sap/fe/core/messagebundle_es_MX.properties +41 -4
  148. package/src/sap/fe/core/messagebundle_et.properties +40 -3
  149. package/src/sap/fe/core/messagebundle_fi.properties +40 -3
  150. package/src/sap/fe/core/messagebundle_fr.properties +41 -4
  151. package/src/sap/fe/core/messagebundle_fr_CA.properties +40 -3
  152. package/src/sap/fe/core/messagebundle_hi.properties +40 -3
  153. package/src/sap/fe/core/messagebundle_hr.properties +40 -3
  154. package/src/sap/fe/core/messagebundle_hu.properties +41 -4
  155. package/src/sap/fe/core/messagebundle_id.properties +42 -5
  156. package/src/sap/fe/core/messagebundle_it.properties +40 -3
  157. package/src/sap/fe/core/messagebundle_iw.properties +40 -3
  158. package/src/sap/fe/core/messagebundle_ja.properties +49 -12
  159. package/src/sap/fe/core/messagebundle_kk.properties +40 -3
  160. package/src/sap/fe/core/messagebundle_ko.properties +40 -3
  161. package/src/sap/fe/core/messagebundle_lt.properties +40 -3
  162. package/src/sap/fe/core/messagebundle_lv.properties +40 -3
  163. package/src/sap/fe/core/messagebundle_ms.properties +40 -3
  164. package/src/sap/fe/core/messagebundle_nl.properties +40 -3
  165. package/src/sap/fe/core/messagebundle_no.properties +40 -3
  166. package/src/sap/fe/core/messagebundle_pl.properties +40 -3
  167. package/src/sap/fe/core/messagebundle_pt.properties +42 -5
  168. package/src/sap/fe/core/messagebundle_pt_PT.properties +40 -3
  169. package/src/sap/fe/core/messagebundle_ro.properties +40 -3
  170. package/src/sap/fe/core/messagebundle_ru.properties +40 -3
  171. package/src/sap/fe/core/messagebundle_sh.properties +40 -3
  172. package/src/sap/fe/core/messagebundle_sk.properties +40 -3
  173. package/src/sap/fe/core/messagebundle_sl.properties +40 -3
  174. package/src/sap/fe/core/messagebundle_sv.properties +41 -4
  175. package/src/sap/fe/core/messagebundle_th.properties +40 -3
  176. package/src/sap/fe/core/messagebundle_tr.properties +40 -3
  177. package/src/sap/fe/core/messagebundle_uk.properties +40 -3
  178. package/src/sap/fe/core/messagebundle_vi.properties +40 -3
  179. package/src/sap/fe/core/messagebundle_zh_CN.properties +40 -3
  180. package/src/sap/fe/core/messagebundle_zh_TW.properties +40 -3
  181. package/src/sap/fe/core/services/AsyncComponentServiceFactory.js +1 -1
  182. package/src/sap/fe/core/services/CacheHandlerServiceFactory.js +1 -1
  183. package/src/sap/fe/core/services/EnvironmentServiceFactory.js +4 -3
  184. package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +3 -0
  185. package/src/sap/fe/core/services/NavigationServiceFactory.js +1 -1
  186. package/src/sap/fe/core/services/ResourceModelServiceFactory.js +1 -1
  187. package/src/sap/fe/core/services/RoutingServiceFactory.js +98 -328
  188. package/src/sap/fe/core/services/ShellServicesFactory.js +31 -2
  189. package/src/sap/fe/core/services/ShellServicesFactory.ts +30 -1
  190. package/src/sap/fe/core/services/SideEffectsServiceFactory.js +8 -5
  191. package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +11 -6
  192. package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +14 -5
  193. package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.js +1 -1
  194. package/src/sap/fe/core/support/InvalidAnnotationColumnKey.support.js +38 -0
  195. package/src/sap/fe/core/support/InvalidAnnotationColumnKey.support.ts +18 -0
  196. package/src/sap/fe/core/templating/DataModelPathHelper.js +8 -37
  197. package/src/sap/fe/core/templating/DataModelPathHelper.ts +13 -33
  198. package/src/sap/fe/core/templating/DisplayModeFormatter.js +114 -0
  199. package/src/sap/fe/core/templating/DisplayModeFormatter.ts +86 -0
  200. package/src/sap/fe/core/templating/EntitySetHelper.js +86 -3
  201. package/src/sap/fe/core/templating/EntitySetHelper.ts +44 -0
  202. package/src/sap/fe/core/templating/FilterHelper.js +10 -7
  203. package/src/sap/fe/core/templating/FilterHelper.ts +8 -6
  204. package/src/sap/fe/core/templating/PropertyHelper.js +2 -2
  205. package/src/sap/fe/core/templating/PropertyHelper.ts +1 -1
  206. package/src/sap/fe/core/templating/UIFormatters.js +47 -107
  207. package/src/sap/fe/core/templating/UIFormatters.ts +76 -72
@@ -0,0 +1,388 @@
1
+ import { ODataModel, ODataMetaModel, Context } from "sap/ui/model/odata/v4";
2
+ import { Filter, FilterOperator } from "sap/ui/model";
3
+ import { Router } from "sap/ui/core/routing";
4
+ import { ModelHelper } from "sap/fe/core/helpers";
5
+
6
+ type ValuedKey = {
7
+ name: string;
8
+ value: string;
9
+ };
10
+
11
+ type PageInfo = {
12
+ pattern: string;
13
+ contextPath: string;
14
+ draftMode: Boolean;
15
+ technicalKeys: ValuedKey[] | undefined;
16
+ semanticKeys: ValuedKey[] | undefined;
17
+ target: string;
18
+ };
19
+
20
+ /**
21
+ * Retrieves a set of key values from startup parameters.
22
+ *
23
+ * @param aKeyNames The array of key names
24
+ * @param oStartupParameters The startup parameters
25
+ * @returns An array of pairs {name, value} if all key values could be found in the startup parameters, undefined otherwise
26
+ */
27
+ function _getKeysFromStartupParams(aKeyNames: string[], oStartupParameters: any): ValuedKey[] | undefined {
28
+ let bAllFound = true;
29
+ const aKeys = aKeyNames.map(name => {
30
+ if (oStartupParameters[name] && oStartupParameters[name].length === 1) {
31
+ return { name, value: oStartupParameters[name][0] as string };
32
+ } else {
33
+ // A unique key value couldn't be found in the startup parameters
34
+ bAllFound = false;
35
+ return { name, value: "" };
36
+ }
37
+ });
38
+
39
+ return bAllFound ? aKeys : undefined;
40
+ }
41
+
42
+ /**
43
+ * Creates a filter from a list of key values.
44
+ *
45
+ * @param aKeys Array of semantic keys or technical keys (with values)
46
+ * @param bDraftMode True if the entity supports draft mode
47
+ * @param oMetaModel The metamodel
48
+ * @returns The filter
49
+ */
50
+ function _createFilterFromKeys(aKeys: ValuedKey[], bDraftMode: Boolean, oMetaModel: ODataMetaModel): Filter {
51
+ const bFilterCaseSensitive = ModelHelper.isFilteringCaseSensitive(oMetaModel);
52
+
53
+ let bFilterOnActiveEntity = false;
54
+ const aFilters = aKeys.map(key => {
55
+ if (key.name === "IsActiveEntity") {
56
+ bFilterOnActiveEntity = true;
57
+ }
58
+ return new Filter({
59
+ path: key.name,
60
+ operator: FilterOperator.EQ,
61
+ value1: key.value,
62
+ caseSensitive: bFilterCaseSensitive
63
+ });
64
+ });
65
+ if (bDraftMode && !bFilterOnActiveEntity) {
66
+ const oDraftFilter = new Filter({
67
+ filters: [new Filter("IsActiveEntity", "EQ", false), new Filter("SiblingEntity/IsActiveEntity", "EQ", null)],
68
+ and: false
69
+ });
70
+ aFilters.push(oDraftFilter);
71
+ }
72
+
73
+ return new Filter(aFilters, true);
74
+ }
75
+
76
+ /**
77
+ * Loads all contexts for a list of page infos.
78
+ *
79
+ * @param aStartupPages The list of page infos
80
+ * @param oModel The model used to load the contexts
81
+ * @returns A Promise for all contexts
82
+ */
83
+ function _requestObjectsFromParameters(aStartupPages: PageInfo[], oModel: ODataModel): Promise<Context[][]> {
84
+ // Load the respective objects for all object pages found in aExternallyNavigablePages
85
+ const aContextPromises = aStartupPages.map(pageInfo => {
86
+ const aKeys = pageInfo.semanticKeys || pageInfo.technicalKeys || [];
87
+ const oFilter = _createFilterFromKeys(aKeys, pageInfo.draftMode, oModel.getMetaModel());
88
+
89
+ // only request a minimum of fields to boost backend performance since this is only used to check if an object exists
90
+ const oListBind = oModel.bindList(pageInfo.contextPath, undefined, undefined, oFilter, {
91
+ "$select": aKeys
92
+ .map(key => {
93
+ return key.name;
94
+ })
95
+ .join(",")
96
+ } as any);
97
+ return oListBind.requestContexts(0, 2);
98
+ });
99
+
100
+ return Promise.all(aContextPromises);
101
+ }
102
+
103
+ /**
104
+ * Returns the list of all pages that allow deeplink and that can be reached using the startup parameters.
105
+ *
106
+ * @param oManifestRouting The routing information from the app manifest
107
+ * @param oStartupParameters The startup parameters
108
+ * @param oMetaModel The metamodel
109
+ * @returns
110
+ */
111
+ function _getReachablePages(oManifestRouting: any, oStartupParameters: any, oMetaModel: ODataMetaModel): PageInfo[][] {
112
+ const aRoutes: any[] = oManifestRouting.routes;
113
+ const mPagesByLevel: Record<number, PageInfo[]> = {};
114
+
115
+ aRoutes.forEach(oRoute => {
116
+ let sPattern: string = oRoute.pattern.replace(":?query:", "");
117
+ if (sPattern.endsWith("/")) {
118
+ sPattern = sPattern.substr(0, sPattern.length - 1);
119
+ }
120
+
121
+ if (sPattern) {
122
+ // Ignore level-0 routes (ListReport)
123
+ sPattern = sPattern.replace(/\(\{[^\}]*\}\)/g, "(#)"); // Replace keys with #
124
+
125
+ // Get the rightmost target for this route
126
+ const sTargetName: string = Array.isArray(oRoute.target) ? oRoute.target[oRoute.target.length - 1] : oRoute.target;
127
+ const oTarget = oManifestRouting.targets[sTargetName];
128
+
129
+ const aPatternSegments = sPattern.split("/");
130
+ const pageLevel = aPatternSegments.length - 1;
131
+
132
+ // The first level of object page allows deep linking by default.
133
+ // Otherwise, the target must allow deep linking explicitely in the manifest
134
+ if (pageLevel === 0 || oTarget?.options?.settings?.allowDeepLinking) {
135
+ const sContextPath: string =
136
+ oTarget.options.settings.contextPath ||
137
+ (oTarget.options.settings.entitySet && "/" + oTarget.options.settings.entitySet);
138
+ const oEntityType = sContextPath && oMetaModel.getObject("/$EntityContainer" + sContextPath + "/");
139
+
140
+ if (oEntityType) {
141
+ // Get the semantic key values for the entity
142
+ const aSemanticKeyNames: any = oMetaModel.getObject(
143
+ "/$EntityContainer" + sContextPath + "/@com.sap.vocabularies.Common.v1.SemanticKey"
144
+ );
145
+ const aSemantickKeys = aSemanticKeyNames
146
+ ? _getKeysFromStartupParams(
147
+ aSemanticKeyNames.map((semKey: any) => {
148
+ return semKey.$PropertyPath as string;
149
+ }),
150
+ oStartupParameters
151
+ )
152
+ : undefined;
153
+
154
+ // Get the technical keys only if we couldn't find the semantic key values, and on first level OP
155
+ const aTechnicalKeys =
156
+ !aSemantickKeys && pageLevel === 0 ? _getKeysFromStartupParams(oEntityType["$Key"], oStartupParameters) : undefined;
157
+
158
+ if (aSemantickKeys || aTechnicalKeys) {
159
+ // The startup parameters contain values for all semantic keys (or technical keys) --> we can store the page info in the corresponding level
160
+ const draftMode =
161
+ oMetaModel.getObject("/$EntityContainer" + sContextPath + "@com.sap.vocabularies.Common.v1.DraftRoot") ||
162
+ oMetaModel.getObject("/$EntityContainer" + sContextPath + "@com.sap.vocabularies.Common.v1.DraftNode")
163
+ ? true
164
+ : false;
165
+
166
+ if (!mPagesByLevel[pageLevel]) {
167
+ mPagesByLevel[pageLevel] = [];
168
+ }
169
+ mPagesByLevel[pageLevel].push({
170
+ pattern: sPattern,
171
+ contextPath: sContextPath,
172
+ draftMode,
173
+ technicalKeys: aTechnicalKeys,
174
+ semanticKeys: aSemantickKeys,
175
+ target: sTargetName
176
+ });
177
+ }
178
+ }
179
+ }
180
+ }
181
+ });
182
+
183
+ // A page is reachable only if all its parents are also reachable
184
+ // So if we couldn't find any pages for a given level, all pages with a higher level won't be reachable anyway
185
+ const aReachablePages: PageInfo[][] = [];
186
+ let level = 0;
187
+ while (mPagesByLevel[level]) {
188
+ aReachablePages.push(mPagesByLevel[level]);
189
+ level++;
190
+ }
191
+
192
+ return aReachablePages;
193
+ }
194
+
195
+ /**
196
+ * Get the list of startup pages.
197
+ *
198
+ * @param oManifestRouting The routing information from the app manifest
199
+ * @param oStartupParameters The startup parameters
200
+ * @param oMetaModel The metamodel
201
+ * @returns An array of startup page infos
202
+ */
203
+ function _getStartupPagesFromStartupParams(oManifestRouting: any, oStartupParameters: any, oMetaModel: ODataMetaModel): PageInfo[] {
204
+ // Find all pages that can be reached with the startup parameters
205
+ const aReachablePages = _getReachablePages(oManifestRouting, oStartupParameters, oMetaModel);
206
+
207
+ if (aReachablePages.length === 0) {
208
+ return [];
209
+ }
210
+
211
+ // Find the longest sequence of pages that can be reached (recursively)
212
+ let result: PageInfo[] = [];
213
+ const current: PageInfo[] = [];
214
+
215
+ function findRecursive(level: number) {
216
+ const aCurrentLevelPages = aReachablePages[level];
217
+ const lastPage = current.length ? current[current.length - 1] : undefined;
218
+
219
+ if (aCurrentLevelPages) {
220
+ aCurrentLevelPages.forEach(function(nextPage) {
221
+ if (!lastPage || nextPage.pattern.indexOf(lastPage.pattern) === 0) {
222
+ // We only consider pages that can be reached from the page at the previous level,
223
+ // --> their pattern must be the pattern of the previous page with another segment appended
224
+ current.push(nextPage);
225
+ findRecursive(level + 1);
226
+ current.pop();
227
+ }
228
+ });
229
+ }
230
+ if (current.length > result.length) {
231
+ result = current.slice(); // We have found a sequence longer than our previous best --> store it as the new longest
232
+ }
233
+ }
234
+
235
+ findRecursive(0);
236
+
237
+ return result;
238
+ }
239
+
240
+ /**
241
+ * Creates the startup object from the list of pages and contexts.
242
+ *
243
+ * @param aStartupPages The pages
244
+ * @param aContexts The contexts
245
+ * @returns An object containing either a hash or a context to navigate to, or an empty object if no deep link was found
246
+ */
247
+ function _getDeepLinkObject(aStartupPages: PageInfo[], aContexts: Context[]): { hash?: string; context?: Context } {
248
+ if (aContexts.length === 1) {
249
+ return { context: aContexts[0] };
250
+ } else if (aContexts.length > 1) {
251
+ // Navigation to a deeper level --> use the pattern of the deepest object page
252
+ // and replace the parameters by the ID from the contexts
253
+ let hash = aStartupPages[aStartupPages.length - 1].pattern;
254
+ aContexts.forEach(function(oContext) {
255
+ hash = hash.replace("(#)", "(" + oContext.getPath().split("(")[1]);
256
+ });
257
+
258
+ return { hash };
259
+ } else {
260
+ return {};
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Calculates startup parameters for a deeplink case, from startup parameters and routing infoirmation.
266
+ *
267
+ * @param oManifestRouting The routing information from the app manifest
268
+ * @param oStartupParameters The startup parameters
269
+ * @param oModel The OData model
270
+ * @returns An object containing either a hash or a context to navigate to, or an empty object if no deep link was found
271
+ */
272
+ function getDeepLinkStartupHash(
273
+ oManifestRouting: any,
274
+ oStartupParameters: any,
275
+ oModel: ODataModel
276
+ ): Promise<{ hash?: string; context?: Context }> {
277
+ let aStartupPages: PageInfo[];
278
+
279
+ return oModel
280
+ .getMetaModel()
281
+ .requestObject("/$EntityContainer/")
282
+ .then(() => {
283
+ // Check if semantic keys are present in url parameters for every object page at each level
284
+ aStartupPages = _getStartupPagesFromStartupParams(oManifestRouting, oStartupParameters, oModel.getMetaModel());
285
+
286
+ return _requestObjectsFromParameters(aStartupPages, oModel);
287
+ })
288
+ .then((aValues: Context[][]) => {
289
+ if (aValues.length) {
290
+ // Make sure we only get 1 context per promise, and flatten the array
291
+ const aContexts: Context[] = [];
292
+ aValues.forEach(function(aFoundContexts) {
293
+ if (aFoundContexts.length === 1) {
294
+ aContexts.push(aFoundContexts[0]);
295
+ }
296
+ });
297
+
298
+ return aContexts.length === aValues.length ? _getDeepLinkObject(aStartupPages, aContexts) : {};
299
+ } else {
300
+ return {};
301
+ }
302
+ });
303
+ }
304
+
305
+ /**
306
+ * Calculates the new hash based on the startup parameters.
307
+ *
308
+ * @param oStartupParameters The startup parameter values (map parameter name -> array of values)
309
+ * @param sContextPath The context path for the startup of the app (generally the path to the main entity set)
310
+ * @param oRouter The router instance
311
+ * @param oMetaModel The meta model
312
+ * @returns A promise containing the hash to navigate to, or an empty string if there's no need to navigate
313
+ */
314
+ function getCreateStartupHash(oStartupParameters: any, sContextPath: string, oRouter: Router, oMetaModel: ODataMetaModel): Promise<String> {
315
+ return oMetaModel.requestObject(sContextPath + "@").then(function(oEntitySetAnnotations: any) {
316
+ let sMetaPath = "";
317
+ let bCreatable = true;
318
+
319
+ if (
320
+ oEntitySetAnnotations["@com.sap.vocabularies.Common.v1.DraftRoot"] &&
321
+ oEntitySetAnnotations["@com.sap.vocabularies.Common.v1.DraftRoot"]["NewAction"]
322
+ ) {
323
+ sMetaPath = sContextPath + "@com.sap.vocabularies.Common.v1.DraftRoot/NewAction@Org.OData.Core.V1.OperationAvailable";
324
+ } else if (
325
+ oEntitySetAnnotations["@com.sap.vocabularies.Session.v1.StickySessionSupported"] &&
326
+ oEntitySetAnnotations["@com.sap.vocabularies.Session.v1.StickySessionSupported"]["NewAction"]
327
+ ) {
328
+ sMetaPath =
329
+ sContextPath + "@com.sap.vocabularies.Session.v1.StickySessionSupported/NewAction@Org.OData.Core.V1.OperationAvailable";
330
+ }
331
+
332
+ if (sMetaPath) {
333
+ const bNewActionOperationAvailable = oMetaModel.getObject(sMetaPath);
334
+ if (bNewActionOperationAvailable === false) {
335
+ bCreatable = false;
336
+ }
337
+ } else {
338
+ const oInsertRestrictions = oEntitySetAnnotations["@Org.OData.Capabilities.V1.InsertRestrictions"];
339
+ if (oInsertRestrictions && oInsertRestrictions.Insertable === false) {
340
+ bCreatable = false;
341
+ }
342
+ }
343
+ if (bCreatable) {
344
+ return getDefaultCreateHash(oStartupParameters, sContextPath, oRouter);
345
+ } else {
346
+ return "";
347
+ }
348
+ });
349
+ }
350
+
351
+ /**
352
+ * Calculates the hash to create a new object.
353
+ *
354
+ * @param oStartupParameters The startup parameter values (map parameter name -> array of values)
355
+ * @param sContextPath The context path of the entity set to be used for the creation
356
+ * @param oRouter The router instance
357
+ * @returns The hash
358
+ */
359
+ function getDefaultCreateHash(oStartupParameters: any, sContextPath: string, oRouter: Router): string {
360
+ let sDefaultCreateHash =
361
+ oStartupParameters && oStartupParameters.preferredMode ? (oStartupParameters.preferredMode[0] as string) : "create";
362
+ let sHash = "";
363
+
364
+ sDefaultCreateHash =
365
+ sDefaultCreateHash.indexOf(":") !== -1 && sDefaultCreateHash.length > sDefaultCreateHash.indexOf(":") + 1
366
+ ? sDefaultCreateHash.substr(0, sDefaultCreateHash.indexOf(":"))
367
+ : "create";
368
+ sHash = sContextPath.substring(1) + "(...)?i-action=" + sDefaultCreateHash;
369
+ if (oRouter.getRouteInfoByHash(sHash)) {
370
+ return sHash;
371
+ } else {
372
+ throw new Error("No route match for creating a new " + sContextPath.substring(1));
373
+ }
374
+ }
375
+
376
+ const AppStartupHelper = {
377
+ _getKeysFromStartupParams,
378
+ _createFilterFromKeys,
379
+ _requestObjectsFromParameters,
380
+ _getReachablePages,
381
+ _getStartupPagesFromStartupParams,
382
+ _getDeepLinkObject,
383
+ getDeepLinkStartupHash,
384
+ getCreateStartupHash,
385
+ getDefaultCreateHash
386
+ };
387
+
388
+ export default AppStartupHelper;