create-ui5-freestyle-lr 0.2.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 (36) hide show
  1. package/README.md +141 -0
  2. package/package.json +34 -0
  3. package/src/cli.js +74 -0
  4. package/src/metadata/fetch.js +42 -0
  5. package/src/metadata/parse.js +104 -0
  6. package/src/prompts/basic.js +43 -0
  7. package/src/prompts/fields.js +144 -0
  8. package/src/prompts/odata.js +57 -0
  9. package/src/render/buildContext.js +67 -0
  10. package/src/render/controlForType.js +136 -0
  11. package/src/render/engine.js +81 -0
  12. package/src/templates/README.md.ejs +62 -0
  13. package/src/templates/_valueHelp.fragment.xml.ejs +17 -0
  14. package/src/templates/package.json.ejs +14 -0
  15. package/src/templates/ui5.yaml.ejs +28 -0
  16. package/src/templates/webapp/Component.js.ejs +47 -0
  17. package/src/templates/webapp/controller/App.controller.js +29 -0
  18. package/src/templates/webapp/controller/BaseController.js +35 -0
  19. package/src/templates/webapp/controller/ErrorHandler.js +71 -0
  20. package/src/templates/webapp/controller/NotFound.controller.js +12 -0
  21. package/src/templates/webapp/controller/Worklist.controller.js.ejs +1158 -0
  22. package/src/templates/webapp/css/style.css +17 -0
  23. package/src/templates/webapp/i18n/i18n.properties.ejs +83 -0
  24. package/src/templates/webapp/i18n/i18n_de.properties.ejs +83 -0
  25. package/src/templates/webapp/index.html.ejs +52 -0
  26. package/src/templates/webapp/localService/backendCheck.js.ejs +52 -0
  27. package/src/templates/webapp/localService/mockserver.js.ejs +29 -0
  28. package/src/templates/webapp/manifest.json.ejs +106 -0
  29. package/src/templates/webapp/model/formatter.js +148 -0
  30. package/src/templates/webapp/model/models.js +23 -0
  31. package/src/templates/webapp/view/App.view.xml +10 -0
  32. package/src/templates/webapp/view/NotFound.view.xml +12 -0
  33. package/src/templates/webapp/view/Worklist.view.xml.ejs +173 -0
  34. package/src/templates/webapp/view/fragments/GroupDialog.fragment.xml.ejs +11 -0
  35. package/src/templates/webapp/view/fragments/InfoPopover.fragment.xml +38 -0
  36. package/src/templates/webapp/view/fragments/SortDialog.fragment.xml.ejs +11 -0
@@ -0,0 +1,17 @@
1
+ html, body, body > .sapUiBody {
2
+ height: 100%;
3
+ }
4
+
5
+ .infoBarText {
6
+ font-style: italic;
7
+ }
8
+
9
+ .lrTable,
10
+ .lrTable .sapMListTbl,
11
+ .lrTable .sapMListTblCnt,
12
+ .lrTable .sapMListHdr,
13
+ .lrTable .sapMListHdrTBar,
14
+ .lrTable .sapMIBar,
15
+ .lrTable .sapMOTB {
16
+ border-radius: 0 !important;
17
+ }
@@ -0,0 +1,83 @@
1
+ # App
2
+ appTitle=<%= appTitle %>
3
+ appDescription=<%= appDescription %>
4
+ errorText=An unexpected error occurred.
5
+
6
+ # Worklist
7
+ worklistTitle=<%= appTitle %>
8
+ worklistViewTitle=<%= appTitle %>
9
+ tableTitleCount=Items ({0}/{1})
10
+ tableTitleNoCount=Items
11
+ noDataText=No items to display
12
+
13
+ # Search
14
+ searchField.placeholder=Search
15
+
16
+ # Columns
17
+ <% columns.forEach(function (col) { -%>
18
+ col.<%= col.name %>=<%= col.label %>
19
+ <% }) -%>
20
+ col.info=Info
21
+
22
+ # Filters
23
+ <% filters.forEach(function (f) { -%>
24
+ filter.<%= f.fieldName %>=<%= f.label %>
25
+ <% }) -%>
26
+
27
+ # Pagination
28
+ rowsPerPage=Rows per page
29
+ rowsPerPageError=Rows per page must be between {0} and {1}.
30
+
31
+ # Info bar
32
+ info.filteredBy=Filtered by {0}
33
+ info.sortedBy=Sorted by {0} ({1})
34
+ info.groupedBy=Grouped by {0}
35
+ info.searchedBy=Searched: "{0}"
36
+ sort.asc=Ascending
37
+ sort.desc=Descending
38
+ group.empty=(empty)
39
+
40
+ # Toolbar
41
+ columnSettings=Columns
42
+ tooltip.sort=Sort
43
+ tooltip.group=Group
44
+ tooltip.refresh=Refresh
45
+ tooltip.export=Export to Excel
46
+ tooltip.autoRefresh=Auto-refresh every 30s
47
+ autoRefresh.btnOff=Auto: Off
48
+ autoRefresh.btnOn=Auto: On
49
+ autoRefresh.on=Auto-refresh enabled (every 30s)
50
+ autoRefresh.off=Auto-refresh disabled
51
+ tableRefreshed=Table refreshed
52
+ lastRefreshed.label=Last updated
53
+ variant.saved=View saved
54
+ close=Close
55
+
56
+ # Export
57
+ export.noData=Nothing to export
58
+ export.success=Export complete
59
+ export.error=Export failed
60
+ export.largeConfirm=You are about to export {0} rows. Continue?
61
+ export.dialogTitle=Exporting…
62
+ export.dialogText=Generating Excel file
63
+
64
+ # Multi-select / bulk action
65
+ selectedCount=selected
66
+ bulkAction=Action
67
+ bulkActionDemo={0} item(s) actioned
68
+ clearSelection=Clear selection
69
+
70
+ # Empty state
71
+ noDataIllustrationTitle=No items
72
+ noDataIllustrationDesc=Try adjusting your filters or refresh the table.
73
+
74
+ # Info popover (demo — see Worklist.controller.js onInfoPopoverPress)
75
+ link.info=Info
76
+ infoPopoverTitle=Row Details
77
+ infoPopoverKey=Key
78
+ infoPopoverDetail=Detail
79
+ infoPopoverTimestamp=Timestamp
80
+
81
+ # Not Found
82
+ notFoundTitle=Not Found
83
+ notFoundText=The requested resource was not found.
@@ -0,0 +1,83 @@
1
+ # App
2
+ appTitle=<%= appTitle %>
3
+ appDescription=<%= appDescription %>
4
+ errorText=Ein unerwarteter Fehler ist aufgetreten.
5
+
6
+ # Worklist
7
+ worklistTitle=<%= appTitle %>
8
+ worklistViewTitle=<%= appTitle %>
9
+ tableTitleCount=Einträge ({0}/{1})
10
+ tableTitleNoCount=Einträge
11
+ noDataText=Keine Einträge vorhanden
12
+
13
+ # Search
14
+ searchField.placeholder=Suchen
15
+
16
+ # Columns — translate field labels manually
17
+ <% columns.forEach(function (col) { -%>
18
+ col.<%= col.name %>=<%= col.label %>
19
+ <% }) -%>
20
+ col.info=Info
21
+
22
+ # Filters — translate filter labels manually
23
+ <% filters.forEach(function (f) { -%>
24
+ filter.<%= f.fieldName %>=<%= f.label %>
25
+ <% }) -%>
26
+
27
+ # Pagination
28
+ rowsPerPage=Zeilen pro Seite
29
+ rowsPerPageError=Zeilen pro Seite muss zwischen {0} und {1} liegen.
30
+
31
+ # Info bar
32
+ info.filteredBy=Gefiltert nach {0}
33
+ info.sortedBy=Sortiert nach {0} ({1})
34
+ info.groupedBy=Gruppiert nach {0}
35
+ info.searchedBy=Gesucht: "{0}"
36
+ sort.asc=Aufsteigend
37
+ sort.desc=Absteigend
38
+ group.empty=(leer)
39
+
40
+ # Toolbar
41
+ columnSettings=Spalten
42
+ tooltip.sort=Sortieren
43
+ tooltip.group=Gruppieren
44
+ tooltip.refresh=Aktualisieren
45
+ tooltip.export=Nach Excel exportieren
46
+ tooltip.autoRefresh=Auto-Aktualisierung alle 30s
47
+ autoRefresh.btnOff=Auto: Aus
48
+ autoRefresh.btnOn=Auto: An
49
+ autoRefresh.on=Auto-Aktualisierung aktiv (alle 30s)
50
+ autoRefresh.off=Auto-Aktualisierung deaktiviert
51
+ tableRefreshed=Tabelle aktualisiert
52
+ lastRefreshed.label=Zuletzt aktualisiert
53
+ variant.saved=Ansicht gespeichert
54
+ close=Schließen
55
+
56
+ # Export
57
+ export.noData=Keine Daten zum Exportieren
58
+ export.success=Export abgeschlossen
59
+ export.error=Export fehlgeschlagen
60
+ export.largeConfirm=Sie exportieren {0} Zeilen. Fortfahren?
61
+ export.dialogTitle=Export läuft…
62
+ export.dialogText=Excel-Datei wird erstellt
63
+
64
+ # Multi-select / bulk action
65
+ selectedCount=ausgewählt
66
+ bulkAction=Aktion
67
+ bulkActionDemo={0} Eintrag/Einträge bearbeitet
68
+ clearSelection=Auswahl aufheben
69
+
70
+ # Empty state
71
+ noDataIllustrationTitle=Keine Einträge
72
+ noDataIllustrationDesc=Filter anpassen oder Tabelle aktualisieren.
73
+
74
+ # Info popover
75
+ link.info=Info
76
+ infoPopoverTitle=Zeilendetails
77
+ infoPopoverKey=Schlüssel
78
+ infoPopoverDetail=Detail
79
+ infoPopoverTimestamp=Zeitstempel
80
+
81
+ # Not Found
82
+ notFoundTitle=Nicht gefunden
83
+ notFoundText=Die angeforderte Ressource wurde nicht gefunden.
@@ -0,0 +1,52 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title><%= appTitle %></title>
8
+ <!--
9
+ flexibilityServices wires sap.ui.fl (used by VariantManagement) to a
10
+ connector. Default = LocalStorageConnector, so saved variants live in
11
+ the browser. To persist on a SAP backend, swap to "LrepConnector"
12
+ (requires /sap/bc/lrep to be reachable). Multiple connectors can be
13
+ chained; see sap.ui.fl docs.
14
+ -->
15
+ <script
16
+ id="sap-ui-bootstrap"
17
+ src="resources/sap-ui-core.js"
18
+ data-sap-ui-theme="sap_horizon"
19
+ data-sap-ui-resourceroots='{"<%= appId %>": "./"}'
20
+ data-sap-ui-compat-version="edge"
21
+ data-sap-ui-async="true"
22
+ data-sap-ui-xx-waitForTheme="true"
23
+ data-sap-ui-flexibilityServices='[{"connector":"LocalStorageConnector"}]'>
24
+ </script>
25
+ <script>
26
+ // Wait for UI5 core, run the backend preflight check, then mount the
27
+ // Component. If the backend is reachable the app uses real data; if
28
+ // not (e.g. offline dev, no proxy), backendCheck starts a MockServer
29
+ // that fakes data from localService/metadata.xml.
30
+ sap.ui.require(["sap/ui/core/Core"], function (Core) {
31
+ Core.ready().then(function () {
32
+ sap.ui.require([
33
+ "sap/ui/core/ComponentContainer",
34
+ "<%= namespacePath %>/localService/backendCheck"
35
+ ], function (ComponentContainer, backendCheck) {
36
+ backendCheck.decide().then(function () {
37
+ new ComponentContainer({
38
+ id: "container",
39
+ name: "<%= appId %>",
40
+ settings: { id: "<%= appName %>" },
41
+ height: "100%",
42
+ async: true
43
+ }).placeAt("content");
44
+ });
45
+ });
46
+ });
47
+ });
48
+ </script>
49
+ </head>
50
+ <body class="sapUiBody" id="content">
51
+ </body>
52
+ </html>
@@ -0,0 +1,52 @@
1
+ sap.ui.define([
2
+ "./mockserver"
3
+ ], function (mockserver) {
4
+ "use strict";
5
+
6
+ const SERVICE_URL = "<%= serviceUrl %>";
7
+ const TIMEOUT_MS = 3000;
8
+
9
+ function ping() {
10
+ return new Promise(function (resolve) {
11
+ const controller = new AbortController();
12
+ const timer = setTimeout(function () {
13
+ controller.abort();
14
+ resolve(false);
15
+ }, TIMEOUT_MS);
16
+
17
+ fetch(SERVICE_URL + "$metadata", {
18
+ method: "HEAD",
19
+ signal: controller.signal,
20
+ credentials: "include"
21
+ }).then(function (r) {
22
+ clearTimeout(timer);
23
+ // 2xx = backend reachable and accessible.
24
+ // 401 / 403 = backend alive, auth issue only — still treat as "real".
25
+ resolve(r.ok || r.status === 401 || r.status === 403);
26
+ }).catch(function () {
27
+ clearTimeout(timer);
28
+ resolve(false);
29
+ });
30
+ });
31
+ }
32
+
33
+ return {
34
+ /**
35
+ * Pings the configured OData service. If reachable, returns without
36
+ * side-effects. If unreachable, starts a MockServer so the app works
37
+ * offline with synthetic data generated from the local metadata.xml.
38
+ */
39
+ decide: function () {
40
+ return ping().then(function (isReachable) {
41
+ if (!isReachable) {
42
+ // eslint-disable-next-line no-console
43
+ console.info("[backendCheck] Backend not reachable — starting MockServer");
44
+ mockserver.init();
45
+ } else {
46
+ // eslint-disable-next-line no-console
47
+ console.info("[backendCheck] Backend is reachable — using real data");
48
+ }
49
+ });
50
+ }
51
+ };
52
+ });
@@ -0,0 +1,29 @@
1
+ sap.ui.define([
2
+ "sap/ui/core/util/MockServer"
3
+ ], function (MockServer) {
4
+ "use strict";
5
+
6
+ return {
7
+ /**
8
+ * Starts a MockServer that reads localService/metadata.xml and
9
+ * returns randomly generated rows matching the schema for every
10
+ * OData request going to the main service URL.
11
+ */
12
+ init: function () {
13
+ const oMockServer = new MockServer({
14
+ rootUri: "<%= serviceUrl %>"
15
+ });
16
+
17
+ MockServer.config({
18
+ autoRespond: true,
19
+ autoRespondAfter: 300
20
+ });
21
+
22
+ oMockServer.simulate(
23
+ sap.ui.require.toUrl("<%= namespacePath %>/localService/metadata.xml")
24
+ );
25
+ oMockServer.start();
26
+ return oMockServer;
27
+ }
28
+ };
29
+ });
@@ -0,0 +1,106 @@
1
+ {
2
+ "_version": "1.60.0",
3
+ "sap.app": {
4
+ "id": "<%= appId %>",
5
+ "type": "application",
6
+ "i18n": "i18n/i18n.properties",
7
+ "title": "{{appTitle}}",
8
+ "description": "{{appDescription}}",
9
+ "applicationVersion": {
10
+ "version": "1.0.0"
11
+ },
12
+ "dataSources": {
13
+ "mainService": {
14
+ "uri": "<%= serviceUrl %>",
15
+ "type": "OData",
16
+ "settings": {
17
+ "odataVersion": "2.0",
18
+ "localUri": "localService/metadata.xml"
19
+ }
20
+ }
21
+ }
22
+ },
23
+ "sap.ui": {
24
+ "technology": "UI5",
25
+ "fullWidth": true,
26
+ "icons": {
27
+ "icon": "sap-icon://task"
28
+ },
29
+ "deviceTypes": {
30
+ "desktop": true,
31
+ "tablet": true,
32
+ "phone": true
33
+ }
34
+ },
35
+ "sap.ui5": {
36
+ "flexEnabled": true,
37
+ "rootView": {
38
+ "viewName": "<%= appId %>.view.App",
39
+ "type": "XML",
40
+ "async": true,
41
+ "id": "app"
42
+ },
43
+ "dependencies": {
44
+ "minUI5Version": "<%= minUI5Version %>",
45
+ "libs": {
46
+ "sap.ui.core": {},
47
+ "sap.m": {},
48
+ "sap.f": {},
49
+ "sap.ui.comp": {},
50
+ "sap.ui.layout": {},
51
+ "sap.uxap": {},
52
+ "sap.ui.export": {},
53
+ "sap.ui.fl": {}
54
+ }
55
+ },
56
+ "contentDensities": {
57
+ "compact": true,
58
+ "cozy": true
59
+ },
60
+ "resources": {
61
+ "css": [
62
+ { "uri": "css/style.css" }
63
+ ]
64
+ },
65
+ "models": {
66
+ "i18n": {
67
+ "type": "sap.ui.model.resource.ResourceModel",
68
+ "settings": {
69
+ "bundleName": "<%= appId %>.i18n.i18n",
70
+ "supportedLocales": [""<% if (hasGerman) { %>, "de"<% } %>],
71
+ "fallbackLocale": ""
72
+ }
73
+ },
74
+ "": {
75
+ "dataSource": "mainService",
76
+ "preload": true
77
+ }
78
+ },
79
+ "routing": {
80
+ "config": {
81
+ "routerClass": "sap.m.routing.Router",
82
+ "viewType": "XML",
83
+ "viewPath": "<%= appId %>.view",
84
+ "controlId": "app",
85
+ "controlAggregation": "pages",
86
+ "bypassed": { "target": ["notFound"] },
87
+ "async": true
88
+ },
89
+ "routes": [
90
+ { "pattern": ":?query:", "name": "worklist", "target": ["worklist"] }
91
+ ],
92
+ "targets": {
93
+ "worklist": {
94
+ "viewName": "Worklist",
95
+ "viewId": "worklist",
96
+ "viewLevel": 1,
97
+ "title": "{i18n>worklistViewTitle}"
98
+ },
99
+ "notFound": {
100
+ "viewName": "NotFound",
101
+ "viewId": "notFound"
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,148 @@
1
+ sap.ui.define([
2
+ "sap/ui/core/format/DateFormat"
3
+ ], function (DateFormat) {
4
+ "use strict";
5
+
6
+ return {
7
+
8
+ /**
9
+ * Date+time formatter. Default pattern "dd.MM.yyyy HH:mm:ss".
10
+ * Pass a custom pattern as 2nd arg for variations.
11
+ */
12
+ formatDate: function (vValue, sPattern) {
13
+ if (!vValue) return "";
14
+ const oDate = vValue instanceof Date ? vValue : new Date(vValue);
15
+ if (isNaN(oDate.getTime())) return "";
16
+ return DateFormat.getDateTimeInstance({
17
+ pattern: sPattern || "dd.MM.yyyy HH:mm:ss"
18
+ }).format(oDate);
19
+ },
20
+
21
+ /**
22
+ * Date-only formatter "dd.MM.yyyy". Useful as ObjectIdentifier title.
23
+ */
24
+ formatDateOnly: function (vValue) {
25
+ if (!vValue) return "";
26
+ const oDate = vValue instanceof Date ? vValue : new Date(vValue);
27
+ if (isNaN(oDate.getTime())) return "";
28
+ return DateFormat.getDateInstance({ pattern: "dd.MM.yyyy" }).format(oDate);
29
+ },
30
+
31
+ /**
32
+ * Time-only formatter "HH:mm:ss". Useful as ObjectIdentifier secondary text.
33
+ */
34
+ formatTimeOnly: function (vValue) {
35
+ if (!vValue) return "";
36
+ const oDate = vValue instanceof Date ? vValue : new Date(vValue);
37
+ if (isNaN(oDate.getTime())) return "";
38
+ return DateFormat.getTimeInstance({ pattern: "HH:mm:ss" }).format(oDate);
39
+ },
40
+
41
+ /**
42
+ * Maps a status value to one of: "None" / "Success" / "Warning" / "Error" / "Information".
43
+ * Used by GenericTag (status attribute) and ColumnListItem (highlight attribute).
44
+ *
45
+ * The defaults below cover common English status vocabulary. To support
46
+ * your own domain-specific codes (e.g. "MTCH", "01", "OPEN"), add cases
47
+ * at the TOP of the function — they take priority over the generic ones.
48
+ */
49
+ formatStatusState: function (sStatus) {
50
+ if (sStatus === undefined || sStatus === null || sStatus === "") return "None";
51
+ const s = String(sStatus).toUpperCase();
52
+
53
+ // ---- Add your domain-specific status codes here ----
54
+ // if (s === "MTCH") return "Success";
55
+ // if (s === "NMTC") return "Error";
56
+ // if (s === "CMTC") return "Warning";
57
+ // ----------------------------------------------------
58
+
59
+ // Generic English status terms — cover most cases out of the box
60
+ if (/^(OK|SUCCESS|SUCCESSFUL|SUCC|DONE|COMPLETE|COMPLETED|ACTIVE|APPROVED|PASSED|YES|TRUE|1)$/.test(s)) return "Success";
61
+ if (/^(ERR|ERROR|FAIL|FAILED|REJECTED|INACTIVE|CANCELLED|CANCELED|BLOCKED|NO|FALSE|0)$/.test(s)) return "Error";
62
+ if (/^(WRN|WARN|WARNING|PENDING|PEND|TODO|DRAFT|HOLD|REVIEW|IN_PROGRESS)$/.test(s)) return "Warning";
63
+ if (/^(INFO|INFORMATION|NEW|OPEN|UNREAD)$/.test(s)) return "Information";
64
+
65
+ return "None";
66
+ },
67
+
68
+ /**
69
+ * DEMO ONLY — always returns "Success".
70
+ *
71
+ * Bind ColumnListItem `highlight` (or GenericTag `status`) to this
72
+ * formatter to verify the highlight is visually wired up — every row
73
+ * gets a green bar regardless of data. Useful when MockServer returns
74
+ * random strings that don't match any real status code.
75
+ *
76
+ * Switch back to `formatStatusState` once your real backend (or your
77
+ * domain mapping inside formatStatusState) is in place.
78
+ */
79
+ formatStatusStateDemo: function () {
80
+ return "Success";
81
+ },
82
+
83
+ /**
84
+ * Strip leading zeros (e.g. SAP partner ID "0000123456" -> "123456").
85
+ */
86
+ formatPartnerId: function (sId) {
87
+ if (!sId) return "";
88
+ return String(sId).replace(/^0+/, "");
89
+ },
90
+
91
+ /**
92
+ * Wrap value in <strong><code> — bold monospace, most visually prominent.
93
+ * Use for primary identifiers like GUIDs.
94
+ */
95
+ formatStrongCode: function (sValue) {
96
+ if (sValue === undefined || sValue === null) return "";
97
+ return "<strong><code>" + sValue + "</code></strong>";
98
+ },
99
+
100
+ /**
101
+ * Wrap value in <code> — monospace, lighter weight.
102
+ * Use for secondary identifiers like CustomerId, PartnerId.
103
+ */
104
+ formatCode: function (sValue) {
105
+ if (sValue === undefined || sValue === null) return "";
106
+ return "<code>" + sValue + "</code>";
107
+ },
108
+
109
+ /**
110
+ * Wrap value in <cite> — italic, reference-like.
111
+ * Use for keys, UUIDs, references.
112
+ */
113
+ formatCite: function (sValue) {
114
+ if (sValue === undefined || sValue === null) return "";
115
+ return "<cite>" + sValue + "</cite>";
116
+ },
117
+
118
+ /**
119
+ * Round a numeric value to 2 decimals.
120
+ */
121
+ numberUnit: function (sValue) {
122
+ if (sValue === undefined || sValue === null || sValue === "") return "";
123
+ const n = parseFloat(sValue);
124
+ return isNaN(n) ? "" : n.toFixed(2);
125
+ },
126
+
127
+ /**
128
+ * Animate a numeric JSON-model value from current to fTarget over
129
+ * iDuration ms (ease-out-cubic). Useful for progress bars.
130
+ */
131
+ _animateValue: function (oModel, sPath, fTarget, iDuration) {
132
+ oModel._animations = oModel._animations || {};
133
+ if (oModel._animations[sPath]) oModel._animations[sPath].cancelled = true;
134
+ const oToken = { cancelled: false };
135
+ oModel._animations[sPath] = oToken;
136
+ const fStart = oModel.getProperty(sPath) || 0;
137
+ const iStartTime = performance.now();
138
+ const ease = (t) => 1 - Math.pow(1 - t, 3);
139
+ const step = (iNow) => {
140
+ if (oToken.cancelled) return;
141
+ const iProgress = Math.min((iNow - iStartTime) / iDuration, 1);
142
+ oModel.setProperty(sPath, Math.round(fStart + (fTarget - fStart) * ease(iProgress)));
143
+ if (iProgress < 1) requestAnimationFrame(step);
144
+ };
145
+ requestAnimationFrame(step);
146
+ }
147
+ };
148
+ });
@@ -0,0 +1,23 @@
1
+ sap.ui.define([
2
+ "sap/ui/model/json/JSONModel",
3
+ "sap/ui/Device",
4
+ "sap/base/util/ObjectPath"
5
+ ], function (JSONModel, Device, ObjectPath) {
6
+ "use strict";
7
+
8
+ return {
9
+ createDeviceModel: function () {
10
+ const oModel = new JSONModel(Device);
11
+ oModel.setDefaultBindingMode("OneWay");
12
+ return oModel;
13
+ },
14
+
15
+ createFLPModel: function () {
16
+ const fnGetUser = ObjectPath.get("sap.ushell.Container.getUser");
17
+ const bIsShareInJamActive = fnGetUser ? fnGetUser().isJamActive() : false;
18
+ const oModel = new JSONModel({ isShareInJamActive: bIsShareInJamActive });
19
+ oModel.setDefaultBindingMode("OneWay");
20
+ return oModel;
21
+ }
22
+ };
23
+ });
@@ -0,0 +1,10 @@
1
+ <mvc:View
2
+ controllerName="__APP_ID__.controller.App"
3
+ displayBlock="true"
4
+ xmlns="sap.m"
5
+ xmlns:mvc="sap.ui.core.mvc">
6
+ <App
7
+ id="app"
8
+ busy="{appView>/busy}"
9
+ busyIndicatorDelay="{appView>/delay}"/>
10
+ </mvc:View>
@@ -0,0 +1,12 @@
1
+ <mvc:View
2
+ controllerName="__APP_ID__.controller.NotFound"
3
+ xmlns="sap.m"
4
+ xmlns:mvc="sap.ui.core.mvc">
5
+ <MessagePage
6
+ title="{i18n>notFoundTitle}"
7
+ text="{i18n>notFoundText}"
8
+ description=""
9
+ icon="sap-icon://document"
10
+ showNavButton="true"
11
+ navButtonPress=".onNavBack"/>
12
+ </mvc:View>