cds-caching 1.2.0 → 1.3.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 (79) hide show
  1. package/README.md +195 -1114
  2. package/app/dashboard/Component-dbg.js +59 -0
  3. package/app/dashboard/Component-dbg.js.map +1 -0
  4. package/app/dashboard/Component.js +2 -0
  5. package/app/dashboard/Component.js.map +1 -0
  6. package/app/dashboard/Component.ts +59 -0
  7. package/app/dashboard/controller/App-dbg.controller.js +132 -0
  8. package/app/dashboard/controller/App-dbg.controller.js.map +1 -0
  9. package/app/dashboard/controller/App.controller.js +2 -0
  10. package/app/dashboard/controller/App.controller.js.map +1 -0
  11. package/app/dashboard/controller/App.controller.ts +147 -0
  12. package/app/dashboard/controller/BaseController-dbg.js +75 -0
  13. package/app/dashboard/controller/BaseController-dbg.js.map +1 -0
  14. package/app/dashboard/controller/BaseController.js +2 -0
  15. package/app/dashboard/controller/BaseController.js.map +1 -0
  16. package/app/dashboard/controller/BaseController.ts +88 -0
  17. package/app/dashboard/controller/Cache-dbg.controller.js +421 -0
  18. package/app/dashboard/controller/Cache-dbg.controller.js.map +1 -0
  19. package/app/dashboard/controller/Cache.controller.js +2 -0
  20. package/app/dashboard/controller/Cache.controller.js.map +1 -0
  21. package/app/dashboard/controller/Cache.controller.ts +490 -0
  22. package/app/dashboard/controller/Main-dbg.controller.js +32 -0
  23. package/app/dashboard/controller/Main-dbg.controller.js.map +1 -0
  24. package/app/dashboard/controller/Main.controller.js +2 -0
  25. package/app/dashboard/controller/Main.controller.js.map +1 -0
  26. package/app/dashboard/controller/Main.controller.ts +31 -0
  27. package/app/dashboard/controller/SingleMetric-dbg.controller.js +306 -0
  28. package/app/dashboard/controller/SingleMetric-dbg.controller.js.map +1 -0
  29. package/app/dashboard/controller/SingleMetric.controller.js +2 -0
  30. package/app/dashboard/controller/SingleMetric.controller.js.map +1 -0
  31. package/app/dashboard/controller/SingleMetric.controller.ts +335 -0
  32. package/app/dashboard/i18n/i18n.properties +61 -0
  33. package/app/dashboard/i18n/i18n_de.properties +3 -0
  34. package/app/dashboard/i18n/i18n_en.properties +3 -0
  35. package/app/dashboard/index-cdn.html +28 -0
  36. package/app/dashboard/index.html +19 -0
  37. package/app/dashboard/manifest.json +145 -0
  38. package/app/dashboard/model/formatter-dbg.js +253 -0
  39. package/app/dashboard/model/formatter-dbg.js.map +1 -0
  40. package/app/dashboard/model/formatter.js +2 -0
  41. package/app/dashboard/model/formatter.js.map +1 -0
  42. package/app/dashboard/model/formatter.ts +275 -0
  43. package/app/dashboard/model/models-dbg.js +13 -0
  44. package/app/dashboard/model/models-dbg.js.map +1 -0
  45. package/app/dashboard/model/models.js +2 -0
  46. package/app/dashboard/model/models.js.map +1 -0
  47. package/app/dashboard/model/models.ts +13 -0
  48. package/app/dashboard/resources/sap-ui-custom-dbg.js +4695 -0
  49. package/app/dashboard/resources/sap-ui-custom-dbg.js.map +1 -0
  50. package/app/dashboard/resources/sap-ui-custom.js +5794 -0
  51. package/app/dashboard/resources/sap-ui-custom.js.map +1 -0
  52. package/app/dashboard/service/CacheStatisticsService-dbg.js +267 -0
  53. package/app/dashboard/service/CacheStatisticsService-dbg.js.map +1 -0
  54. package/app/dashboard/service/CacheStatisticsService.js +2 -0
  55. package/app/dashboard/service/CacheStatisticsService.js.map +1 -0
  56. package/app/dashboard/service/CacheStatisticsService.ts +397 -0
  57. package/app/dashboard/view/App.view.xml +18 -0
  58. package/app/dashboard/view/Cache.view.xml +777 -0
  59. package/app/dashboard/view/Main.view.xml +57 -0
  60. package/app/dashboard/view/SingleMetric.view.xml +337 -0
  61. package/cds-plugin.js +52 -0
  62. package/db/cache-store.cds +12 -0
  63. package/db/statistics.cds +128 -0
  64. package/index.cds +2 -128
  65. package/lib/CachingService.js +13 -0
  66. package/lib/add.js +17 -0
  67. package/lib/operations/AsyncOperations.js +162 -111
  68. package/lib/operations/BasicOperations.js +35 -0
  69. package/lib/operations/CapOperations.js +92 -40
  70. package/lib/support/CacheStatisticsHandler.js +35 -10
  71. package/lib/support/CacheStoreManager.js +29 -0
  72. package/lib/support/KeyvCDS.js +149 -0
  73. package/lib/support/MultitenancyDetector.js +25 -0
  74. package/lib/support/RuntimeConfigurationManager.js +69 -37
  75. package/lib/support/StatisticsPersistenceManager.js +18 -2
  76. package/lib/support/Telemetry.js +137 -0
  77. package/lib/util.js +29 -11
  78. package/package.json +44 -12
  79. package/srv/caching-api-service.js +47 -2
@@ -0,0 +1,335 @@
1
+ import BaseController from "./BaseController";
2
+ import JSONModel from "sap/ui/model/json/JSONModel";
3
+ import ODataModel from "sap/ui/model/odata/v4/ODataModel";
4
+ import { Route$PatternMatchedEvent } from "sap/ui/core/routing/Route";
5
+ import MessageBox from "sap/m/MessageBox";
6
+
7
+ /**
8
+ * @namespace cds.plugin.caching.dashboard.controller
9
+ */
10
+ export default class SingleMetric extends BaseController {
11
+ private uiModel: JSONModel;
12
+
13
+ public onInit(): void {
14
+ super.onInit();
15
+
16
+ // Create a JSON model for UI data binding
17
+ this.uiModel = new JSONModel({
18
+ metricId: "",
19
+ // Performance metrics
20
+ hitRatio: 0,
21
+ cacheEfficiency: 0,
22
+ throughput: 0,
23
+ errorRate: 0,
24
+ // Latency metrics
25
+ avgLatency: 0,
26
+ avgHitLatency: 0,
27
+ avgMissLatency: 0,
28
+ // Operation counts
29
+ hits: 0,
30
+ misses: 0,
31
+ sets: 0,
32
+ deletes: 0,
33
+ errors: 0,
34
+ // Native function metrics
35
+ nativeSets: 0,
36
+ nativeGets: 0,
37
+ nativeDeletes: 0,
38
+ nativeClears: 0,
39
+ nativeDeleteByTags: 0,
40
+ nativeErrors: 0,
41
+ totalNativeOperations: 0,
42
+ nativeThroughput: 0,
43
+ nativeErrorRate: 0,
44
+ // System information
45
+ memoryUsage: 0,
46
+ itemCount: 0,
47
+ uniqueKeys: 0,
48
+ uptimeMs: 0,
49
+ // Chart data
50
+ latencyData: [],
51
+ cacheThroughData: [],
52
+ nativeData: []
53
+ });
54
+ this.getView().setModel(this.uiModel, "ui");
55
+
56
+ this.getRouter().getRoute("singleMetric").attachPatternMatched(this.onRouteMatched, this);
57
+ }
58
+
59
+ public onRouteMatched(event: Route$PatternMatchedEvent): void {
60
+ const { cache, metricId } = event.getParameter("arguments") as { cache: string; metricId: string };
61
+
62
+ this.uiModel.setProperty("/metricId", metricId);
63
+
64
+ // Set layout to three columns
65
+ (<JSONModel>this.getModel("app")).setProperty("/layout", "ThreeColumnsEndExpanded");
66
+
67
+ // Load the specific metric
68
+ this.loadMetric(cache, metricId);
69
+
70
+ this.formatChart();
71
+ }
72
+
73
+ /**
74
+ * Load specific metric data
75
+ */
76
+ private async loadMetric(cacheName: string, metricId: string): Promise<void> {
77
+ try {
78
+ const model = this.getModel() as ODataModel;
79
+
80
+ // Try to get the metric from the Metrics entity
81
+ const context = model.bindContext(`/Metrics(ID='${metricId}',cache='${cacheName}')`);
82
+ const metric = await context.requestObject();
83
+
84
+ if (metric) {
85
+ // Set all the metric values
86
+ this.uiModel.setProperty("/hitRatio", metric.hitRatio || 0);
87
+ this.uiModel.setProperty("/cacheEfficiency", metric.cacheEfficiency || 0);
88
+ this.uiModel.setProperty("/throughput", metric.throughput || 0);
89
+ this.uiModel.setProperty("/errorRate", metric.errorRate || 0);
90
+
91
+ // Latency metrics
92
+ this.uiModel.setProperty("/avgLatency", metric.avgLatency || 0);
93
+ this.uiModel.setProperty("/avgHitLatency", metric.avgHitLatency || 0);
94
+ this.uiModel.setProperty("/avgMissLatency", metric.avgMissLatency || 0);
95
+
96
+ // Operation counts
97
+ this.uiModel.setProperty("/hits", metric.hits || 0);
98
+ this.uiModel.setProperty("/misses", metric.misses || 0);
99
+ this.uiModel.setProperty("/sets", metric.sets || 0);
100
+ this.uiModel.setProperty("/deletes", metric.deletes || 0);
101
+ this.uiModel.setProperty("/errors", metric.errors || 0);
102
+
103
+ // Native function metrics
104
+ this.uiModel.setProperty("/nativeSets", metric.nativeSets || 0);
105
+ this.uiModel.setProperty("/nativeGets", metric.nativeGets || 0);
106
+ this.uiModel.setProperty("/nativeDeletes", metric.nativeDeletes || 0);
107
+ this.uiModel.setProperty("/nativeClears", metric.nativeClears || 0);
108
+ this.uiModel.setProperty("/nativeDeleteByTags", metric.nativeDeleteByTags || 0);
109
+ this.uiModel.setProperty("/nativeErrors", metric.nativeErrors || 0);
110
+ this.uiModel.setProperty("/totalNativeOperations", metric.totalNativeOperations || 0);
111
+ this.uiModel.setProperty("/nativeThroughput", metric.nativeThroughput || 0);
112
+ this.uiModel.setProperty("/nativeErrorRate", metric.nativeErrorRate || 0);
113
+
114
+ // System information
115
+ this.uiModel.setProperty("/memoryUsage", metric.memoryUsage || 0);
116
+ this.uiModel.setProperty("/itemCount", metric.itemCount || 0);
117
+ this.uiModel.setProperty("/uptimeMs", metric.uptimeMs || 0);
118
+
119
+ // Calculate unique keys (this might need to come from a different source)
120
+ this.uiModel.setProperty("/uniqueKeys", 0); // TODO: Get from key metrics data
121
+
122
+ // Generate chart data
123
+ this.generateLatencyChartData(metric);
124
+ this.generateCacheThroughChartData(metric);
125
+ this.generateNativeChartData(metric);
126
+
127
+ } else {
128
+ MessageBox.error("Metric not found");
129
+ }
130
+
131
+ } catch (error) {
132
+ console.error("Error loading metric:", error);
133
+ MessageBox.error("Failed to load metric details");
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Generate latency data for the chart
139
+ */
140
+ private generateLatencyChartData(metric: any): void {
141
+ const latencyData = [
142
+ {
143
+ operation: "Average Hit Latency",
144
+ latency: metric.avgHitLatency || 0
145
+ },
146
+ {
147
+ operation: "Average Miss Latency",
148
+ latency: metric.avgMissLatency || 0
149
+ },
150
+ {
151
+ operation: "Average Read-Through Latency",
152
+ latency: metric.avgReadThroughLatency || 0
153
+ }
154
+ ];
155
+
156
+ this.uiModel.setProperty("/latencyData", latencyData);
157
+ }
158
+
159
+ /**
160
+ * Generate Read-Through operations data for pie chart
161
+ */
162
+ private generateCacheThroughChartData(metric: any): void {
163
+ const cacheThroughData = [
164
+ {
165
+ operation: "Hits",
166
+ count: metric.hits || 0
167
+ },
168
+ {
169
+ operation: "Misses",
170
+ count: metric.misses || 0
171
+ },
172
+ {
173
+ operation: "Errors",
174
+ count: metric.errors || 0
175
+ }
176
+ ];
177
+
178
+ this.uiModel.setProperty("/cacheThroughData", cacheThroughData);
179
+ }
180
+
181
+ /**
182
+ * Generate Native Function operations data for pie chart
183
+ */
184
+ private generateNativeChartData(metric: any): void {
185
+ const nativeData = [
186
+ {
187
+ operation: "Sets",
188
+ count: metric.nativeSets || 0
189
+ },
190
+ {
191
+ operation: "Gets",
192
+ count: metric.nativeGets || 0
193
+ },
194
+ {
195
+ operation: "Deletes",
196
+ count: metric.nativeDeletes || 0
197
+ },
198
+ {
199
+ operation: "Clears",
200
+ count: metric.nativeClears || 0
201
+ },
202
+ {
203
+ operation: "Delete By Tags",
204
+ count: metric.nativeDeleteByTags || 0
205
+ },
206
+ {
207
+ operation: "Errors",
208
+ count: metric.nativeErrors || 0
209
+ }
210
+ ];
211
+
212
+ this.uiModel.setProperty("/nativeData", nativeData);
213
+ }
214
+
215
+ public formatChart() {
216
+ // Format latency chart (bar chart)
217
+ const latencyChart = this.getView().byId("metricLatencyChart") as any;
218
+ if (latencyChart) {
219
+ latencyChart.setVizProperties({
220
+ legend: {
221
+ visible: false
222
+ },
223
+ plotArea: {
224
+ dataLabel: {
225
+ visible: true,
226
+ formatString: "#,## ms"
227
+ },
228
+ gridline: {
229
+ visible: false
230
+ }
231
+ },
232
+ valueAxis: {
233
+ axisLine: {
234
+ visible: false
235
+ },
236
+ axisTick: {
237
+ visible: false
238
+ },
239
+ label: {
240
+ visible: false
241
+ },
242
+ title: {
243
+ visible: false
244
+ }
245
+ },
246
+ categoryAxis: {
247
+ title: {
248
+ visible: false
249
+ }
250
+ },
251
+ title: {
252
+ visible: false,
253
+ text: 'Latency by Operation'
254
+ }
255
+ });
256
+ }
257
+
258
+ // Format Read-Through pie chart
259
+ const cacheThroughChart = this.getView().byId("metricCacheThroughChart") as any;
260
+ if (cacheThroughChart) {
261
+ cacheThroughChart.setVizProperties({
262
+ legend: {
263
+ visible: true
264
+ },
265
+ plotArea: {
266
+ dataLabel: {
267
+ visible: true
268
+ }
269
+ },
270
+ title: {
271
+ visible: false
272
+ }
273
+ });
274
+ }
275
+
276
+ // Format Native Function pie chart
277
+ const nativeChart = this.getView().byId("metricNativeChart") as any;
278
+ if (nativeChart) {
279
+ nativeChart.setVizProperties({
280
+ legend: {
281
+ visible: true
282
+ },
283
+ plotArea: {
284
+ dataLabel: {
285
+ visible: true
286
+ }
287
+ },
288
+ title: {
289
+ visible: false
290
+ }
291
+ });
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Handle refresh button press
297
+ */
298
+ public onRefresh(): void {
299
+ const cacheName = this.getModel("app").getProperty("/selectedCache");
300
+ const metricId = this.uiModel.getProperty("/metricId");
301
+
302
+ if (cacheName && metricId) {
303
+ this.loadMetric(cacheName, metricId);
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Handle full screen mode
309
+ */
310
+ public handleFullScreen(): void {
311
+ (<JSONModel>this.getModel("app")).setProperty("/layout", "EndColumnFullScreen");
312
+ }
313
+
314
+ /**
315
+ * Handle exit full screen mode
316
+ */
317
+ public handleExitFullScreen(): void {
318
+ (<JSONModel>this.getModel("app")).setProperty("/layout", "ThreeColumnsEndExpanded");
319
+ }
320
+
321
+ /**
322
+ * Handle close end column
323
+ */
324
+ public handleClose(): void {
325
+ (<JSONModel>this.getModel("app")).setProperty("/layout", "TwoColumnsMidExpanded");
326
+ this.getRouter().navTo("cache", { cache: this.getModel("app").getProperty("/selectedCache") });
327
+ }
328
+
329
+ /**
330
+ * Handle grid columns change
331
+ */
332
+ public onColumnsChange(): void {
333
+ // Handle responsive grid column changes if needed
334
+ }
335
+ }
@@ -0,0 +1,61 @@
1
+ appTitle=Cache Performance Dashboard
2
+ appDescription=Comprehensive cache statistics and monitoring dashboard
3
+ btnText=Say Hello
4
+
5
+ # Main Dashboard
6
+ mainTitle=Cache Performance Dashboard
7
+ refreshButton=Refresh
8
+ persistButton=Persist Statistics
9
+
10
+ # Navigation
11
+ keyAnalysis=Key Analysis
12
+
13
+ # Metrics
14
+ hitRatio=Hit Ratio
15
+ avgLatency=Average Latency
16
+ throughput=Throughput
17
+ errorRate=Error Rate
18
+ totalRequests=Total Requests
19
+ memoryUsage=Memory Usage
20
+ uniqueKeys=Unique Keys
21
+ uptime=Uptime
22
+
23
+ # Keys
24
+ keysTitle=Key Analysis
25
+ keysSubtitle=Cache Key Access Patterns
26
+ topKeys=Top Accessed Keys
27
+ coldKeys=Cold Keys
28
+ keyStatistics=Key Statistics
29
+ totalKeysTracked=Total Keys Tracked
30
+ mostActiveKey=Most Active Key
31
+ leastActiveKey=Least Active Key
32
+
33
+ # Common
34
+ loading=Loading...
35
+ noData=No data available
36
+ error=Error
37
+ success=Success
38
+ warning=Warning
39
+
40
+ # Statistics Page
41
+ statisticsTitle=Statistics
42
+ statisticsSubtitle=Historical cache statistics
43
+ statisticsFilters=Filters
44
+ statisticsFiltersSubtitle=Select date range and period
45
+ statisticsSummary=Summary
46
+ statisticsSummarySubtitle=Statistics overview
47
+ statisticsData=Statistics Data
48
+ statisticsDataSubtitle=Detailed statistics records
49
+ statisticsTrends=Trends
50
+ statisticsTrendsSubtitle=Performance trends over time
51
+ statisticsPeriod=Period
52
+ statisticsFrom=From
53
+ statisticsTo=To
54
+ statisticsLoad=Load
55
+ statisticsRefresh=Refresh
56
+ statisticsExport=Export CSV
57
+ statisticsTotalRecords=Total Records
58
+ statisticsAvgHitRatio=Average Hit Ratio
59
+ statisticsAvgLatency=Average Latency
60
+ statisticsTotalRequests=Total Requests
61
+ statisticsNoData=No statistics found for the selected criteria
@@ -0,0 +1,3 @@
1
+ appTitle=cds.plugin.caching.dashboard
2
+ appDescription=UI5 Application cds.plugin.caching.dashboard
3
+ btnText=Sag Hallo
@@ -0,0 +1,3 @@
1
+ appTitle=cds.plugin.caching.dashboard
2
+ appDescription=UI5 Application cds.plugin.caching.dashboard
3
+ btnText=Say Hello
@@ -0,0 +1,28 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate" />
5
+ <meta http-equiv="Pragma" content="no-cache" />
6
+ <meta http-equiv="expires" content="0" />
7
+
8
+ <meta charset="utf-8" />
9
+
10
+ <title>UI5 Application: cds.plugin.caching.dashboard</title>
11
+
12
+ <script
13
+ id="sap-ui-bootstrap"
14
+ src="https://ui5.sap.com/resources/sap-ui-core.js"
15
+ data-sap-ui-resource-roots='{
16
+ "cds.plugin.caching.dashboard": "./"
17
+ }'
18
+ data-sap-ui-on-init="module:sap/ui/core/ComponentSupport"
19
+ data-sap-ui-compat-version="edge"
20
+ data-sap-ui-frame-options="trusted"
21
+ data-sap-ui-async="true"
22
+ ></script>
23
+ </head>
24
+
25
+ <body class="sapUiBody">
26
+ <div data-sap-ui-component data-name="cds.plugin.caching.dashboard"></div>
27
+ </body>
28
+ </html>
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html><html><head>
2
+ <meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate">
3
+ <meta http-equiv="Pragma" content="no-cache">
4
+ <meta http-equiv="expires" content="0">
5
+
6
+ <meta charset="utf-8">
7
+
8
+ <title>UI5 Application: cds.plugin.caching.dashboard</title>
9
+
10
+ <script id="sap-ui-bootstrap" src="resources/sap-ui-custom.js" data-sap-ui-resource-roots="{
11
+ &quot;cds.plugin.caching.dashboard&quot;: &quot;./&quot;
12
+ }" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-compat-version="edge" data-sap-ui-frame-options="trusted" data-sap-ui-async="true"></script>
13
+ </head>
14
+
15
+ <body class="sapUiBody">
16
+ <div data-sap-ui-component="" data-name="cds.plugin.caching.dashboard"></div>
17
+
18
+
19
+ </body></html>
@@ -0,0 +1,145 @@
1
+ {
2
+ "_version": "1.12.0",
3
+ "sap.app": {
4
+ "id": "cds.plugin.caching.dashboard",
5
+ "type": "application",
6
+ "i18n": "i18n/i18n.properties",
7
+ "title": "{{appTitle}}",
8
+ "description": "{{appDescription}}",
9
+ "applicationVersion": {
10
+ "version": "1.0.0"
11
+ },
12
+ "sourceTemplate": {
13
+ "id": "generator-ui5-ts-app",
14
+ "version": "1.1.0"
15
+ },
16
+ "dataSources": {
17
+ "caching": {
18
+ "uri": "/odata/v4/caching/",
19
+ "type": "OData",
20
+ "settings": {
21
+ "odataVersion": "4.0"
22
+ }
23
+ }
24
+ }
25
+ },
26
+ "sap.ui": {
27
+ "technology": "UI5",
28
+ "icons": {},
29
+ "deviceTypes": {
30
+ "desktop": true,
31
+ "tablet": true,
32
+ "phone": true
33
+ }
34
+ },
35
+ "sap.ui5": {
36
+ "rootView": {
37
+ "viewName": "cds.plugin.caching.dashboard.view.App",
38
+ "type": "XML",
39
+ "id": "app"
40
+ },
41
+ "dependencies": {
42
+ "minUI5Version": "1.136.1",
43
+ "libs": {
44
+ "sap.ui.core": {},
45
+ "sap.m": {},
46
+ "sap.ui.layout": {},
47
+ "sap.viz": {},
48
+ "sap.ui.table": {},
49
+ "sap.ui.unified": {},
50
+ "sap.f": {},
51
+ "sap.tnt": {}
52
+ }
53
+ },
54
+ "handleValidation": true,
55
+ "contentDensities": {
56
+ "compact": true,
57
+ "cozy": true
58
+ },
59
+ "models": {
60
+ "i18n": {
61
+ "type": "sap.ui.model.resource.ResourceModel",
62
+ "settings": {
63
+ "bundleName": "cds.plugin.caching.dashboard.i18n.i18n",
64
+ "supportedLocales": [
65
+ "en",
66
+ "de"
67
+ ],
68
+ "fallbackLocale": "en",
69
+ "async": true
70
+ }
71
+ },
72
+ "formatter": {
73
+ "type": "sap.ui.model.json.JSONModel",
74
+ "settings": {}
75
+ },
76
+ "": {
77
+ "type": "sap.ui.model.odata.v4.ODataModel",
78
+ "settings": {
79
+ "serviceUrl": "/odata/v4/caching-api/",
80
+ "operationMode": "Server",
81
+ "autoExpandSelect": true,
82
+ "groupId": "$auto"
83
+ }
84
+ }
85
+ },
86
+ "routing": {
87
+ "config": {
88
+ "routerClass": "sap.f.routing.Router",
89
+ "viewType": "XML",
90
+ "viewPath": "cds.plugin.caching.dashboard.view",
91
+ "controlId": "fcl",
92
+ "controlAggregation": "pages"
93
+ },
94
+ "routes": [
95
+ {
96
+ "pattern": "",
97
+ "name": "main",
98
+ "target": "main",
99
+ "subroutes": [
100
+ {
101
+ "pattern": "cache/{cache}",
102
+ "name": "cache",
103
+ "target": "cache",
104
+ "subroutes": [
105
+ {
106
+ "pattern": "cache/{cache}/statistic/{metricId}",
107
+ "name": "singleMetric",
108
+ "target": "singleMetric"
109
+ },
110
+ {
111
+ "pattern": "cache/{cache}/key-metric/{keyMetricId}",
112
+ "name": "singleKeyMetric",
113
+ "target": "singleKeyMetric"
114
+ }
115
+ ]
116
+ }
117
+ ]
118
+ }
119
+ ],
120
+ "targets": {
121
+ "main": {
122
+ "viewName": "Main",
123
+ "viewLevel": 1,
124
+ "controlAggregation": "beginColumnPages"
125
+ },
126
+ "cache": {
127
+ "viewName": "Cache",
128
+ "viewLevel": 2,
129
+ "controlAggregation": "midColumnPages"
130
+ },
131
+ "singleMetric": {
132
+ "viewName": "SingleMetric",
133
+ "viewLevel": 3,
134
+ "controlAggregation": "endColumnPages"
135
+ },
136
+ "singleKeyMetric": {
137
+ "viewName": "SingleKeyMetric",
138
+ "viewLevel": 3,
139
+ "controlAggregation": "endColumnPages"
140
+ }
141
+ }
142
+ },
143
+ "flexBundle": false
144
+ }
145
+ }